dziwnie działający kod PHP

0

Jestem nowy i witam wszystkich.

Wiem ,że tworzycie poważniejsze kody ale dla odmiany może ktoś mi pomoże.
Zrobiłem program, który dla podanej kwoty (na razie działa dla kwoty powyżej 50zl) oblicza maksymalnie możliwą ilość banknotów 10zł oraz monet 5,2 i 1zł. potrzebnych do jej rozmienienia .
Działa poprawnie z jednym wyjątkiem. Dla kwoty 164 źle oblicza ilość 2-złotówek. I tylko dla tej !!??

<?php

$kwota=164;
 
$b10 = $kwota / 10; // ilośc banknotów 10zl
$r = $kwota%$b10;
$b10 = $b10 - $r/10;

     if (($kwota - $b10 * 10 ) >= 5) 
     {
         $b5 = 1;        // ilośc monet 5zł
     }

$r2 = ($kwota - $b10 * 10 - $b5 * 5 ) ; // pozostala kwota (dla  monet 2zł i 1zł))

if ($r2 == 4) {          // kod dziala jezeli użyję >=4 
    $b2 = 2;
  
}

 if ($r2 == 3) {
     $b2 = 1;
     $b1 = 1;
 }

if ($r2 == 2) {
     $b2 = 1;
 }
 if ($r2 == 1) {
     $b1 = 1;
 }

 echo "Kwota   = ".$kwota. "<br><br>";
 
 echo " Banknotów 10 zl   ---".$b10 ."<br>";
 echo "Monet 5 zł        --- ".$b5."<br>";
 echo "Monet 2 zł        ---  ".$b2. "<br>";
 echo "Monet 1 zł        ---  ".$b1."<br>";

 ?>
2

r2 to float z obliczeń dlatego Ci nie pasuje do == 4.

Śpiący jestem ale na szybko nie lepiej tak?

<?php

$amount = 164;

$banknots = [10 => 0, 5 => 0, 2 => 0, 1 => 0];

foreach($banknots as $nominal => $numbers) {
    $mod = $amount % $nominal;
    $numbers = ($amount - $mod) / $nominal;
    
    $amount -= $numbers * $nominal;
    
    $banknots[$nominal] = $numbers;
}

var_dump($banknots);
0

Dziękuję za odpowiedź .
Masz bez wątpienia rację. Tylko nie rozumiem dlaczego ten, mój ,działa dobrze dla wszystkich innych liczb.174, 184, itd.
Widzę już, że ma błąd , ale dlaczego tak "wybiórczo" oblicza. Błąd to błąd,powinien być cały czas.

2

@adikama: poczytaj o IEEE 754.

Wewnętrzna interpretacja liczb zmiennoprzecinkowych jest niedokładna. Dla jednej liczby dostaniesz przypadkowo dobry wynik, a inna liczba może mieć pecha...

1
adikama napisał(a):

Masz bez wątpienia rację. Tylko nie rozumiem dlaczego ten, mój ,działa dobrze dla wszystkich innych liczb.174, 184, itd.
Widzę już, że ma błąd , ale dlaczego tak "wybiórczo" oblicza. Błąd to błąd,powinien być cały czas.

Te liczby nie są specjalne, po prostu reprezentacja liczb float ma określoną precyzję, i Twoje obliczenia skutkują liczbą która wykracza poza tą precyzję. To właściwie ten sam problem, jak w JavaScript, gdzie 0.1 + 0.2 == 0.3; // false.

W skrócie, liczb zmiennoprzecinkowych (jak np 10.0, 12.04, 0.0034) nie można porównać ==. Jeśli dostaniesz false z porównania float == float, to nie koniecznie one są różne; a jak dostaniesz true to nie koniecznie są równe. Jedyne co możesz zrobić to porównać > lub <, albo sprawdzić jak duża jest różnica pomiędzy liczbami, ale == nie.

0

I wszystko stało się jasne.
Dzięki za odpowiedzi.

1 użytkowników online, w tym zalogowanych: 0, gości: 1