Why doesn't the compiler understand I want the result to be a decimal number?
Il compilatore C ++ sta semplicemente seguendo regole ben definite e deterministiche come stabilito nello standard C ++ . Lo standard C ++ ha queste regole perché il comitato per gli standard ha deciso di farlo in questo modo.
Potrebbero aver scritto lo standard per dire che la matematica intera ha come risultato numeri in virgola mobile, o lo fa solo nel caso di un resto. Tuttavia, ciò aggiunge complessità: o ho bisogno di sapere in anticipo quale sia il risultato, o magari riconvertirlo in intero se dà sempre un float. Forse io voglio un intero.
Una delle filosofie fondamentali di C ++ è "non paghi per quello che non usi". Se in realtà vuoi la complessità del mixaggio di interi e float (e delle istruzioni aggiuntive della CPU e degli accessi alla memoria che questo comporta 1 ), fai il cast del tipo come hai menzionato nella tua domanda . Altrimenti, attenersi alla matematica standard intera.
Infine, la miscelazione di variabili integrali e in virgola mobile può comportare una perdita di precisione e risultati talvolta errati, come discuto di seguito. Se lo vuoi, allora pagalo: altrimenti, lo standard impone ai compilatori di attenersi a un rigido insieme di regole per mescolare i tipi di dati. Questo è un comportamento ben definito: come sviluppatore C ++, posso osservarlo nello standard e vedere come funziona.
Ci sono essenzialmente tre modi per fare ciò che stai cercando di fare, ognuno con vantaggi e svantaggi.
-
Matematica intera: questo risulta nel troncare i risultati durante la divisione come hai scoperto. Se si desidera la parte decimale, è necessario trattarla separatamente dividendo, ottenendo il resto e trattando la parte decimale come il resto diviso per il divisore. Questo è un po 'più complesso di un'operazione e ha più variabili da manipolare.
-
Calcolo matematico a virgola mobile: questo in genere produce risultati (sufficienti) corretti per valori piccoli, ma può facilmente introdurre errori con precisione e arrotondamenti, specialmente all'aumentare dell'esponente. Se dividi un numero elevato con un numero piccolo, potresti persino causare un underflow o semplicemente ottenere un risultato errato perché le scale dei numeri non giocano bene tra loro.
-
Fai i tuoi calcoli. Esistono corsi che gestiscono precisione estesa dei numeri decimali e razionali . Questi in genere sono più lenti della matematica sui tipi predefiniti, ma in genere sono ancora piuttosto veloci e forniscono matematica di precisione arbitraria. Arrotondare e altri problemi non sono automatici come lo sono con i float IEEE, ma ottieni più controllo e sicuramente più precisione.
La chiave qui è scegliere in base al dominio del problema. Tutti e tre i metodi di rappresentazione dei numeri hanno i loro vantaggi e svantaggi. Usando un contatore di loop? Scegli un tipo integrale. Rappresentare le posizioni nello spazio 3D? Probabilmente un gruppo di galleggianti. Vuoi tenere traccia dei soldi? Utilizza un tipo decimale fisso.
1 Le architetture CPU più popolari (ad es. x86-64 ) saranno separate insiemi di istruzioni che operano su diversi tipi di registro come intero e virgola mobile, oltre a istruzioni aggiuntive per la conversione tra integrale, virgola mobile e varie rappresentazioni di essi (firmati e non firmati, float e double). Alcune di queste operazioni possono comportare anche l'accesso alla memoria: convertire un valore e memorizzarlo in memoria (la sua variabile). La matematica a livello di CPU non è semplice come "integer in, float out". Mentre aggiungere due interi può essere una semplice operazione molto , probabilmente una singola istruzione, mescolando i tipi di dati può aumentare la complessità.