logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[Delphi] Delphi 2007: Różnice w porównaniu liczb w instrukcji IF i zmiennych

redie 01 Wrz 2011 10:05 1844 15
REKLAMA
  • #1 9884017
    redie
    Poziom 16  
    Posty: 169
    Pomógł: 25
    Ocena: 1
    Witam,
    zauważyłem w Delphi 2007 różnicę w wykonaniu warunku porównującego dwie liczby w zależności od tego czy są one wpisane bezpośrednio do instrukcji IF czy najpierw są przypisane do zmiennych.
    Poniższy przykład pokazuje o co mi chodzi. Wynikiem jest to że pierwszy warunek zwraca False a drugi True a powinno być True w obu przypadkach.

    Czy ktoś może mi wytłumaczyć dokładnie co jest przyczyną takiego zachowania? Czy jest to zależne od ustawień parametrów projektu?

    Kod: Delphi
    Zaloguj się, aby zobaczyć kod
  • REKLAMA
  • #2 9884044
    Ilmarinen
    Poziom 14  
    Posty: 106
    Pomógł: 10
    Ocena: 16
    Weź działania w nawias.
    
    Kod Delphi - [rozwiń]
    var
      e,f: Double;
    begin
    [b]if (5*(30/360)) = (5/12)[/b]
      then Memo1.Lines.Add('test porównania: True')
      else Memo1.Lines.Add('test porównania: False');
     
      e := 5*(30/360);
      f := 5/12;
      if e = f
      then Memo1.Lines.Add('test porównania zmiennych: True')
      else Memo1.Lines.Add('test porównania zmiennych: False');
    end;
    
  • REKLAMA
  • #3 9884049
    Szymon Tarnowski
    Poziom 27  
    Posty: 1292
    Pomógł: 61
    Ocena: 181
    Możliwe że w pierwszym warunku liczby są castowane na całkowite.
    Mea culpa, to by spowodowało że 0 = 0 i wynik true.
  • #4 9884056
    redie
    Poziom 16  
    Posty: 169
    Pomógł: 25
    Ocena: 1
    Dodanie tych nawiasów nic nie zmienia. Ale jako ciekawostkę napiszę, że usunięcie nawiasów poprawia sytuację.
    Mimo wszystko jak ktoś potrafi to wytłumaczyć to prosiłbym o odpowiedź.

    Kod: Delphi
    Zaloguj się, aby zobaczyć kod
  • #6 9884151
    redie
    Poziom 16  
    Posty: 169
    Pomógł: 25
    Ocena: 1
    Po zamianie kolejności na to co zaproponowałeś zadziałało, ale jak wpisałem 1 zamiast 5 to już nie.

    Kod: Delphi
    Zaloguj się, aby zobaczyć kod
  • #7 9884302
    Ilmarinen
    Poziom 14  
    Posty: 106
    Pomógł: 10
    Ocena: 16
    Myśle że przyczyną może być to że działanie 5/30 jest wykonywane nie przez program docelowy tylko przez kompilator i tu może być różnica w obliczaniu wartości. Stosując zmienne to program wykonuje obliczenia.
  • REKLAMA
  • #8 9884304
    Szymon Tarnowski
    Poziom 27  
    Posty: 1292
    Pomógł: 61
    Ocena: 181
    redie napisał:
    Po zamianie kolejności na to co zaproponowałeś zadziałało, ale jak wpisałem 1 zamiast 5 to już nie.

    Kod: Delphi
    Zaloguj się, aby zobaczyć kod
    Nie mam delphi pod ręką, a tym bardziej 2007, ale może uda się taka sztuczka żeby dowiedzieć się jak kompilator przetwarza te obliczenia wartości stałych:
    Kod: Delphi
    Zaloguj się, aby zobaczyć kod

    Kod: Delphi
    Zaloguj się, aby zobaczyć kod

    W obu przypadkach chodzi o to żeby kompilator sam dobrał typy a nie sugerować mu tego tego przez typ zmiennej do której się przypisuje. Writeln to zaszłość jeszcze ze starego Turbo Pascala, tylko trzeba program zrobić jako aplikację konsolową.
  • REKLAMA
  • #9 9884393
    redie
    Poziom 16  
    Posty: 169
    Pomógł: 25
    Ocena: 1
    Operacje arytmetyczne na "stałych" które w kodzie zostały wpisane w postaci liczb (nie zmiennych) są wykonywane przez preprocesor, więc to on jest odpowiedzialny za błąd.

    Sprawdziłem poniższy kod i wartości są identyczne dla danej linii.
    W tym kodzie również chyba ten preprocesor bierze udział wciskając od razu wartość którą policzył. A skoro na konsoli obie wyglądają tak samo to chyba oznacza że preprocesor zwrócił taki sam wynik.
    Kod: Delphi
    Zaloguj się, aby zobaczyć kod


    Ewentualnie funkcja writeln zaokrągla wynik, bo np. nie może wyświetlić liczby z dokładnością do 10^-20, czy coś?

    Jak sprawdzić czy wynik działania "5*30/360" jest binarnie taki sam jak "5/360*30" bez rzutowania na zmienną.
  • #10 9884725
    Szymon Tarnowski
    Poziom 27  
    Posty: 1292
    Pomógł: 61
    Ocena: 181
    redie napisał:
    Operacje arytmetyczne na "stałych" które w kodzie zostały wpisane w postaci liczb (nie zmiennych) są wykonywane przez preprocesor, więc to on jest odpowiedzialny za błąd.
    Podpisze się pod tym obiema ręcyma, ale w tym przypadku wymiękam jakby to sprawdzić. Można by tylko jeszcze zerknąć w debugerze jaki kod jest generowany i czy w ogóle tam jest wykonywane jakieś porównanie arytmetyczne czy całość jest zoptymalizowana do true/false a co za tym idzie jedna z gałęzi tego warunku w ogóle usunięta. Mam jeszcze jedną sugestię, spróbuj różnych opcji kombinacji parametrów do optymalizacji kodu, to też może mieć na to wpływ.
  • #11 9884852
    redie
    Poziom 16  
    Posty: 169
    Pomógł: 25
    Ocena: 1
    Sprawdziłem opcje optymalizacji. Teraz zrobiłem jeszcze jeden test. Najpierw przypisałem do zmiennych wartości poszczególnych licz, a później wykonałem na nich operacje (jak poniżej) i wynik też jest błędny.

    Kod: Delphi
    Zaloguj się, aby zobaczyć kod

    Już mnie to zaczyna bawić :)
  • Pomocny post
    #12 9885172
    Szymon Tarnowski
    Poziom 27  
    Posty: 1292
    Pomógł: 61
    Ocena: 181
    A sprawdź jaki będzie wynik odejmowania tych dwóch prawie równych liczb, jeśli nie zero, to w takim razie to jest problem "standardowy" z liczbami zmiennoprzecinkowymi polegający na niejednoznaczności liczby i nieciągłości zbioru. Tak na szybko znalazłem taki tekst
    http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
  • #13 9886728
    Eagle
    Poziom 24  
    Posty: 536
    Pomógł: 57
    Ocena: 31
    Szymon trafnie ocenił. Sprawdź co jest pod adresem pamięci przechowującym zmienne

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    ten link pozwala rozkodować liczby w IEEE-754 wklej wartość hex bez 0x na początku i zobacz dlaczego jest różnica

    Eagle
  • #14 9903007
    redie
    Poziom 16  
    Posty: 169
    Pomógł: 25
    Ocena: 1
    do Eagle:
    U mnie wartości zmiennych są identycznie w postaci binarnej.

    do Szymona Tarnowskiego:
    Odjęcie tych wartości nie jest równe 0 (a powinno), więc tak jak napisałeś podchodzi to pod ten problem standardowy.
    Wynikiem odejmowania jest: 2,71050543121376E-20

    Pozostaje chyba tylko po prostu mieć to na uwadze podczas pisania kodu.
    Moje podsumowanie: trzeba najpierw wykonywać mnożenie a później dzielenie, bo przy dzieleniu powstaje liczba z ograniczoną dokładnością ;)

    Dzięki za dyskusję.
  • #15 9904689
    Eagle
    Poziom 24  
    Posty: 536
    Pomógł: 57
    Ocena: 31
    Skoro są równe to jakim cudem różnica jest różna od zera ?

    cóż może w C jest inaczej ;)

    Eagle
  • #16 9905425
    Konto nie istnieje
    Konto nie istnieje  

Podsumowanie tematu

LABEL_AI_GENERATED
W dyskusji poruszono problem różnic w porównywaniu liczb w Delphi 2007, gdzie warunki w instrukcji IF zwracają różne wyniki w zależności od tego, czy liczby są wpisane bezpośrednio, czy przypisane do zmiennych. Użytkownicy sugerowali, że może to być związane z rzutowaniem typów przez kompilator oraz z precyzją obliczeń zmiennoprzecinkowych. Wskazano na problemy z porównywaniem wartości zmiennoprzecinkowych, które mogą prowadzić do niejednoznaczności wyników. Użytkownicy testowali różne kombinacje operacji arytmetycznych oraz optymalizacji kodu, co potwierdziło, że kolejność działań ma znaczenie dla uzyskania poprawnych wyników. Ostatecznie, podkreślono, że przy porównywaniu liczb zmiennoprzecinkowych należy być ostrożnym z uwagi na ograniczenia precyzji.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA