ad esempio, con il dollaro, non hai mai una precisione inferiore a $ 0,01
Oh veramente?
la secolare questione del perché non dovresti conservare la valuta come un numero in virgola mobile IEEE 754.
Non esitate a memorizzare pollici in numeri in virgola mobile IEEE 754 . Conservano esattamente come ti aspetteresti.
Non esitate a memorizzare qualsiasi somma di denaro in numeri a virgola mobile IEEE 754 che è possibile memorizzare utilizzando i segni di spunta che dividono un righello in frazioni di pollice.
Perché? Perché quando usi IEEE 754 è così che lo stai memorizzando.
Il fatto è che i pollici sono divisi a metà. La cosa sulla maggior parte dei tipi di valuta è che sono divisi in decimi (alcuni tipi non lo sono ma restiamo concentrati).
Questa differenza non sarebbe poi così confusa se non che, per la maggior parte dei linguaggi di programmazione, l'input e l'output dai numeri in virgola mobile IEEE 754 sono espressi in decimali! Il che è molto strano perché non sono memorizzati in decimali.
Per questo motivo non si arriva mai a vedere come i bit fanno cose strane quando si chiede al computer di memorizzare 0.1
. Vedi la stranezza solo quando fai matematica contro di essa e ha strani errori.
Da java efficace di Josh Bloch :
System.out.println(1.03 - .42);
produce 0.6100000000000001
Quello che dice di più di questo non è il 1
modo di sedersi laggiù a destra. Sono i numeri strani che dovevano essere usati per ottenerlo. Invece di usare l'esempio più popolare 0.1
, dobbiamo usare un esempio che mostri il problema ed eviti l'arrotondamento che lo nasconderebbe.
Ad esempio, perché funziona?
System.out.println(.01 - .02);
produce -0.01
Perché siamo stati fortunati.
Odio i problemi che sono difficili da diagnosticare perché a volte divento "fortunato".
IEEE 754 semplicemente non può memorizzare 0,1 con precisione. Ma se gli chiedi di memorizzare 0.1 e poi gli chiedi di stampare, mostrerà 0.1 e penserai che tutto vada bene. Non va bene, ma non puoi vederlo perché sta arrotondando per tornare a 0.1.
Alcune persone confondono il diavolo con gli altri chiamando queste discrepanze arrotondando gli errori. No, questi non sono errori di arrotondamento. L'arrotondamento sta facendo ciò che dovrebbe e trasformando ciò che non è un decimale in un decimale in modo che possa essere stampato sullo schermo.
Ma ciò nasconde la discrepanza tra la modalità di visualizzazione del numero e la modalità di memorizzazione. L'errore non si è verificato quando si è verificato l'arrotondamento. È successo quando hai deciso di inserire un numero in un sistema che non è in grado di memorizzarlo con precisione e hai pensato che fosse memorizzato esattamente quando non lo era.
Nessuno si aspetta che π memorizzi esattamente in una calcolatrice e riescono a lavorarci bene. Quindi il problema non riguarda nemmeno la precisione. Si tratta della precisione attesa. I computer visualizzano un decimo come 0.1
i nostri calcolatori, quindi ci aspettiamo che memorizzino un decimo perfettamente come fanno i nostri calcolatori. Non lo fanno. Il che è sorprendente, poiché i computer sono più costosi.
Lascia che ti mostri la mancata corrispondenza:
Si noti che 1/2 e 0,5 si allineano perfettamente. Ma 0.1 non si allinea. Sicuramente puoi avvicinarti se continui a dividere per 2 ma non lo colpirai mai esattamente. E abbiamo bisogno di sempre più bit ogni volta che ci dividiamo per 2. Quindi rappresentare 0,1 con qualsiasi sistema che divide per 2 richiede un numero infinito di bit. Il mio disco rigido non è poi così grande.
Quindi IEEE 754 smette di provare quando si esauriscono i bit. Il che è bello perché ho bisogno di spazio sul mio disco rigido per ... foto di famiglia. No davvero. Foto di famiglia : P
Ad ogni modo, ciò che digiti e ciò che vedi sono i decimali (a destra) ma ciò che memorizzi è bicimali (a sinistra). A volte quelli sono perfettamente uguali. A volte no. A volte sembra che siano gli stessi quando semplicemente non lo sono. Questo è l'arrotondamento.
In particolare, cosa dobbiamo sapere per poter archiviare valori in alcune valute e stamparle?
Per favore, se stai gestendo il mio denaro basato su decimali, non usare float o doppi.
Se sei sicuro che cose come i decimi di penny non saranno coinvolte, allora conserva solo i penny. Se non lo sei, scopri quale sarà la più piccola unità di questa valuta e usala. Se non puoi, usa qualcosa come BigDecimal .
Il mio patrimonio netto si adatterà probabilmente sempre a un intero a 64 bit, ma cose come BigInteger funzionano bene per progetti più grandi di così. Sono solo più lenti dei tipi nativi.
Capire come conservarlo è solo metà del problema. Ricorda che devi anche essere in grado di visualizzarlo. Un buon design separerà queste due cose. Il vero problema con l'utilizzo di float qui è che queste due cose sono messe insieme.