![]() |
Überlauf bei Rechenoperation mitbekommen
Ich hab folgendes Problem, ich möchte den Überlauf bei einer Integer Rechenoperation mitbekomme, allerdings ohne dass es eine Fehlermeldung gibt. Ich will es einfach nur wissen. Die Rechenoperation soll wie üblich fortgesetzt werden, mit dem falschen Ergebnis, ich will es nur wissen.
Eine Lösung habe ist, aber die gefällt mir nicht. Standard ist {$Q-}. Mit der Direktive {$Q+} kann ich die Überlaufprüfung einschalten, allerdings gibt es dann eine Fehlermeldung. Die kann ich mit EIntOverflow abfangen, allerdings wird die Rechnung nicht fortgeführt, aber das will ich. Eine Möglichkeit ist die Info zu kassieren und dann ein weiteres Mal, dieses mit {$Q-} zu rechnen. Aber so blöd ist der Compiler nicht. Der sagt sich - der Typ weiß nicht was er will - und ignoriert eine von beiden Routinen. Man kann anscheinend in einer Prozedur nicht gleichzeitig {$Q+} und {$Q-} nutzen. Also muss eine der Routinen ausgelagert werden. Und spätestens hier wird aus eine Vierzeilener ein Zwanzigzeiler. Gibt es eine Möglichkeit bei {$Q-} nach einer Rechnung mitzubekommen ob es einen Überlauf gab? |
AW: Überlauf bei Rechenoperation mitbekommen
Ich wüsste jetzt nichts, außer Try-Except und im Except nochmals berechnen, ohne Überlaufprüfung.
Delphi-Quellcode:
// A := B * C; mit {$Q-}
mov eax,[ebp-$14] imul dword ptr [ebp-$18] mov [ebp-$10],eax //A := B * C; mit {$Q+} mov eax,[ebp-$14] imul dword ptr [ebp-$18] jno $0dde2376 call $0dd71098 mov [ebp-$10],eax |
AW: Überlauf bei Rechenoperation mitbekommen
Natürlich: Die Operation einfach mit Int64 Werten ausprobieren.
Mein Tipp: Mach aus dem 4-Zeiler einen 20-Zeiler, denn mehr Zeilen heißt nicht gleich 'weniger Übersichtlich'. Was Du hier vorhast ist ja auch etwas merkwürdig. Übrigens wird der 'Trick' mti den Int64-Werten bei der 'MulDiv' Funktion verwendet. Hier wird a*b div c gerechnet, aber so, das ein Überlauf (bei a*b) vermieden wird. |
AW: Überlauf bei Rechenoperation mitbekommen
Das hängt von den verwendeten Operationen und Datentypen ab. Ohne ASM ist es im allgemeinen schwierig. Ich verwende zB für den für mich interessanten Fall der Überlauferkennung bei signed 32-Bit-Addition:
Delphi-Quellcode:
Hinweise für einige Operationen bei
function add32_ovr(x,y: longint; var z: longint): boolean;
{-Add z=x+y with overflow detection} begin {See Hacker's delight, Ch 2-12} {$ifopt Q+} z := longint(int64(x)+y); {$else} z := x+y; {$endif} add32_ovr := ((z xor x) and (z xor y)) < 0; end; ![]() ![]() |
AW: Überlauf bei Rechenoperation mitbekommen
Was bei mir zumindest für Integer Operationen funktioniert ist folgendes:
Delphi-Quellcode:
function OverflowHappend(): Boolean;
asm jno @no_overflow mov eax, 1 ret @no_overflow: xor eax, eax end; procedure TForm1.Button1Click(Sender: TObject); var n: Integer; begin n := MaxInt; n := n + 40; if OverflowHappend then ShowMessage('Overflow'); Caption := IntToStr(n); // Damit Delphi da nichts wegoptimiert end; |
AW: Überlauf bei Rechenoperation mitbekommen
Zitat:
Das mit einem Int64 (bzw. allgemein größeren Zahl) ist es auch möglich (man prüft mit if ob Max überschritten wurde), ich hatte aber fixe Idee die Rechnung normal auszuführen und die Info vom System zu erhalten. Das "Problem" ist, dass das eigentlich einfach zu lösen ist, also ein paar Dummy-Variablen usw. Nur so dumm ist der Compiler nicht. Wenn er er glaubt, dass eine Rechnung nicht nötig ist, und prüfen auf Error ist eigentlich unsinnig, dann ignoriert er die Routine. //EDIT: Also das kürzeste was ich hin bekomme (hier im Beispiel mit Byte) ist das:
Delphi-Quellcode:
Es müssen zwei Funktionen sein, sonst klappt das nicht.
function IncByte(var X: Byte; N: Byte = 1): Boolean;
function IncTest: Boolean; begin Result := False; {$OverFlowChecks On} try Inc(X, N); except on EIntOverflow do Result := True; end; end; var X2: Byte; begin X2 := X; Result := IncTest; {$OverFlowChecks Off} if Result then begin X := X2; Inc(X, N); end; end; |
AW: Überlauf bei Rechenoperation mitbekommen
Wieso klappt das denn nicht?
$Q, bzw. $OverFlowChecks sollte nur auf Zeilenebene gültig sein, alss nur bis zur nächsten Definition, oder bis Dateiende, falls nichts mehr kommt. Bei INC muß man etwas aufpassen ... siehe Beschreibung vom letzten Beispiel und darum hier auch die Tempvariable.
Delphi-Quellcode:
function IncByte(var X: Byte; N: Byte = 1): Boolean;
var X2: Byte; begin X2 := X; try {$OverFlowChecks On} Inc(X, N); {$OverFlowChecks Off} // entweder das Result := True; except on EIntOverflow do begin X := X2; {$OverFlowChecks Off} // oder das .... das wo, sollte nahezu egal sein Inc(X, N); Result := False; end; end; end; Wenn es vor dem Zuweisen knallt, dann geht das auch ohne zusätzliche Variable.
Delphi-Quellcode:
Wenn INC direkt im Ziel-Speicher rechnet, dann ist auch mit Exception dennoch das Ergebnis bereits in der Variable und muß nicht nochmal berechnet werden.
function IncByte(var X: Byte; N: Byte = 1): Boolean;
begin try {$OverFlowChecks On} X := X + N; Result := True; except on EIntOverflow do begin {$OverFlowChecks Off} Inc(X, N); Result := False; end; end; end;
Delphi-Quellcode:
function IncByte(var X: Byte; N: Byte = 1): Boolean;
begin try {$OverFlowChecks On} Inc(X, N); {$OverFlowChecks Off} Result := True; except on EIntOverflow do Result := False; end; end; |
AW: Überlauf bei Rechenoperation mitbekommen
Also ich weiß nicht wie das in höheren Delphi Versionen ist, aber
Delphi-Quellcode:
beide Direktiven in einer Funktion klappt nicht bei mir. Wenn am Ende {$Q-} steht, hat bei mir {$Q+} am Anfang keine Wirkung. Es gibt bei mir keine Fehlermeldung.
begin
{$Q+} ... {$Q-} end; Was bleib ist es auf zwei Funktionen zu verteilen:
Delphi-Quellcode:
function IncByte(var X: Byte; N: Byte = 1): Boolean;
procedure IncTest; begin {$OverFlowChecks On} Inc(X, N); end; var X2: Byte; begin X2 := X; try IncTest; {$OverFlowChecks Off} Result := False; except on EIntOverflow do begin {$OverFlowChecks Off} X := X2; Inc(X, N); Result := True; end; end; end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:14 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz