Domanda

Si è verificato un altro problema di calcolo matematico.

$a = 34.56

$b = 34.55

$ a effettua alcuni calcoli per ottenere questa cifra

$ b sta arrotondando il valore 0,05 più vicino per ottenere questa cifra

ciò che accade è

$c = $b - $a

presumibilmente dovrei essere -0,01, ma echo il $ c è show -0.00988888888888

Provo a usare n umber_format ($ c, 2) , ma l'output è 0,00,

come posso assicurarmi che $ a e $ b siano esattamente 2 decimali, nessun numero nascosto sul retro.

nella mia conoscenza php number_format è solo in grado di formattare il display, ma il valore non è in realtà 2 decimali,

Spero di poter ottenere aiuto da qui. Questo mi ha davvero frustrato.

È stato utile?

Soluzione

Prova sprintf (" ;%. 2f " ;, $ c);

I numeri in virgola mobile sono rappresentati nella notazione IEEE in base alle potenze di 2, quindi i numeri decimali finali potrebbero non essere un numero binario finale, ecco perché ottieni le cifre finali.

Come suggerito dal codificatore a lunghezza variabile, se conosci la precisione che desideri e non cambia (ad es. quando hai a che fare con denaro), potrebbe essere meglio usare solo numeri a virgola fissa, ovvero esprimere i numeri come centesimi piuttosto di dollari

$a = 3456;

$b = 3455;

$c = $b - $a;

sprintf ("%.2f", $c/100.0);

In questo modo, non si verificheranno errori di arrotondamento se si eseguono molti calcoli prima della stampa.

Altri suggerimenti

Usa round () :

$c = round($b - $a, 2);

Nota: puoi anche scegliere la modalità di arrotondamento nel modo appropriato.

Modifica: Ok non capisco cosa sta facendo sprintf () che number_format () non è:

$c = number_format($b - $a, 2);

vs

$c = sprintf("%.2f", $b - $a);

Calcolo nativo:

$a = 34.56;
$b = 34.55;
$c = $b - $a; // -0.010000000000005    

Funziona come previsto (! usa sempre le funzioni BC per i calcoli con numeri reali, il problema è per tutte le piattaforme basate su C):

$a = '34.56';
$b = '34.55';
$c = bcsub($b, $a, 4); // -0.0100    

Di recente ho riscontrato questo problema anche quando facevo calcoli con float. Ad esempio, avevo 2 float che quando sottratto e formattato, il valore era -0,00.

$floatOne = 267.58;
$floatTwo = 267.58;
$result = number_format($floatOne - floatTwo, 2);
print $result; //printed a string -0.00

Quello che ho fatto è stato:

$result = abs($floatOne - $floatTwo);// Made the number positive
print money_format('%i', $result); // printed the desired precision 0.00

Nella mia soluzione so che floatOne non sarà mai inferiore a floatDue. La funzione money_format è definita solo se il sistema ha funzionalità strfmon, Windows no.

Ti sei imbattuto in una delle trappole di numeri in virgola mobile; che non possono sempre rappresentare esatte frazioni decimali. Se vuoi valori decimali esatti, stai meglio usando numeri interi e poi dividendo per la precisione che vuoi alla fine.

Ad esempio, se stai effettuando calcoli in float che rappresentano Dollari (o la tua valuta preferita), potresti voler effettivamente fare i tuoi calcoli in centesimi interi.

Puoi evitare molto accuratamente tutti questi problemi semplicemente usando la libreria bcmath.

Ricorda solo di leggere la documentazione e fai attenzione se stai passando argomenti come stringhe o come tipi di dati numerici.

Se qualcuno arriva ancora a questa pagina con problemi simili in cui la sottrazione di numeri mobili causa errori o valori strani. Voglio spiegare questo problema con qualche dettaglio in più. Il colpevole sono i numeri in virgola mobile. E diversi sistemi operativi e diverse versioni dei linguaggi di programmazione possono comportarsi diversamente.

Per illustrare il problema, spiegherò perché con un semplice esempio di seguito.

Non è direttamente correlato a PHP e non è un bug. Tuttavia, ogni programmatore dovrebbe essere a conoscenza di questo problema.

Questo problema ha richiesto molte vite due decenni fa.

Il 25 febbraio 1991 questo problema nel calcolo del numero fluttuante in una batteria missilistica MIM-104 Patriot gli impedì di intercettare un missile Scud in arrivo a Dhahran, in Arabia Saudita, contribuendo alla morte di 28 soldati del 14 ° distaccamento del quartier generale dell'esercito degli Stati Uniti.

Ma perché succede?

Il motivo è che i valori in virgola mobile rappresentano una precisione limitata. Quindi, un valore potrebbe non avere la stessa rappresentazione di stringa dopo qualsiasi elaborazione. Anche include la scrittura di un valore in virgola mobile nello script e direttamente stampandolo senza operazioni matematiche.

Solo un semplice esempio:

$a = '36';
$b = '-35.99';
echo ($a + $b);

Ti aspetteresti che stampi 0,01, giusto? Ma stamperà una risposta molto strana come 0,009999999999998

Come altri numeri, anche i numeri in virgola mobile double o float sono memorizzati come una stringa di 0 e 1. Il modo in cui il virgola mobile differisce dall'intero sta nel modo in cui interpretiamo gli 0 e gli 1 quando vogliamo guardarli. Ci sono molti standard su come sono memorizzati.

I numeri a virgola mobile sono generalmente inseriti in un dato di computer come bit di segno, campo esponente e significato o mantissa, da sinistra a destra ....

I numeri decimali non sono ben rappresentati in binario a causa della mancanza di spazio sufficiente. Quindi, non puoi esprimere 1/3 esattamente come è 0,3333333 ..., giusto? Perché non possiamo rappresentare 0,01 come un numero float binario è per lo stesso motivo. 1/100 è 0.00000010100011110101110000 ..... con un 10100011110101110000 ripetuto.

Se 0,01 viene mantenuto in forma semplificata e troncata dal sistema di 01000111101011100001010 in binario, quando viene tradotto di nuovo in decimale, verrebbe letto come 0,0099999 .... a seconda del sistema (i computer a 64 bit ti daranno una precisione molto migliore rispetto a 32-bit). In questo caso il sistema operativo decide se stamparlo come vede o come renderlo in un modo più leggibile dall'uomo. Quindi, dipende dalla macchina come vogliono rappresentarlo. Ma può essere protetto a livello di lingua con metodi diversi.

Se si formatta il risultato, echo number_format (0.009999999999998, 2); stamperà 0,01.

È perché in questo caso istruisci come dovrebbe essere letto e quanto precisione richiedi.

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