Wynik funkcji Int(13/1.3)<>10 - dlaczego ?

0

Witam.

Prosiłbym o wyjaśnienie czemu taki kod:

 procedure TForm1.FormShow(Sender: TObject);
var
  o,i : real;
  test:string;
begin
           i := 13;
           o := 1.3;

           test:=test+#13#10+ 'i= '         +FloatToStr(i);
           test:=test+#13#10+ 'o= '         +FloatToStr(o);
           test:=test+#13#10+ 'i/o= '       +FloatToStr(i/o);
           test:=test+#13#10+ 'Int(i/o)= '  +FloatToStr(Int(i/o));
           test:=test+#13#10+ 'Int(13/1.3)='+FloatToStr(Int(13/1.3));

           Memo1.Lines.Add(test)  ;

end;     

Daje taki wynik :

i= 13
o= 1,3
i/o= 10
Int(i/o)= 9
Int(13/1.3)=10

Chodzi mi szczególnie o wiersz zawierający : Int(i/o)= 9. Skoro i=13, o=1,3 to Int(i/o) (czyli Int(13/1.3)) powinno dać chyba 10 ?

Z góry dziękuję za pomoc.

1

Jeszcze dodaj:

if  o<>1.3 then test:=test+#13#10'To powinno wszystko wyjaśnić';

Nie spodziewaj się po real żadnej dokładności.
1.3 - w liczbach zmiennoprzecinkowych zawsze będzie zapisywana w przybliżeniu, mniej więcej tak jak 1/3 nie da rady zapisać w skończonej ilości pozycji dziesiętnych.

0

Spodziewałem się że chodzi o jakieś zaokrąglenia lecz zdziwiło mnie to, że i/o= 10 a Int(i/o)=9.
Jak w takim razie rozwiązać tego typu problem ?

Dla testu zmieniłem Real na Single - wynik poprawny...

W niektórych przypadkach poprawny w innych nie ...

1

Zamień na Extended;
Nigdy nie porównuj wartości zmiennoprzecinkowych za pomocą = co najwyżej: if abs(i/o-10)<Epsilon then gdzie Epsilon mała liczba np 1E-8

0

@hipekk - dlatego że liczby zmiennoprzeciskowe nie są aż tak dokładne żeby porównywać je przez standardowy operator porównania = wymyślnono zestaw funkcji CompareValue znajdujących się w module Math, które porównują dwie wartości (nie tylko zmiennoprzecinkowe) na podstawie ustalonej, bardzo małej Delty; Więc aby mieć możliwość porównania dwóch liczb zmiennoprzecinkowych z jakąś malutką dokładnością musisz skorzystać z tej funkcji;

Źródło funkcji CompareValue ze źródeł Lazarusa:

function CompareValue (const A, B: Extended; delta: Extended = 0.0): TValueRelationship;
begin
  result:=GreaterThanValue;
  if abs(a-b)<=delta then
    result:=EqualsValue
  else
   if a<b then
     result:=LessThanValue;
end;

Jak widać działa to na takiej zasadzie, jaką podał @_13th_Dragon, tyle że obudowane jest w funkcję i pozwala na podanie dowolnej Delty w parametrze; Funkcja zwraca wartość typu TValueRelationship, który to zadeklarowany jest w module Math:

type
  TValueRelationship = -1..1;

const
  EqualsValue = 0;
  LessThanValue = Low(TValueRelationship);
  GreaterThanValue = High(TValueRelationship);

Tak więc polecam najpierw szukać informacji w sieci zanim założy się wątek na forum, a także zainteresowanie się źródłami modułów Lazarusa; Aby przejść do deklaracji stałej, typu, klasy, funkcji itd. wystarczy przytrzymać klawisz Ctrl i kliknąć na nazwę tego elementu, a zostanie otwarty moduł z jego deklaracją (pod warunkiem, że moduł ten jest dodany do sekcji uses w programie); A jeśli potrzeba przeglądnąć kod jakiejś metody, to tak samo Ctrl + LPM, z tym że kursor zostanie ustawiony na deklaracji metody w klasie i aby przejść do jej definicji należy wcisnąć kombinację Shift+Ctrl+Down; Nie zawsze metody danej klasy są zadeklarowane w tym samym module, co klasa.

1 użytkowników online, w tym zalogowanych: 0, gości: 1