Rariteiten bij vermenigvuldigen

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Karel Bijvelds

Karel Bijvelds

25/06/2015 15:45:26
Quote Anchor link
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?


Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
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;
     }
?>

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
 
PHP hulp

PHP hulp

25/04/2024 12:51:56
 
- SanThe -

- SanThe -

25/06/2015 15:52:25
Quote Anchor link
Waarom $a = "3,29"; en niet gewoon direct het juiste getal $a = 3.29; ?
Gewijzigd op 25/06/2015 15:53:13 door - SanThe -
 
Karel Bijvelds

Karel Bijvelds

25/06/2015 15:58:26
Quote Anchor link
De waarde van $a wordt extern aangeleverd!

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?


Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
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;
     }
?>

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
 
- SanThe -

- SanThe -

25/06/2015 16:07:20
Quote Anchor link
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
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);
     }

?>
 
Ward van der Put
Moderator

Ward van der Put

25/06/2015 16:14:22
Quote Anchor link
Dat 9.87 hier niet gelijk is aan 9.87, ligt aan de onnauwkeurigheid van floating-point operaties:

http://stackoverflow.com/questions/3148937/compare-floats-in-php
 
Karel Bijvelds

Karel Bijvelds

25/06/2015 18:22:07
Quote Anchor link
Dank voor de reactie!

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)
PHP script in nieuw venster Selecteer het PHP script
1
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;

?>


Current PHP version: 5.4.16
GELIJK: 9.87 = 9.87=3*3.29
 
Ivo P

Ivo P

25/06/2015 18:28:21
Quote Anchor link
number_format moet je alleen gebruiken in combinatie met "echo".

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();
 
Ward van der Put
Moderator

Ward van der Put

25/06/2015 18:44:53
Quote Anchor link
Als je van de vergelijking van floats

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.)
 
Karel Bijvelds

Karel Bijvelds

26/06/2015 10:52:56
Quote Anchor link
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 !!!!!!!

<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 !!!!!!!

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
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;

?>


Current PHP version: 5.4.16
GELIJK: 9.87 = 9.87=3*3.29
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.