2015-10-23 17 views
9

Questo codice:strano funzionamento del ceil() funzione (PHP)

echo (40 * (10/100 + 1)); //44 
echo (50 * (10/100 + 1)); //55 
echo ceil(40 * ((10/100) + 1)); //44 
echo ceil(50 * ((10/100) + 1)); //56 (!) 

ritengo, che "56" in ragione del punto (55,0000,000001 millions => 56) flottante, ma non posso capito perché per "40" risultato è "44", non "45"

+0

Puoi trovare ulteriori informazioni al riguardo: http://php.net/manual/en/function.ceil.php –

+0

@MayurKoshti Non mi sembra come se non lo facesse t capire la funzione. In realtà è piuttosto strano che ciò stia accadendo mentre '50 * ((10/100) + 1)' corrisponde a 55 perfettamente. Non è un galleggiante. Quindi non dovrebbe arrotondare fino a 56 in primo luogo. – icecub

+0

@NikitaKolosov: puoi stampare separatamente il valore di ogni passaggio intermedio e vedere dove potrebbe essere andato storto? – klaar

risposta

5

Il 55 non è in realtà 55. è possibile verificare che facilmente:

<?php 
$x = (40 * (10/100 + 1)); // 44 
$y = (50 * (10/100 + 1)); // 55 
echo '$x == 44: ' . ($x == 44 ? 'True' : 'False') . "\n"; 
echo '$y == 55: ' . ($y == 55 ? 'True' : 'False') . "\n"; 
echo '$y > 55: ' . ($y > 55 ? 'True' : 'False') . "\n"; 
echo $y - 55; 

Resa:

$x == 44: True 
$y == 55: False 
$y > 55: True 
7.105427357601E-15 

Come si può vedere la differenza è minuscola (7.1 * 10^-15) ma che comunque lo rende più grande di 55, quindi ceil lo arrotonda.

La ragione basta vedere 55 è perché eco verrà convertito il galleggiante into a string:

conversione String avviene automaticamente nel campo di applicazione di un'espressione in cui è necessaria una stringa. Questo accade quando si usano le funzioni di eco o di stampa o quando una variabile viene confrontata con una stringa.

Per questa conversione il comportamento di troncamento standard interromperà le cifre ad un certo punto. Questo è configurata dal precision configuration parameter e il valore predefinito è 14. È possibile evitare questo comportamento utilizzando sprintf con una precisione personalizzato:

echo sprintf('%.50f', $y); 
// 55.00000000000000710542735760100185871124267578125000 
+0

Quindi perché 'abs ($ y)' restituisce 55? – icecub

+1

@icecub 'abs()' non cambia il numero ma solo il segno. quindi 'abs ($ y)' per un positivo '$ y' ti dà lo stesso numero. Viene semplicemente mostrato come '55', perché la stampa del numero tronca le cifre ad un certo punto. – poke

+0

Capisco. Ancora lo trovo un po 'strano visto che ho sempre pensato che 'abs()' restituisca il numero assoluto indipendentemente dalla quantità di cifre in virgola mobile. Anche guardando da una prospettiva matematica, dovrebbe essere semplicemente 55: P Comunque, grazie per aver spiegato! – icecub

1

Dobbiamo notare precisione in virgola mobile http://php.net/manual/en/language.types.float.php

numeri razionali che sono esattamente rappresentabili come numeri in virgola mobile nella base 10, come 0.1 o 0.7, non hanno una rappresentazione esatta di come numeri in virgola mobile nella base 2, che viene utilizzata internamente, indipendentemente dalle dimensioni della mantissa. Quindi, non possono essere convertiti nelle loro controparti binarie interne senza una piccola perdita di precisione. Questo può portare a risultati confusi: ad esempio, piano ((0,1 + 0,7) * 10) sarà solitamente tornare 7 invece dei previsti 8, dal momento che la rappresentazione interna sarà qualcosa di simile 7,9999999999999991118 ....

E questa è la risposta alla domanda Perché i miei numeri non si sommano?http://floating-point-gui.de/. Spiega sinteticamente perché ottieni quel risultato inaspettato