Porównywanie liczb, double float

Witam, spędziłem wczoraj sporo godzin w biurze na debugowaniu kodu napisanego przez naszego kontraktora i w końcu znalazłem buga. Przyczyną błędu była różnica odejmowania dwu liczb całkowitych wynosząca 15.1234e-15 :-)

Ale może więcej szczegółów podam:

Pisząc w Visual Basic 6 gostek porównywał rezultat konwersji CDbl() stringu od którego odjął stałą numeryczną 1.8 do lokalnej zmiennej double.

Czyli mamy kod:

Sub AlaMaKota(nieważne tutaj argumenty procedury) Dim len as Double

len = CDbl("tekst wydłubany z RS232") - 1.8

If len <> CDbl("inny tekst wydłubany z RS232) Then zgłoś błąd i kapitulujemy... kaput! Else lecimy z testami talej, wsio w pariadkie Endif.

Pierwszy tekst z RS232 był 32.8, drugi 31. 32.8-1.8 = 31. Powinno być wszystko ok, bo w matematyce 31 równe jest 31 :-) Wynik porównania VB6 był 31 nie jest równe 31 i program kapitulował...

Po zamienieniu testu "if double <> double then" na test "if double - double < -0.001 Or double - double > 0.001 then" program zaczął pracować normalnie.

Przyczyną błędu była różnica odejmowania wynosząca 15.1234e-15

Dlaczego konwersja CDbl stringu 31 lub 32.8 dodaje jakieś śmieci do zmiennej double float na 15 miejscu po przecinku?? A może odejmowanie stałej 1.8 wprowadza ten błąd?

Czy to jest normalne zachowanie się VB6?

Czy inne Visuale jak VC++ lub VC# też tak mają?

Reply to
Pszemol
Loading thread data ...

Prawdziwi programiści nie używają liczb zmiennoprzecinkowych.

Obowiązkowa lektura na wieczór:

formatting link
Mateusz

Reply to
Mateusz Viste

Użytkownik "Pszemol" napisał w wiadomości grup dyskusyjnych:qdqqh6$n2f$ snipped-for-privacy@dont-email.me...

To nie jest problem VB, to jest problem przyjetego formatu liczb rzeczywistych. Albo problem programisty :-)

31 jest dokladne, 0.8 nie. 0.5 jest dokladne, 0.25 i 0.75 itd - ale wiekszosc liczb "dziesietnych po przecinku" niestety nie.

Po prostu nie da sie zapisac 32.8 dokladnie. Programista ma o tym wiedziec i sie zabezpieczyc :-)

To jest problem procesora z FP IEEEcostam.

Akurat .net ma dodatkowe formaty (Decimal), w ktorych powinno to dzialac. Tylko trzeba ie Ale i tak bym dorzucil zabezpieczenie.

Problem promieniuje na bazy danych, gdzie mamy duzo kwot, a te grosze tez nie sa dokladne :-)

J.

Reply to
J.F.

W dniu środa, 12 czerwca 2019 14:17:44 UTC+2 użytkownik Pszemol napisał:

Mniej więcej wszystko tak ma. "Normalne" typy zmiennoprzecinkowe (normalne, czyli float, double, zapisywane w stałej ilości bitów) odwzorowują liczby z jakąśtam dokładnością. Podczas operacji prawie zawsze wprowadza się jakąś odchyłkę. Porównywanie takich liczb na równość lub różność to źródło smrodu. Twój fix jest ok, to zdrowa praktyka na porównanie liczb zmiennoprzecinkowych: if abs(x-y)<0.00...001 then...

WP

Reply to
Wojciech Piechowski

W dniu 12.06.2019 o 14:17, Pszemol pisze:

Bo typy rzeczywiste mają dużą dynamikę kosztem dużego szumu :-)

Reply to
Zbych

Kurde, a ja myślałem, że to jitter. Chociaż nie, jitter jest losowy, a tutaj mamy całkowitą powtarzalność, coś jak problem z kwantami bardziej ;)

Miłego. Irek.N.

Reply to
Irek.N.

On 2019-06-12 14:17, Pszemol wrote: [...]

No nieźle, nieźle. Myślałem, że to ja jestem dinozaurem, który w chacie używa WinXP, a tu widzę, że ludzie jeszcze komercyjnie piszą coś nowego pod VB6, do którego extended support skończył się w 2008. :-D Tak mnie jakoś tknął ten VB6, bo pamiętam, jak mój koleżka się nim zachwycał gdzieś pod koniec lat 90-tych. :-D

Reply to
JDX

