| 

.NET C# Java Javascript Exception

1
Liebe Freunde von Codekicker.de,

ich bin mit meinem Latein am ende.

Ich hab nun schon alle möglichen Konvertierungen versucht, PHP berechnet mir aus dem Wert 8.775, bei einem round 8,7799999999 ...

Hat jemand ähnliche Phänomene und kennt abhilfe?

Vielen Dank!
News:
18.11.2009
Martin Bassus 486 1 8
Könntest du bitte die exakte betroffene Zeile nennen? In deiner Frage sind mindestens zwei unterschiedliche Versionen zu finden. :)
Blauesocke 18.11.2009
1
Macht es einen Unterschied, ob du mit '8,775' oder 8.775 arbeitest? D.h. ist das Problem beim round oder der Konvertierung von String nach Float?
BeachBlocker 18.11.2009
1
Also bei mir kommt in PHP bei echo round(8.775,2); immernoch 8,78 raus. Bitte poste mal deine komplette Zeile bzw. deine Variablenwerte dazu. Grüßle
Scout 19.11.2009
4 Antworten
2
Ich gehe davon aus, das die Schreibweise '8,775' falsch ist und statt dessen '8.775' gemeint ist. Ein impliziter Cast durch PHP von '8,775' hätte in jedem Fall einen Integer - in diesem Fall 8 zur Folge.
Ein kleiner Test mit
$var1 = '8.775';
$var2 = 8.775;

$res1 = round($var1, 2);
$res2 = round($var2, 2);
$res3 = round(8.775, 2);
$res4 = round('8.775', 2);

echo 'res1('.gettype($res1).'): '.$res1;
echo '<br />';
echo 'res2('.gettype($res2).'): '.$res2;
echo '<br />';
echo 'res3('.gettype($res3).'): '.$res3;
echo '<br />';
echo 'res4('.gettype($res4).'): '.$res4;

liefert als Ergebnis:
res1(double): 8.78
res2(double): 8.78
res3(double): 8.78
res4(double): 8.78

Das Problem ist also erstmal nicht nachvollziehbar. Mögliche Ursachen könnten sein:

  • PHP Manual: "Der Wertebereich für Fließkommawertes ist platformabhängig, ..."
  • Der "Rundungsfehler" tritt an einer anderen Stelle als der Vermuteten auf
  • Die Berechnung von Round ist in verschiedenen PHP-Versionen unterschiedlich

Du solltest also zuallererst ausschliesen, dass der Fehler nicht aus einer vorhergehenden / nachfolgenden Berechnung stammt und dein Script ggfs. mal auf einer anderen Plattform testen.
19.11.2009
FalkP 3,3k 3 8
Ich habe das mal C++ statt mit PHP getested:
Die interne Darstellung von 8.78 ist 8.7799999999999994.

Mit printf("%lg") wird allerdings "8.78" ausgegeben. Das liegt aber allein an der Ausgaberountine, denn dort wird noch einmal 'gerundet', denn mit printf("%25.20lg") wird das 'richtige' "8.7799999999999994" ausgegeben. Es also nicht an der round Funktion, sondern, dass für 8.78 intern keine exakte Darstellung verwendet wird.
FalkP: Probier das doch noch mal bitte mit PHP und einem Ausgabeformat wie %25.20lg".
BeachBlocker 24.11.2009
@BeachBlocker: eine Ausgabe mit printf("%.20f", $res1); liefert auf meinem PHP sowohl unter WinXP als auch unter Linux 8.77999999999999936051. Es ist also dann wohl tatsächlich so, dass sich 8.78 nicht als Flieskommazahl mit endlicher (im Sinne eines PC oder Small-Server) Genauigkeit darstellen läßt.
Was lehrt uns das: Traue nie einer Augaberoutine und impliziten Umwandlungen ;)
FalkP 30.11.2009
3
Ja, aber das ist keine Phänoman, sondern verursacht durch die Besonderheiten der internen Repräsentation von Zahlen auf dem Computer, bzw. der Datentypen, die eine Programmiersprache anbietet. Siehe auch http://www.php.net/manual/en/language.types.float.php

