Rariteiten bij vermenigvuldigen
Ik kom een probleem tegen bij het verwerken van mutaties. Dit probleem heb ik teruggebracht tot onderstaand script, hetgeen de output levert zoals onder is weergegeven (behalve de kleur dan).
Regel 3*3,29 en 6*3,29 worden weergegeven met ONGELIJK, maar volgens mij zouden deze ook gelijk moeten zijn.
Een prijs wordt vermenigvuldigd met het aantal en gecontroleerd met het opgegeven bedrag.
Er zit een conversie in (komma naar punt).
Een andere prijs opvoeren in $a (bv 1,11) geeft weer andere regels als verschil; $a = "1,23" geeft alles goed.
Al dagen aan het zoeken!
Wat doe ik fout?
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
echo 'Current PHP version: ' . phpversion();
$a = "1,12";
$b = array();
for ($aantal=1;$aantal<10;$aantal++)
{
$prijs = trim(str_replace(",", ".", $a));
$bedrag = $aantal*trim(str_replace(",", ".", $a));
$b[$aantal] = $aantal*$prijs;
$kleur = "black";
$fout = "";
$controlebedrag = trim(str_replace(",", ".", $b[$aantal]));
if ($bedrag <> $controlebedrag):
$fout = "ONGELIJK!!!";
$kleur = "red";
endif;
echo "<font color = $kleur><br>".$aantal."*".$a."=".$bedrag." ".$b[$aantal]." ".$controlebedrag."</font> ".$fout;
}?>
echo 'Current PHP version: ' . phpversion();
$a = "1,12";
$b = array();
for ($aantal=1;$aantal<10;$aantal++)
{
$prijs = trim(str_replace(",", ".", $a));
$bedrag = $aantal*trim(str_replace(",", ".", $a));
$b[$aantal] = $aantal*$prijs;
$kleur = "black";
$fout = "";
$controlebedrag = trim(str_replace(",", ".", $b[$aantal]));
if ($bedrag <> $controlebedrag):
$fout = "ONGELIJK!!!";
$kleur = "red";
endif;
echo "<font color = $kleur><br>".$aantal."*".$a."=".$bedrag." ".$b[$aantal]." ".$controlebedrag."</font> ".$fout;
}?>
Geeft als output:
Current PHP version: 5.4.16
1*3,29=3.29 3.29 3.29
2*3,29=6.58 6.58 6.58
3*3,29=9.87 9.87 9.87 ONGELIJK!!!
4*3,29=13.16 13.16 13.16
5*3,29=16.45 16.45 16.45
6*3,29=19.74 19.74 19.74 ONGELIJK!!!
7*3,29=23.03 23.03 23.03
8*3,29=26.32 26.32 26.32
9*3,29=29.61 29.61 29.61
Gewijzigd op 25/06/2015 15:55:12 door Karel Bijvelds
Gewijzigd op 25/06/2015 15:53:13 door - SanThe -
Toevoeging op 25/06/2015 16:04:01:
Karel Bijvelds op 25/06/2015 15:45:26:
Hallo,
Ik kom een probleem tegen bij het verwerken van mutaties. Dit probleem heb ik teruggebracht tot onderstaand script, hetgeen de output levert zoals onder is weergegeven (behalve de kleur dan).
Regel 3*3,29 en 6*3,29 worden weergegeven met ONGELIJK, maar volgens mij zouden deze ook gelijk moeten zijn.
Een prijs wordt vermenigvuldigd met het aantal en gecontroleerd met het opgegeven bedrag.
Er zit een conversie in (komma naar punt).
Een andere prijs opvoeren in $a (bv 1,11) geeft weer andere regels als verschil; $a = "1,23" geeft alles goed.
Al dagen aan het zoeken!
Wat doe ik fout?
Geeft als output:
Current PHP version: 5.4.16
1*3,29=3.29 3.29 3.29
2*3,29=6.58 6.58 6.58
3*3,29=9.87 9.87 9.87 ONGELIJK!!!
4*3,29=13.16 13.16 13.16
5*3,29=16.45 16.45 16.45
6*3,29=19.74 19.74 19.74 ONGELIJK!!!
7*3,29=23.03 23.03 23.03
8*3,29=26.32 26.32 26.32
9*3,29=29.61 29.61 29.61
Ik kom een probleem tegen bij het verwerken van mutaties. Dit probleem heb ik teruggebracht tot onderstaand script, hetgeen de output levert zoals onder is weergegeven (behalve de kleur dan).
Regel 3*3,29 en 6*3,29 worden weergegeven met ONGELIJK, maar volgens mij zouden deze ook gelijk moeten zijn.
Een prijs wordt vermenigvuldigd met het aantal en gecontroleerd met het opgegeven bedrag.
Er zit een conversie in (komma naar punt).
Een andere prijs opvoeren in $a (bv 1,11) geeft weer andere regels als verschil; $a = "1,23" geeft alles goed.
Al dagen aan het zoeken!
Wat doe ik fout?
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
echo 'Current PHP version: ' . phpversion();
$a = "3,29";
$b = array();
for ($aantal=1;$aantal<10;$aantal++)
{
$prijs = trim(str_replace(",", ".", $a));
$bedrag = $aantal*trim(str_replace(",", ".", $a));
$b[$aantal] = $aantal*$prijs;
$kleur = "black";
$fout = "";
$controlebedrag = trim(str_replace(",", ".", $b[$aantal]));
if ($bedrag <> $controlebedrag):
$fout = "ONGELIJK!!!";
$kleur = "red";
endif;
echo "<font color = $kleur><br>".$aantal."*".$a."=".$bedrag." ".$b[$aantal]." ".$controlebedrag."</font> ".$fout;
}?>
echo 'Current PHP version: ' . phpversion();
$a = "3,29";
$b = array();
for ($aantal=1;$aantal<10;$aantal++)
{
$prijs = trim(str_replace(",", ".", $a));
$bedrag = $aantal*trim(str_replace(",", ".", $a));
$b[$aantal] = $aantal*$prijs;
$kleur = "black";
$fout = "";
$controlebedrag = trim(str_replace(",", ".", $b[$aantal]));
if ($bedrag <> $controlebedrag):
$fout = "ONGELIJK!!!";
$kleur = "red";
endif;
echo "<font color = $kleur><br>".$aantal."*".$a."=".$bedrag." ".$b[$aantal]." ".$controlebedrag."</font> ".$fout;
}?>
Geeft als output:
Current PHP version: 5.4.16
1*3,29=3.29 3.29 3.29
2*3,29=6.58 6.58 6.58
3*3,29=9.87 9.87 9.87 ONGELIJK!!!
4*3,29=13.16 13.16 13.16
5*3,29=16.45 16.45 16.45
6*3,29=19.74 19.74 19.74 ONGELIJK!!!
7*3,29=23.03 23.03 23.03
8*3,29=26.32 26.32 26.32
9*3,29=29.61 29.61 29.61
Code (php)
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
<?php
echo 'Current PHP version: ' . phpversion();
$a = "1,12";
$prijs = strval(str_replace(",", ".", $a));
for ($aantal=1;$aantal<10;$aantal++)
{
echo "<br>".$aantal."*".$a."=".($aantal*$prijs);
}
?>
echo 'Current PHP version: ' . phpversion();
$a = "1,12";
$prijs = strval(str_replace(",", ".", $a));
for ($aantal=1;$aantal<10;$aantal++)
{
echo "<br>".$aantal."*".$a."=".($aantal*$prijs);
}
?>
De verwijzing van Ward van der Put gevolgd en bekeken.
Als oplossing kies ik voor het standaardiseren van de uitkomsten en deze dan te vergelijken.
Zo loopt iig mijn script.
Indien iemand een elegantere oplossing heeft dan verneem ik dat graag.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
echo 'Current PHP version: ' . phpversion();
$a = "3,29";
$b = "9,87";
$aantal = 3;
$prijs = number_format(str_replace(",", ".", $a),2);
$bedrag = number_format($aantal*$prijs,2);
$controlebedrag = number_format(str_replace(",", ".", $b),2);
if ($bedrag <> $controlebedrag):
echo "<br>ONGELIJK: ". $controlebedrag." <> ".$bedrag."=".$aantal."*".$prijs;
else:
echo "<br>GELIJK: ". $controlebedrag." = ".$bedrag."=".$aantal."*".$prijs;
endif;
?>
echo 'Current PHP version: ' . phpversion();
$a = "3,29";
$b = "9,87";
$aantal = 3;
$prijs = number_format(str_replace(",", ".", $a),2);
$bedrag = number_format($aantal*$prijs,2);
$controlebedrag = number_format(str_replace(",", ".", $b),2);
if ($bedrag <> $controlebedrag):
echo "<br>ONGELIJK: ". $controlebedrag." <> ".$bedrag."=".$aantal."*".$prijs;
else:
echo "<br>GELIJK: ". $controlebedrag." = ".$bedrag."=".$aantal."*".$prijs;
endif;
?>
Current PHP version: 5.4.16
GELIJK: 9.87 = 9.87=3*3.29
Je ziet nu dat je op regel 6 $prijs vult met een string. Bijvoorbeeld "3,98"
Vervolgens probeer je met die string een berekening te doen: $aantal * $prijs.
Daar grijpt php weer in.
PHP probeert nu in hoeverre de string als getal gezien kan worden. Van "3,98" blijft dan "3" over.
$aantal is ook 3, dus 3*3 = 9.
Dat resultaat (9) haal je weer door number_format() om er 9,00 van te maken.
Hoe jouw script dan toch 9,87 weet op te leveren????
Toevoeging op 25/06/2015 18:32:15:
edit:
ik zie dat je de "gebruikelijke" actie bij number_format() om een punt door een komma te vervangen hier niet toepast.
je misbruikt hier number_format() dus eigenlijk als round();
if ($bedrag <> $controlebedrag)
een vergelijking van strings maakt, dan gaat het wel goed:
if (''.$bedrag != ''.$controlebedrag)
Je overtreedt anders een van de regels voor floating-point logica: vergelijkingen van gelijkheden of ongelijkheden zijn bij floats onnauwkeurig en daardoor onbetrouwbaar.
Verder kun je de nauwkeurigheid op twee manieren opvoeren:
• Gebruik de BC Math-functies.
• Gebruik absolute getallen, dus integers, want die zijn wél nauwkeurig. Aangezien je met bedragen rekent, kun je die bijvoorbeeld met 1000 vermenigvuldigen, daarna je berekeningen uitvoeren en tot slot de uitkomsten weer door 1000 delen bij de weergave. (Met de nadruk op weergave, zoals Ivo ook zegt.)
Ik heb de BC_Math-functies toegepast.
Zonder de bcmul-functie in regel 7 valt ie ook in de GELIJK-tak, maar voor uniformiteit (en misschien wel noodzaak) ook hier de BC_Math_functies gebruikt.
Wat weten we samen toch veel !!!!!!!
<php?
echo 'Current PHP version: ' . phpversion();
$a = "3,29";
$b = "9,87";
$aantal = 3;
$prijs = str_replace(",", ".", $a);
$bedrag = bcmul($aantal, $prijs, 2);
$controlebedrag = str_replace(",", ".", $b);
$vergelijking = bccomp($bedrag, $controlebedrag, 2);
if (bccomp($bedrag, $controlebedrag, 2) <> 0):
echo "<br>ONGELIJK: ". $controlebedrag." <> ".$bedrag."=".$aantal."*".$prijs;
else:
echo "<br>GELIJK: ". $controlebedrag." = ".$bedrag."=".$aantal."*".$prijs;
endif;
?>
Current PHP version: 5.4.16
GELIJK: 9.87 = 9.87=3*3.29
Toevoeging op 26/06/2015 10:53:42:
Karel Bijvelds op 26/06/2015 10:52:56:
Dank voor de oplossing,
Ik heb de BC_Math-functies toegepast.
Zonder de bcmul-functie in regel 7 valt ie ook in de GELIJK-tak, maar voor uniformiteit (en misschien wel noodzaak) ook hier de BC_Math_functies gebruikt.
Wat weten we samen toch veel !!!!!!!
Current PHP version: 5.4.16
GELIJK: 9.87 = 9.87=3*3.29
Ik heb de BC_Math-functies toegepast.
Zonder de bcmul-functie in regel 7 valt ie ook in de GELIJK-tak, maar voor uniformiteit (en misschien wel noodzaak) ook hier de BC_Math_functies gebruikt.
Wat weten we samen toch veel !!!!!!!
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php echo 'Current PHP version: ' . phpversion();
$a = "3,29";
$b = "9,87";
$aantal = 3;
$prijs = str_replace(",", ".", $a);
$bedrag = bcmul($aantal, $prijs, 2);
$controlebedrag = str_replace(",", ".", $b);
$vergelijking = bccomp($bedrag, $controlebedrag, 2);
if (bccomp($bedrag, $controlebedrag, 2) <> 0):
echo "<br>ONGELIJK: ". $controlebedrag." <> ".$bedrag."=".$aantal."*".$prijs;
else:
echo "<br>GELIJK: ". $controlebedrag." = ".$bedrag."=".$aantal."*".$prijs;
endif;
?>
$a = "3,29";
$b = "9,87";
$aantal = 3;
$prijs = str_replace(",", ".", $a);
$bedrag = bcmul($aantal, $prijs, 2);
$controlebedrag = str_replace(",", ".", $b);
$vergelijking = bccomp($bedrag, $controlebedrag, 2);
if (bccomp($bedrag, $controlebedrag, 2) <> 0):
echo "<br>ONGELIJK: ". $controlebedrag." <> ".$bedrag."=".$aantal."*".$prijs;
else:
echo "<br>GELIJK: ". $controlebedrag." = ".$bedrag."=".$aantal."*".$prijs;
endif;
?>
Current PHP version: 5.4.16
GELIJK: 9.87 = 9.87=3*3.29