Weź chłopie ić na studia (ja miałem to nawet na wieczorowych 20 lat temu) i się doucz! Zamiast zadawać głupie pytania. Choć gdybyś dłubał w czymś innym niż VB to byś wiedział o problemie (w każdej książce do Asemblera czy C czy C++ to powinno być).

Reply to
Szyk Cech

Nie szedłbym tak daleko. Oczywiście używają ale wiedzą też, jakie są ich ograniczenia i jak je porównywać.

Reply to
Queequeg

W dniu 12.06.2019 o 14:29, Mateusz Viste pisze:

Nie ma co przesadzać, liczby zmiennoprzecinkowe po to powstały, żeby je używać. Trzeba tylko porównywać je zakładając pewną dopuszczalną tolerancję.

Reply to
Cezary Grądys

Użytkownik "Szyk Cech" napisał w wiadomości grup dyskusyjnych:Jk8ME.2$ snipped-for-privacy@fx19.fr...

Musialbym sobie przypomniec ... ale przy okazji Assemblera raczej nikt nie poruszal takiego watku. Przy C predzej, ale to gdzies na pograniczu.

Kto nie uczyl sie Fortranu, ten nie zna zycia :-)

J.

Reply to
J.F.

W dniu środa, 12 czerwca 2019 07:17:44 UTC-5 użytkownik Pszemol napisał:

Koledzy juz powiedzieli co trzeba. Ja dodam ze jak ten kto ten program pisal naprawde malo wie i jesli on dzialal wczesniej to tylko przypadkiem.

Jesli on, ten kontraktor jest z indii to albo zglos to jako ryzyko projekt managerowi i zasugeruj zeby znalezli nieco kompetentniejszego albo od teraz testujcie wszystko tak jakby to wam, nie przymierzajac, malpa pisala.

Co do PM-a. Policz ile czasu na to poswieciles, udokumentuj buga i zbieraj. Jak sie trafi kolejny taki kwiatek to zbieraj w kupke. Nawet dobry PM nie unegocjuje wiele bez podkladki. A negocjacje nie koniecznie musza sie toczyc z kontraktorem, moze to byc tez wewnetrzne tarcie na zmiane na inna lige cenowa. Podkladka czyni cuda.

Reply to
sczygiel

Prawda, ale wcześniej trzeba było zaliczyć Algol.

Reply to
stary grzyb

To raczej utrzymywanie starego kodu.

Reply to
Pszemol

Ale kultury osobistej Cię tam nie nauczyli... szkoda.

ha ha :-) No brawo.

Reply to
Pszemol

Nie wiem jaką mają z nim umowę. Ale ich wystawił do wiatru bo ostatnio jakąś dodatkową funkcję chcieli dodać do programu i nie był zainteresowany aby przyjść i pisać ten kod dalej... Gdy patrzę jak jest kod napisany to się nie dziwię.

Reply to
Pszemol

Faktem jest, że gdy zmienne nie skaczą dynamicznie od e-15 do e+15 to warto znaleźć zakres wariacji mierzonej zmiennej, oczekwianą dokładność i zamiast na float operować na long integer * 10000 na przykład...

Dzięki za linka, zapoznam się w wolnym czasie.

Reply to
Pszemol

Teraz jak czytam co napisałeś to wydaje się to oczywiste. Ale taki byłem szczęśliwy że wreszcie znalazłem buga i uruchomiłem program że samamu mi się ta klapka w mózgu nie odklapiła - dzięki.

Reply to
Pszemol

W dniu 2019-06-12 o 14:17, Pszemol pisze:

Kiedy dawno temu (naprawdę dawno) pisałem/modyfikowałem program do pracy dyplomowej to w pewnym momencie zaczął się wysypywać z błędem dzielenia przez zero. Po dochodzeniu okazało się że pomimo jawnej deklaracji double pewne konkretne obliczenia robił na real i w mianowniku pojawiało się zero. Żadne jawne deklaracje i wymuszenia typu obliczeń tego nie potrafiły zmienić, pomogła dopiero zmiana kompilatora. Sztuczne dodanie obliczeń powodowało tylko przesunięcie momentu wywalenia się programu. Podobne obliczenia w innym miejscu robił jak należy. A ten drugi (właściwie to on był pierwszy tylko z pewnych powodów chciałem użyć innego) nie miał w ogóle takich problemów.

Pozdrawiam

DD

Reply to
Dariusz Dorochowicz

I tam. Nieprawda. W _kazdym_ systemie/formacie FP moze sie zdarzyc.

_Wylacznie_ problem programisty.

Prawda!

Wcale nie. To jest problem jak najbardziej ogolny.

Racja! Sam Decimal tak naprawde przed niczym sam z siebie nie chroni.

Raaacja ! :)

AK

Reply to
AK

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.