2010-03-23 12 views
11

Ragazzo, questo è davvero strano. Mi aspetto che il seguente codice stampi il 1990, ma stampa 1989!Perché `intval (19.9 * 100)` è uguale a `1989`?

$val = '$19.9'; 

$val = preg_replace('/[^\d.]/','',$val); 
$val = intval($val * 100); 

echo $val; 

Perché mai succede questo?

Edit: e questo codice:

$val = '$19.9'; 
$val = preg_replace('/[^\d.]/','',$val); 
echo $val . "<br>"; 
$val = $val * 100; 
echo $val . "<br>"; 
$val = intval($val); 
echo $val; 

Stampe:

19.9 
1990 
1989 

Perché intval(1990) pari 1989 ???

+0

'intval ('1990')' mi dà 1990. Proverò a controllare il tuo caso. Nel frattempo, prova a dare un titolo più pertinente alla tua domanda. – zneak

+0

No, no. 'intval ('1990')' dà 1990, quello che sto dicendo è che l'esempio suggerisce indirettamente che 'intval (1990)' è uguale a '1989' –

+1

Questo problema è stato discusso in circa ogni altra lingua conosciuta dall'uomo in questo sito ... – animuson

risposta

17

Questo è un problema di precisione inerente ai numeri in virgola mobile in PHP e in molti altri linguaggi. Questo bug report discute un po ', nel contesto della fusione come un int:

http://bugs.php.net/bug.php?id=33731

Prova round($val * 100) invece.

+0

Sì, ce l'hai. – zneak

+0

Ok, 'round' fornisce la risposta attesa. Quali implicazioni ha l'uso di 'round' invece di' intval'? –

+0

a quanto ho capito, la conversione del valore in un int utilizzando 'intval()' riduce il valore float dopo il decimale invece di arrotondarlo. – Funkatron

0

$val è un numero in virgola mobile - il risultato di "19.9" * 100. I numeri in virgola mobile non sono accurati al 100% in nessuna lingua (questo è in base alla progettazione). Se è necessaria una precisione decimale del 100% per i valori in dollari, è necessario utilizzare numeri interi ed eseguire tutti i calcoli utilizzando centesimi (ad esempio, "$19.90" deve essere 1990).

+0

Allora ... cosa stai dicendo? –

+0

L'utilizzo di interi non è affatto una buona soluzione. Devono occuparsi di importi superiori a 20 milioni? Ops. Valute diverse, non tutte hanno 100 sottounità? Non si puo 'fare. –

+0

@ Michael - PHP non ha interi a 64 bit? Penso che valute diverse siano un non-problema, dal momento che non puoi comunque confrontarle tra loro direttamente. –

4

La solita risposta a questo tipo di domande è leggere What Every Computer Scientist Should Know About Floating-Point Arithmetic.

+1

... che purtroppo non aiuta affatto le persone che fanno questo tipo di domande di base. –

+1

e nemmeno un aiuto per quelli di noi che producono molto codice, ma non sono matematici. – wadesworld

+0

Ho visto in un'altra risposta che qualcuno aveva scritto una versione semplificata di questo documento, ma non ricordo quale domanda o chi fosse. – Powerlord

2

Perché intval (1990) equivale a 1989 ???

Perché sei non prendere intval(1990). Stai prendendo intval($val * 100) dove $val è un numero vicino, ma leggermente più piccolo di, 19.9.

Leggi The Floating-Point Guide per capire perché è così.

Per quanto riguarda come risolvere il problema: non utilizzare mai valori a virgola mobile per denaro. In PHP, dovresti usare invece BCMath.