Domanda

Perché questo codice 7.30 - 7.20 in Ruby torna 0.0999999999999996, non 0.10?

Ma se scriverò 7.30 - 7.16, per esempio, tutto sarà ok, vado a prendere 0.14.

Quello che il problema, e come posso risolverlo?

Altri suggerimenti

Il problema è che alcuni numeri possiamo facilmente scrivere in decimale non hanno una rappresentazione esatta nel particolare formato in virgola mobile implementata da hardware corrente. Un modo casuale di affermare questo è che tutti i numeri interi fanno, ma non tutte le frazioni, in quanto normalmente memorizzare la frazione con un esponente di 2**e. Quindi, si hanno 3 scelte:

  1. Per concludere in modo appropriato. Il risultato non arrotondato è sempre molto molto vicino, quindi un risultato arrotondato è invariabilmente "perfetta". Questo è ciò che fa Javascript e un sacco di gente non si rendono nemmeno conto che JS fa tutto in virgola mobile.

  2. Utilizzare rappresentazione in virgola fissa. Rubino in realtà rende il tutto veramente facile; è una delle poche lingue che si sposta senza soluzione di continuità alla Classe bignum da Fixnum come numeri diventano più grandi.

  3. Utilizzare una classe che è stato progettato per risolvere questo problema, come BigDecimal

Per guardare il problema in modo più dettagliato, si può tentare di rappresentare il vostro "7.3" in formato binario. La parte 7 è facile, 111, ma come facciamo 0,3? 111.1 è 7.5, troppo grande, 111.01 è 7.25, sempre più vicino. Risulta, 111,010,011 mila è il "più piccolo numero successivo più vicino", 7,296,875 mila, e quando cerchiamo di riempire il mancante 0,003,125 mila alla fine scopriamo che è solo 111,010011001100110011 ... per sempre, non è rappresentabile nella nostra codifica scelto in una stringa di bit finita .

Il problema è che virgola mobile è imprecisa . È possibile risolverlo utilizzando numeri interi razionali, BigDecimal o semplicemente (per esempio se si desidera memorizzare i soldi è possibile memorizzare il numero di centesimi come un int al posto del numero di dollari come un galleggiante).

BigDecimal può accuratamente memorizzare qualsiasi numero che ha un numero finito di cifre in base 10 e tondi numeri che non lo fanno (così tre terzi non sono un intero).

razionale può con precisione memorizzare qualsiasi numero razionale e non in grado di memorizzare i numeri irrazionali a tutti.

Questo è un errore comune da come numeri in virgola float sono rappresentati nella memoria.

L'uso BigDecimal se avete bisogno di risultati esatti.

result=BigDecimal.new("7.3")-BigDecimal("7.2")
puts "%2.2f" % result

E 'interessante notare che un numero che ha pochi decimali in una base può in genere hanno un gran numero di decimali in un altro. Ad esempio, ci vuole un numero infinito di decimali da esprimere 1/3 (= 0,3333 ...) nella base 10, ma solo un decimale nella base 3. Analogamente, ci vogliono molti decimali per esprimere il numero 1/10 ( = 0,1) nella base 2.

Dal momento che si sta facendo matematiche in virgola mobile, allora il numero restituito è quello che il computer utilizza per la precisione.

Se si desidera una risposta più vicina, con una precisione insieme, solo più il galleggiante da che (come per 100), convertirlo in un int, fare la matematica, poi dividere.

Ci sono altre soluzioni, ma trovo che questo sia il più semplice dal momento che l'arrotondamento sembra sempre un po 'incerto per me.

Questo è stato chiesto prima qui, si potrebbe voler cercare alcune delle risposte dato prima, come questo: trattati i problemi di precisione di numeri in virgola mobile

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top