znaczacy > comp.* > comp.programming

Pszemol (12.06.2019, 14:17)
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ą?
Mateusz Viste (12.06.2019, 14:29)
On Wed, 12 Jun 2019 07:17:45 -0500, Pszemol wrote:
> Piszac w Visual Basic 6 gostek porównywal rezultat konwersji CDbl()
> stringu od którego odjal stala numeryczna 1.8 do lokalnej zmiennej
> double.


Prawdziwi programisci nie uzywaja liczb zmiennoprzecinkowych.

Obowiazkowa lektura na wieczór:


Mateusz
J.F. (12.06.2019, 14:44)
Użytkownik "Pszemol" napisał w wiadomości grup
dyskusyjnych:qdqqh6$n2f$1...
>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.
Zbych (12.06.2019, 14:48)
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 :-)
Irek.N. (12.06.2019, 14:56)
> 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.
bartekltg (12.06.2019, 15:07)
On Wednesday, June 12, 2019 at 2:17:44 PM UTC+2, Pszemol wrote:
[..]
> Endif.
> Pierwszy tekst z RS232 byl 32.8, drugi 31. 32.8-1.8 = 31.
> Powinno byc wszystko ok, bo w matematyce 31 równe jest 31 :-)


Ale nie dzialasz na liczbach rzeczywistych, ale na reprezentacji
zmiennoprzecinkowej.
Wszytkie trzy liczby tak naprawde maja wartosc tylko zblizona
do tych napisanych.

> Wynik porównania VB6 byl 31 nie jest równe 31 i program
> kapitulowal...
> Po zamienieniu testu "if double <> double then" na test
> "if double - double < -0.001 Or double - double > 0.001 then"
> program zaczal pracowac normalnie.


Uzywaj funkcji abs, to samo, a czytelniej.

Tak, to jest poprawne rozwiazanie.

> Przyczyna bledu byla róznica odejmowania wynoszaca 15.1234e-15
> Dlaczego konwersja CDbl stringu 31 lub 32.8 dodaje jakies
> smieci do zmiennej double float na 15 miejscu po przecinku??
> A moze odejmowanie stalej 1.8 wprowadza ten blad?
> Czy to jest normalne zachowanie sie VB6?
> Czy inne Visuale jak VC++ lub VC# tez tak maja?


W sumei to pierwsz rzecz, jakiej czlowiek sie dowiaduja na jakimkolwiek
powazniejsyzm kursie dotykajacym zmiennego przecinka. Ze szczegolnym
uwzlgednieniem
"Nie wykonuj porównania == i <> na liczbach zmiennoprzecinkowych"

A jaka przyczyna? To przy okazji opisuja.

Zerknij na wiki, jak wyglada liczba zmiennoprzecinkowa.

2^cos *1.mantysa.

1/2 tak zapiszesz, ale 1/3 nie. 1/10 tez nie.
Zerknij tutaj,

Liczy na single, ale zasada ta sama.
wpisujac 1.8 tak naprawde trzymasz najblizsza
reprezentaowalna liczbe, 1.7999999523162841796875
Podobnie 32.8.
31 jest reprezentowane dokladnie.

Teraz kazda podstawowa operacja arytmetyczna bioraca argumenty
a i b (oznaczamy fl(a) i fl(b) jako wartosci reprezentowane) liczy
fl(a) (dzialanie) fl(b) dokladnie, a potem zapisuje jako najblizsza
reprezentowalna wartosc.

W ogolnosci
fl(a+b) = (fl(a)+fl(b))(1+eps), gdize ten epsylon to dokladnosc
reprezentacji.

pzdr
bartekltg
JDX (12.06.2019, 15:21)
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
Szyk Cech (12.06.2019, 16:52)
> 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ć).
Queequeg (12.06.2019, 16:53)
In pl.misc.elektronika Mateusz Viste <mateusz> 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ć.
Cezary Gradys (12.06.2019, 16:54)
W dniu 12.06.2019 o 14:29, Mateusz Viste pisze:

> Prawdziwi programisci nie uzywaja liczb zmiennoprzecinkowych.
> Obowiazkowa lektura na wieczór:
>


Nie ma co przesadzac, liczby zmiennoprzecinkowe po to powstaly, zeby je
uzywac. Trzeba tylko porównywac je zakladajac pewna dopuszczalna
tolerancje.
J.F. (12.06.2019, 17:27)
Użytkownik "Szyk Cech" napisał w wiadomości grup
dyskusyjnych:Jk8ME.2$6r.0...
>> 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ć).


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.
stary grzyb (12.06.2019, 18:17)
> Kto nie uczyl sie Fortranu, ten nie zna zycia :-)

Prawda, ale wcześniej trzeba było zaliczyć Algol.
Pszemol (13.06.2019, 15:24)
"JDX" <jdx> wrote in message
news:5112
> 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


To raczej utrzymywanie starego kodu.
Pszemol (13.06.2019, 15:35)
"Szyk Cech" <szykcech> wrote in message
news:26r0
> Weź chłopie ić na studia (ja miałem to nawet na wieczorowych
> 20 lat temu) i się doucz! Zamiast zadawać głupie pytania.


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

> 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ć).


ha ha :-) No brawo.
Pszemol (13.06.2019, 15:37)
"Mateusz Viste" <mateusz> wrote in message
news:74cc
> On Wed, 12 Jun 2019 07:17:45 -0500, Pszemol wrote:
>> Piszac w Visual Basic 6 gostek porównywal rezultat konwersji CDbl()
>> stringu od którego odjal stala numeryczna 1.8 do lokalnej zmiennej
>> double.

> Prawdziwi programisci nie uzywaja liczb zmiennoprzecinkowych.


Faktem jest, ze gdy zmienne nie skacza dynamicznie od e-15 do e+15 to
warto znalezc zakres wariacji mierzonej zmiennej, oczekwiana dokladnosc
i zamiast na float operowac na long integer * 10000 na przyklad...

> Obowiazkowa lektura na wieczór:
>


Dzieki za linka, zapoznam sie w wolnym czasie.

Podobne wątki