(Fließkomma-)Dezimalzahlen sind nun mal nicht exakt. In deinem Fall gibt es keine exakte Darstellung der Zahl 8.78. Da hilft nichts. Wenn es in einer Programmiersprache keine Fixkommazahlen gibt außer Ganzzahlen muß man mit Ganzzahlen arbeiten und dann die Nachkommastellen simulieren, z.B. für Währungen mit Cent statt Euro arbeiten.

Abhilfe kommt auf den Anwendungsfall an: z.B. round( 8.775*100, 0 ) sollte 878 ergeben und dann wieder das Komma verschieben.

Es gibt auch für viele Programmiersprachen Biblitheken zur exakten Mathematik.
18.11.2009
BeachBlocker 617 3
1
Okay,....

Also ich hab das jetzt quick´n dirty gelöst.

FalkP hat schon recht, das ganze ist tatsächlich Plattformabhängig.
Wir haben hier verschiedenste Skripte auf identischen Servern damit belegt, bei den meisten geht es, bei anderen geht es wiederrum nicht.

Wo das Problem jetzt genau lag, Who Knows, ich habe jetzt alle möglichen Konvertierungen usw versucht, aber nichts hat mehr geholfen. Da es sich hier um Euro-Beträge handelt und mir die 4. Kommastelle so wirtschaftlich ziemlich egal ist (also ob ich da jetzt drauflege oder nicht) hab ich das so gelöst:

<?php
function modify_betrag($betrag)
{
$betrag=str_replace(",",".",$betrag);
$betrag=explode(".",$betrag);
$hauptzahl=$betrag[0];
$stelle_drei=substr($betrag[1],2,1);
$erstenzwei=substr($betrag[1],0,2);
if($erstenzwei =="")
{
$converted=$hauptzahl;
}
else
{
if($stelle_drei =="" or $stelle_drei ==0)
{
$converted=$betrag[0].".".$erstenzwei;
}
else
{
if($stelle_drei >=5)
{
$erstenzwei=$erstenzwei+1;
}
$ranhaengen=$erstenzwei;
if($ranhaengen =="")
{
$converted=$hauptzahl.".00";
}
elseif($ranhaengen>=100)
{
$ranhaengen="00";
$hauptzahl++;
$converted=$hauptzahl.".".$ranhaengen;
}
else
{
$converted=$hauptzahl.".".$ranhaengen;
}
}
}

return $converted;

}
?>



Zwar echt nicht schön, PHP die Zahl dann einfach selbst vom String wandeln zu lassen, aber so funktioniert es in jedem nur denkbaren Fall garantiert richtig... (ohne Besonderheiten wie Tausenderpunkte etc.. also die Zahl muss vorher schon bereinigt werden).

Grüßli
20.11.2009
Martin Bassus 486 1 8
1
Bitte nächstes Mal die Kommentarfunktion benutzen oder die Frage bearbeiten. Dies ist kein Forum! Die Reihenfolge der Antworten bleibt aufgrund von up- und downvotes nicht immer gleich.
balu 24.11.2009
Ich weiß,.. aber wenn ich die Kommentarfunktion nutze, wäre es in der Frage drin. Hier handelt es sich aber um eine Lösung, die up oder downgevotet werden kann ;-)
Martin Bassus 30.11.2009
-2
Es sollte aber folgendes gehen (laut php.net/round):
echo round(8.775,2);
// 8.78


Edit (nachdem ich heut wohl etwas konfus bin):
Probier mal round(floatval('8.775'),2) und vergeleiche gegen round(8.775,2) und round('8.775',2).
18.11.2009
DaSpors 4,2k 2 8
DaSpors 4,2k 2 8
Hab wohl die Überschrift übersehen :)
Aber: round('8.775',2) MUSS ja komische Werte liefern, weil '8.775' implizit auf was auch immer gecastet wird.
DaSpors 18.11.2009

Stelle deine Php-Frage jetzt!