Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> php kilejność działań, Dlaczego PHP nie umie liczyć?
mimol
post
Post #1





Grupa: Zarejestrowani
Postów: 247
Pomógł: 5
Dołączył: 10.12.2007

Ostrzeżenie: (0%)
-----


Witam, niedawno miałem problem związany z tym, że PHP nie umie liczyć.
Mógłby ktoś wytłumaczyć mi na czym polega problem?
Wiem, że to ma związek z floating point i precyzją, ale to są PROSTE działania, max 3 miejsca po przecinku...
Załóżmy że mam taki kod
  1. $price = 24.5;
  2. $discountPrice = 7.35;
  3. $discount = $price - $discountPrice;
  4.  
  5.  
  6. $offerValue = 100 * $discount / $price;
  7. var_dump($offerValue); // zwraca ładnie 70
  8. var_dump((int)$offerValue); // zwraca 69 tutaj magia...
  9.  
  10. //idzemy więc dalej
  11. $offerValue = 100 * ($discount / $price);
  12. var_dump((int)$offerValue); // zwraca 70, zmiana kolejności wykonywania działań,


Proszę o podanie jakiegoś powodu dlaczego
  1. //discount / price = 0.7
  2. echo (int)(100 * ($discount / $price)); //70
  3. echo (int)(100 * $discount / $price); //69
  4. echo (int)($discount / $price * 100); //70


ew jak wyświetlić prawdziwą wartość $discount / $price (powinno być 0.7) a pewnie jest (6.9999999999999999999),
Oczywiście poradziłem sobie używając bcmath

Ten post edytował mimol 31.12.2013, 19:10:34
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi (1 - 11)
com
post
Post #2





Grupa: Zarejestrowani
Postów: 3 034
Pomógł: 366
Dołączył: 24.05.2012

Ostrzeżenie: (0%)
-----


no a czemu się dziwisz rzutujesz float na inta, a php to chyba już wszyscy wiedza nie radzi sobie z matematyką jak jego starsi bracia
Bo wynik masz taki:
Cytat
float(70)
int(69)
int(70)
Go to the top of the page
+Quote Post
mimol
post
Post #3





Grupa: Zarejestrowani
Postów: 247
Pomógł: 5
Dołączył: 10.12.2007

Ostrzeżenie: (0%)
-----


Proszę czytać uważnie....

"Proszę o podanie jakiegoś powodu dlaczego" (zmiana kolejności wykonywania działań, zmienia liczbę)
Go to the top of the page
+Quote Post
com
post
Post #4





Grupa: Zarejestrowani
Postów: 3 034
Pomógł: 366
Dołączył: 24.05.2012

Ostrzeżenie: (0%)
-----


no to Ci dałem powód, php przy którymś miejscu po przecinku się gubi, a ponieważ masz liczbę zmiennoprzecinkową a potem chcesz z niej zrobić całkowitą dlatego zwraca 69 zamiast 70 wink.gif

specjalnie wrzuciłem wynik żebyś zobaczył jakiego typy zwracany jest wynik wink.gif

  1. $price = 24.5;
  2. $discountPrice = 7.35;
  3. $discount = $price - $discountPrice;
  4.  
  5. echo 100 * $discount / $price; // zwróci 70


Ten post edytował com 31.12.2013, 19:34:04
Go to the top of the page
+Quote Post
zegarek84
post
Post #5





Grupa: Zarejestrowani
Postów: 1 332
Pomógł: 294
Dołączył: 12.10.2008
Skąd: Olkusz

Ostrzeżenie: (0%)
-----


php jest dynamicznie rzutowany trochę dla wygody... wykonaj kilka operacji matematycznych na różnych typach liczb np. w c++ oraz wykonaj kilka rzutowan w trakcie, spróbuj zrozumieć gdzie tracisz precyzję to zrozumiesz gdzie problem i nie będziesz zaprzagal do obliczeń kobyly tam gdzie nie ma takiej potrzeby...


--------------------
Jeśli twoja ręka rusza do przodu powstrzymaj swój gniew; gdy wyprzedza cię twój gniew - wycofaj rękę.

Go to the top of the page
+Quote Post
com
post
Post #6





Grupa: Zarejestrowani
Postów: 3 034
Pomógł: 366
Dołączył: 24.05.2012

Ostrzeżenie: (0%)
-----


polecam ten materiał http://gynvael.coldwind.pl/?id=492 wink.gif
Go to the top of the page
+Quote Post
bostaf
post
Post #7





Grupa: Zarejestrowani
Postów: 374
Pomógł: 79
Dołączył: 6.04.2010
Skąd: Ostrów Wielkopolski

Ostrzeżenie: (0%)
-----


