![]() |
![]() |
![]()
Post
#1
|
|
Grupa: Zarejestrowani Postów: 2 Pomógł: 0 Dołączył: 16.12.2009 Ostrzeżenie: (0%) ![]() ![]() |
Witam,
ostatnio spotkałem się z dość dziwną sytuacją. Zrobiłem programik w PHP który zlicza mi pewne dane typu float z bazy mySQL. Operacje obliczeniowe wykonało samo zapytanie SQL-a. Problem pojawia mi się dopiero wtedy gdy zaczynam mnożyć przez siebie liczby które mają np jedno miejsce po przecinku, np. gdy pomnoże: 2*5,3 to wynik jest 10,6 ale gdy pomnoże 3*5,3 to wynik jest 15,8999999999999998 zauważyłem że jeśli pomnożył bym 5,3 razy wielokrotność liczby 3 to również będzie zwracalo jakieś głupoty. Przeciesz oczywiste jest że wynik powinien wyjść 15,9 a nie 15,899999998 Skąd te błędy? Zauważyłem również, że w javascript gdy mnoże dwie wartości z pól edit przez siebie to sytuacja jest identyczna. Dla przykładu podam jeszcze, że np 3*5,4 = 16.200000000000003 - a nie jak powinno być 16,2. Skąd się biorą te błędy i jak je wyeliminować? z góry dzięki za odpowiedzi. |
|
|
![]() |
![]()
Post
#2
|
|
Grupa: Zarejestrowani Postów: 952 Pomógł: 154 Dołączył: 20.01.2007 Skąd: /dev/oracle Ostrzeżenie: (0%) ![]() ![]() |
Nie da się tego wyeliminować. Jak niby wyobrażasz sobie dokładne zapisanie niepoliczalnie wielkiej ilości liczb rzeczywistych na skończonej, kilkudziesięciobitowej przestrzeni? Arytmetyka zmiennoprzecinkowa z definicji jest niedokładna. Każde działanie wykonywane w niej jest obarczone pewnym błędem. Właściwości:
* Działania zmiennoprzecinkowe nie są łączne. x + (y + z) nie musi być równe (x + y) + z * Nie są rozdzielne: x* ( y + z ) != x * y + x * z Ponadto w tej arytmetyce dokładnie da się zapisać jedynie ułamki o mianowniku będącym potęgą dwójki, np. 1/2 albo 3/16. Pozostałe mają rozwinięcia binarne nieskończone i nie da się ich dokładnie zapisać. W Twoim przypadku ułamek 5,3 nie ma mianownika będącego potęgą dwójki, zatem już na wstępie obarczony jest pewnym błędem, który się kumuluje podczas obliczeń. Jeśli potrzebujesz precyzyjnych obliczeń (np. do obliczeń finansowych, które NIGDY nie powinny być robione w arytmetyce zmiennoprzecinkowej), musisz używać typów stałoprzecinkowych. W PHP ich nie ma, ale to nic nie szkodzi, gdyż można je prosto zasymulować, przekształcając je na zwykłe, całkowite. |
|
|
![]() ![]() |
![]() |
Aktualny czas: 12.10.2025 - 13:29 |