-
1. Data: 2019-06-12 14:17:45
Temat: Porównywanie liczb, double float
Od: "Pszemol" <P...@P...com>
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ą?
-
2. Data: 2019-06-12 14:29:41
Temat: Re: Porównywanie liczb, double float
Od: Mateusz Viste <m...@n...pamietam>
On Wed, 12 Jun 2019 07:17:45 -0500, Pszemol wrote:
> 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.
Prawdziwi programiści nie używają liczb zmiennoprzecinkowych.
Obowiązkowa lektura na wieczór:
http://perso.ens-lyon.fr/jean-michel.muller/goldberg
.pdf
Mateusz
-
3. Data: 2019-06-12 14:44:39
Temat: Re: Porównywanie liczb, double float
Od: "J.F." <j...@p...onet.pl>
Użytkownik "Pszemol" napisał w wiadomości grup
dyskusyjnych:qdqqh6$n2f$...@d...me...
>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ł...
>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?
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 :-)
>Czy inne Visuale jak VC++ lub VC# też tak mają?
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.
-
4. Data: 2019-06-12 14:48:08
Temat: Re: Porównywanie liczb, double float
Od: Zbych <a...@o...pl>
W dniu 12.06.2019 o 14:17, Pszemol pisze:
> Dlaczego konwersja CDbl stringu 31 lub 32.8 dodaje jakieś
> śmieci do zmiennej double float na 15 miejscu po przecinku??
Bo typy rzeczywiste mają dużą dynamikę kosztem dużego szumu :-)
-
5. Data: 2019-06-12 14:56:57
Temat: Re: Porównywanie liczb, double float
Od: "Irek.N." <t...@j...taki.jest>
> Bo typy rzeczywiste mają dużą dynamikę kosztem dużego szumu :-)
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.
-
6. Data: 2019-06-12 15:07:23
Temat: Re: Porównywanie liczb, double float
Od: bartekltg <b...@g...com>
On Wednesday, June 12, 2019 at 2:17:44 PM UTC+2, Pszemol wrote:
> 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 :-)
Ale nie działasz na liczbach rzeczywistych, ale na reprezentacji
zmiennoprzecinkowej.
Wszytkie trzy liczby tak naprawde mają wartość tylko zblizoną
do tych napisanych.
> 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.
Używaj funkcji abs, to samo, a czytelniej.
Tak, to jest poprawne rozwiązanie.
> 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ą?
W sumei to pierwsz rzecz, jakiej człowiek sie dowiaduja na jakimkolwiek
poważniejsyzm kursie dotykającym zmiennego przecinka. Ze szczegolnym
uwzlgędnieniem
"Nie wykonuj porównania == i <> na liczbach zmiennoprzecinkowych"
A jaka przyczyna? To przy okazji opisują.
Zerknij na wiki, jak wyglada liczba zmiennoprzecinkowa.
2^coś *1.mantysa.
1/2 tak zapiszesz, ale 1/3 nie. 1/10 też nie.
Zerknij tutaj,
https://www.h-schmidt.net/FloatConverter/IEEE754.htm
l
Liczy na single, ale zasada ta sama.
wpisując 1.8 tak naprawdę trzymasz najbliższa
reprezentaowalną liczbę, 1.7999999523162841796875
Podobnie 32.8.
31 jest reprezentowane dokładnie.
Teraz każda podstawowa operacja arytmetyczna biorąca argumenty
a i b (oznaczamy fl(a) i fl(b) jako wartośći reprezentowane) liczy
fl(a) (działanie) fl(b) dokładnie, a potem zapisuje jako najbliższa
reprezentowalna wartość.
W ogolności
fl(a+b) = (fl(a)+fl(b))(1+eps), gdize ten epsylon to dokłądność
reprezentacji.
pzdr
bartekltg
-
7. Data: 2019-06-12 15:21:31
Temat: Re: Porównywanie liczb, double float
Od: JDX <j...@o...pl>
On 2019-06-12 14:17, Pszemol wrote:
[...]
> Pisząc w Visual Basic 6 gostek porównywał rezultat konwersji CDbl()
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
-
8. Data: 2019-06-12 16:52:25
Temat: Re: Porównywanie liczb, double float
Od: Szyk Cech <s...@s...pl>
> 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ą?
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ć).
-
9. Data: 2019-06-12 16:53:05
Temat: Re: Porównywanie liczb, double float
Od: q...@t...no1 (Queequeg)
In pl.misc.elektronika Mateusz Viste <m...@n...pamietam> wrote:
> Prawdziwi programiści nie używają liczb zmiennoprzecinkowych.
Nie szedłbym tak daleko. Oczywiście używają ale wiedzą też, jakie są ich
ograniczenia i jak je porównywać.
--
Eksperymentalnie: http://facebook.com/groups/pl.misc.elektronika
-
10. Data: 2019-06-12 16:54:15
Temat: Re: Porównywanie liczb, double float
Od: Cezary Grądys <c...@w...onet.pl>
W dniu 12.06.2019 o 14:29, Mateusz Viste pisze:
>
> Prawdziwi programiści nie używają liczb zmiennoprzecinkowych.
>
> Obowiązkowa lektura na wieczór:
> http://perso.ens-lyon.fr/jean-michel.muller/goldberg
.pdf
>
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ę.
--
Cezary Grądys
c...@w...onet.pl