Magia dzieje się już tutaj:
  1. $discount = $price - $discountPrice;

Zobacz, co wyświetla
  1. echo number_format($discount, 100);
  2. // wyświetli: 17.14999999999999857891452847979962825775146484375000000000000000000000000000000
    00000000000000000000000

Fajne, no nie? smile.gif
Wyjaśnienie tego zjawiska jest tutaj: http://docs.oracle.com/cd/E19957-01/806-35...g_goldberg.html (nie proś mnie o streszczenie wink.gif).
Sposób radzenia sobie z operacjami arytmetycznymi na liczbach zmiennoprzecinkowych tutaj: http://php.net/types.float (w czerwonej ramce).
Go to the top of the page
+Quote Post
Crozin
post
Post #8





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


Cytat
Wiem, że to ma związek z floating point i precyzją, ale to są PROSTE działania, max 3 miejsca po przecinku...
Nie chodzi o liczbę cyfr po przecinku, a o możliwość ich zapisania bez utraty dokładności. I tak 0,1 zostanie zapisane z utratą danych, a 0,5 zostanie zapisane bez utraty danych mimo iż obie mają ledwie jedną cyfrę po przecinku.
Zmiana kolejności wykonywania działań sprawia, że inna ilość danych jest tracona na innym etapie co ma wpływ na końcowy wynik.
Cytat
Oczywiście poradziłem sobie używając bcmath
Niepotrzebnie zaprzęgasz tutaj BC Math, skorzystaj ze zwykłego round.

Ten post edytował Crozin 1.01.2014, 23:48:49
Go to the top of the page
+Quote Post
toffiak
post
Post #9





Grupa: Zarejestrowani
Postów: 395
Pomógł: 80
Dołączył: 24.08.2009

Ostrzeżenie: (0%)
-----


Mały offtop odnośnie złego PHP które nawet nie potrafi poprawnie liczyć:

Python też "nie potrafi" liczyć poprawnie:

Kod
price = 24.5
discount_price = 7.35
discount = price - discount_price
offer_value = 100 * discount / price

print(offer_value)        # 69.999999999....
print(int(offer_value))   # 69

offer_value = 100 * ( discount / price )
print(int(offer_value))   # 70


--------------------
Go to the top of the page
+Quote Post
mimol
post
Post #10





Grupa: Zarejestrowani
Postów: 247
Pomógł: 5
Dołączył: 10.12.2007

Ostrzeżenie: (0%)
-----


  1. $price = 24.5;
  2. $discountPrice = 7.35;
  3. $discount = $price - $discountPrice;
  4.  
  5.  
  6. $offerValue = 100 * $discount / $price;
  7. echo number_format((100 * $discount / $price), 13); //70
  8. echo number_format((100 * $discount / $price), 14); //69.99

Ktoś wyjaśni skad to się bierze? Dlaczego 14 jest magiczna?
Go to the top of the page
+Quote Post
Crozin
post
Post #11





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


Nie jest żadną magiczną liczbą. Popatrz sobie na dokładne wartości liczbowe i ilość dziewiątek po przecinku: http://ideone.com/Bfdmye
Go to the top of the page
+Quote Post
bostaf
post
Post #12





Grupa: Zarejestrowani
Postów: 374
Pomógł: 79
Dołączył: 6.04.2010
Skąd: Ostrów Wielkopolski

Ostrzeżenie: (0%)
-----


Cytat(Crozin @ 2.01.2014, 22:34:42 ) *
Nie jest żadną magiczną liczbą. Popatrz sobie na dokładne wartości liczbowe i ilość dziewiątek po przecinku: http://ideone.com/Bfdmye

Dokładnie. To wynika z zaokrąglania pełnej wartości przechowywanej w pamięci. Nie wiem jaka dokładnie jest precyzja wartości przechowywanej w pamięci, ale przy 50 cyfrach po przecinku:
  1. number_format((100 * $discount / $price), 50);
  2. // 69.99999999999998578914528479799628257751464843750000

Zostawiając tylko 14 cyfr dostaniemy:
Kod
69.99999999999998

co zostanie wyświetlone z zaokrągleniem ostatniej 8 do 9, bo kolejna cyfra to 5 (czyli zaokrąglenie w górę).
Przy 13 miejscach po przecinku
Kod
69.9999999999999

co zostanie wyświetlone z zaokrągleniem ostatniej 9 do 0, bo kolejna cyfra to 8 (czyli zaokrąglenie w górę). Zamiana ostatniej cyfry znaczącej na 0 spowoduje łańcuch takich samych zaokrągleń powodujący wyświetlenie tej liczby jako 70,0000000000000.
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 19.08.2025 - 10:14