2013-08-09 1 views
6

Im folgenden Code, warum der Multiplikationsansatz keine Rundungsfehler erzeugt, während der kumulative Additionsansatz ist?Warum bekomme ich ein anderes Ergebnis von zwei vermeintlich analogen Rechenoperationen?

function get_value() { return 26.82; } 

function a($quantity) { 
    $value_excluding_vat = get_value(); 
    $value_including_vat = round($value_excluding_vat * (1 + (20/100)),2); 
    $total_nett = 0; 
    $total_gross = 0; 
    for($i=0; $i<$quantity; $i++) { 
     $total_nett += $value_excluding_vat; 
     $total_gross += $value_including_vat; 
    } 
    return array(
     $total_nett, 
     $total_gross 
    ); 
} 

function b($quantity) { 
    $value_excluding_vat = get_value(); 
    $value_including_vat = round($value_excluding_vat * (1 + (20/100)),2); 
    return array(
     $quantity * $value_excluding_vat, 
     $quantity * $value_including_vat 
    ); 
} 

$totals = a(1000); 
print_r($totals); 
echo $totals[1] - $totals[0]; 
echo "\n\n"; 
$totals = b(1000); 
print_r($totals); 
echo $totals[1] - $totals[0]; 

Hier ist meine Ausgabe:

Array 
(
    [0] => 26820 
    [1] => 32180 
) 
5360.0000000005 

Array 
(
    [0] => 26820 
    [1] => 32180 
) 
5360 
+0

Mögliche Duplikat http: // Stackoverflow. com/questions/11366522/php-Gleitkomma-Fehler-mit-Grund-Mathematik – BLaZuRE

+9

Ich las Ihre Frage als: _ "Ich hatte Code A (nicht gezeigt), die Ergebnis X zurückgegeben, wenn Sie Gleitkommazahlen multiplizieren und runden. Ich habe das in Code B geändert (nicht gezeigt), was Ergebnis Y ergibt. Warum passiert das? "_. Die Antwort ist: es hängt von Ihrem Code ab und hat wahrscheinlich mit Rundungsfehlern zu tun. Bitte zeigen Sie Ihren tatsächlichen, relevanten Code und Was Sie versucht haben – CodeCaster

+0

Betrachten Sie die Verwendung des Arguments $ mode zu [round()] (http://php.net/manual/en/function.round.php): Der Standard ist PHP_ROUND_HALF_UP –

Antwort

6

Zunächst nützlich sein, zu prüfen, dass es viele Zahlen sind die 10 in der Basis rational , aber nicht in einer binären Gleitkommadarstellung. Zum Beispiel ist der Fließkommawert von 26,82 tatsächlich 26.8200000000000002842170943040400743484497

Natürlich, wenn Sie das hinzufügen, einige Fehler schleichen sich ein, aber bis zu 15 signifikanten Ziffern sollten Sie in Ordnung sein - fügen Sie diese 1000-mal und die Summe ist tatsächlich 26819.9999999997671693563461303710937500000000

Die interessante Frage ist jedoch, wenn wir multiple 26.82 von 1000.0 bekommen wir 26820.0000000000000000000000000000000000000000 - wie geht das?

Die Antwort gibt es einfach ist, dass 26.820,0 tut haben eine genaue binäre Darstellung, und die Multiplikationsoperation ist intelligent genug, um das zu erkennen - auch von 1001,0 multipliziert und 26.82 Subtrahieren würden Sie noch eine genaue Antwort bekommen.

Hier einige interessante Links

3

Problem in machine representation of float values sein kann

zum Beispiel (Warnung Block sehen) 21470.73 kann 21470.729999..9994561 oder 21470.73000 ... 00sein, hängt davon ab, wie sie berechnet worden sind.

Versuchen temporäre Werte wie gross_total_so_far und nett_total_so_far abzurunden, bevor Sie $total

1

ich nicht denke, das Problem der Repräsentation und Subtraktion Gleitkommazahl Aber berechnen kann

Wenn Sie diese Werte ohne Runde subtrahieren von Sie erhalten Ergebnis ** 3578.455

Und wenn Sie es auf zwei Dezimalstellen runden es mit 3578.46.

So php hat eine Lösung mit diesem Problem.

PHP_ROUND_HALF_UP Round val up to precision decimal places away from zero, when it is half way there. Making 1.5 into 2 and -1.5 into -2. 

PHP_ROUND_HALF_DOWN  Round val down to precision decimal places towards zero, when it is half way there. Making 1.5 into 1 and -1.5 into -1. 

PHP_ROUND_HALF_EVEN  Round val to precision decimal places towards the next even value. 

PHP_ROUND_HALF_ODD Round val to precision decimal places towards the next odd value. 

Diese Konstante mit runder Funktion als

echo round(100.675, 2, PHP_ROUND_HALF_UP); // 100.68 
echo round(100.675, 2, PHP_ROUND_HALF_DOWN); // 100.67 

So PHP_ROUND_HALF_DOWN geliefert wird Wird in Ihrem Fall

Verwandte Themen