Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   floating point invalid operation: 10.1 vs. 10.2 (https://www.delphipraxis.net/195817-floating-point-invalid-operation-10-1-vs-10-2-a.html)

striderx 28. Mär 2018 16:09

Delphi-Version: 10.2 Tokyo

floating point invalid operation: 10.1 vs. 10.2
 
Der nachstehende Code läuft unter Delphi 10.1 ohne Problem, bei Delphi 10.2 kommt eine Exception (floating point invalid operation). Plattform ist jeweils Windows 32 Bit.

Delphi-Quellcode:
procedure TdlgMain.Test3;

var
  AWord:   Word;
  ADouble: Double;

begin
  AWord  := 64536;
  ADouble := SQRT(SQR(AWord) + SQR(AWord));
end;
???

Da ich den Source-Code von 10.1 nicht habe (Starter), kann ich nicht nachsehen, ob sich da etwas getan hat.

Uwe Raabe 28. Mär 2018 16:47

AW: floating point invalid operation: 10.1 vs. 10.2
 
Die Hilfe zu SQR() sagt:
Zitat:

Der Rückgabewert (das Quadrat) hat denselben Typ wie X und ist mit der Anweisung X*X identisch.
Das Quadrat passt aber nicht mehr in ein Word und erzeugt so einen internen Überlauf, der in einer negativen Zahl resultiert. Durch die Addition bleibt die Zahl negativ und das SQRT kracht natürlich.

Bei 10.1 gibt es da zwar keine Exception, aber das Ergebnis stimmt leider auch nicht: 64.536² + 64.536² = 8.329.790.592

Delphi-Quellcode:
var
  AWord: Word;
begin
  AWord := 64536;
  Writeln(SQR(AWord) + SQR(AWord)); // => 33920
end;

striderx 28. Mär 2018 17:25

AW: floating point invalid operation: 10.1 vs. 10.2
 
Hallo Uwe,

danke für die Erläuterung - das hatte ich mir schon gedacht.

Die Frage ist nur: Wie bekomme ich es vorerst hin, dass auch unter 10.2 keine Exception kommt? Und was hat sich denn zwischen 10.1 und 10.2 geändert?


Der Hintergund: Ich nutze das als eine Art Zufalls-Generator für einen Graphik-Effekt, den ich zufällig entdeckt habe. Das hat natürlich mit sauberer Programmierung überhaupt nichts zu tun, aber ich habe das bislang noch nicht anderweitig nachbauen können.

Delphi.Narium 28. Mär 2018 17:31

AW: floating point invalid operation: 10.1 vs. 10.2
 
Statt Word Cardinal nehmen oder einen Typen, der in der Lage ist, das Ergebnis aufzunehmen?

Oder ganz grausilig:
Delphi-Quellcode:
procedure TdlgMain.Test3;

var
  AWord: Word;
  ADouble: Double;
  ATemp: Double;

begin
  AWord := 64536;
  ATemp := SQR(AWord + 0.0); // Das Quadrat muss man nicht zweimal berechnen
                             // und + 0.0 macht aus dem Word 'nen Fließkommawert.
  ADouble := SQRT(ATemp + ATemp);
end;

striderx 28. Mär 2018 17:57

AW: floating point invalid operation: 10.1 vs. 10.2
 
So kommt keine Exception, aber der Wert von ADouble ist natürlich anders und der Effekt klappt nicht.

Um den Effekt nachzubauen, müsste ich verstehen, was genau passiert, wenn bei 10.1 keine Exception kommt - das tue ich derzeit noch nicht. Es kommen aber immer die selben 'falschen'/'richtigen' Werte raus.

Delphi.Narium 28. Mär 2018 18:17

AW: floating point invalid operation: 10.1 vs. 10.2
 
Dann berechne doch das Ergebnis einmal "zu Fuß" und vergleiche es mit dem Ergebnis ohne Exception. Stimmen die überein?

Wenn es so ist, wie Uwe es beschrieb, ist das Berechnungsergebnis, bei der Variante ohne Exception, schlicht und einfach falsch.

Oder anders:
Delphi-Quellcode:
var
  AWord: Word;
  AWord2: Word;
  ACardinal: Cardinal;
  ADouble1: Double;
  ADouble2: Double;
  ADouble3: Double;

begin
  AWord    := 64536;
  ACardinal := 64536;
  ADouble1  := 64536;
  AWord    := SQR(AWord);
  ACardinal := SQR(ACardinal);
  ADouble1  := SQR(ADouble1);

  ADouble1 := SQRT(ADouble1 + ADouble1);
  ADouble2 := SQRT(AWord + AWord);
  ADouble3 := SQRT(ACardinal + ACardinal);
  MessageDlg(Format('1. %f%s2. %f%s3.%f', ADouble1,#13,ADouble2,#13,ADouble3]),mtInformation,[mbOk],0);
end;
Wenn ich da jetzt nicht zuviele Schreib- und Denkfehler drinne haben sollte, so wären drei identische Ergebnisse identischer Berechnungen mit unterschiedlichen Datentypen zu erwarten.

Frage: Ist dem (bei der Variante ohne Exception) so?

gammatester 28. Mär 2018 19:18

AW: floating point invalid operation: 10.1 vs. 10.2
 
Zitat:

Zitat von striderx (Beitrag 1397480)
So kommt keine Exception, aber der Wert von ADouble ist natürlich anders und der Effekt klappt nicht.

Warum willst Du denn unbedingt den Effekt haben? Wenn Du den Soureccode ändern kannst, dann mach es doch gleich richtig: Erst die Zuweisung an die Double-Variable und die dann quadrieren. Aller andere ist buggy. (Was passiert eigentlich, wenn Du Overflow/Range-Check eingeschaltet hast?)

striderx 28. Mär 2018 22:44

AW: floating point invalid operation: 10.1 vs. 10.2
 
@Delphi.Narium

Danke für deine Mühe, aber das ist es leider noch nicht. Zwar bekomme ich bei dem nachstehenden Code keinen Floating Point Fehler mehr, dafür jetzt einen Integer-Überlauf.

Delphi-Quellcode:
var
  AWord:     Word;
  ADouble:   Double;
  ACardinal: Cardinal;

begin
  AWord    := 64536;
  ACardinal := SQR(AWord);
  ADouble  := SQRT(ACardinal + ACardinal);
end;
Unter 10.1 enthält ADouble den 184,17. Mathematisch korrekt wäre natürlich 91267,69


@gammatester
Warum ich den Effekt haben will? Weil man damit tolle Bilder erstellen kann. Die von dir vorgeschlagene Vorgehensweise bringt auch nicht das gewünschte Ergebnis. Das alles ist übrigens unabhängig davon, ob die Bereichs-Prüfung an oder ausgeschaltet ist.

himitsu 28. Mär 2018 23:07

AW: floating point invalid operation: 10.1 vs. 10.2
 
Delphi-Quellcode:
AWord := 64536;
ADouble1 := Sqrt(Cardinal(Sqr(Word(AWord))) * 2);
ADouble2 := Sqrt(Cardinal(Sqr(Integer(AWord))) * 2);
ADouble3 := Sqrt(Cardinal(Sqr(Cardinal(AWord))) * 2);
:?:

Uwe Raabe 28. Mär 2018 23:11

AW: floating point invalid operation: 10.1 vs. 10.2
 
Zitat:

Zitat von striderx (Beitrag 1397495)
Zwar bekomme ich bei dem nachstehenden Code keinen Floating Point Fehler mehr, dafür jetzt einen Integer-Überlauf.

Ich denke, du solltest AWord zu einem Cardinal machen. Das Quadrat eines Word passt immer in einen Cardinal, aber halt nicht immer in einen Integer oder gar ein Word. Da der Rückgabewert von SQR den gleichen Typ hat wie das Argument, muss das Argument schon ein Cardinal sein, bei dem das Hi-Word gleich 0 ist. Andernfalls bekommt man einen Integeroverflow.

Am sichersten fährst du, wenn AWord gleich als Double oder Extended deklariert wird.

Delphi-Quellcode:
var
  AWord: Double;
  ADouble: Double;

begin
  AWord := 64536;
  ADouble := SQRT(SQR(AWord) + SQR(AWord));
end;
Du kannst es dem Compiler aber auch leichter machen und es gleich so schreiben:

Delphi-Quellcode:
  AWord := 64536;
  ADouble := SQRT(2)*AWord;


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:13 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz