AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Überlauf bei Rechenoperation mitbekommen

Überlauf bei Rechenoperation mitbekommen

Ein Thema von Popov · begonnen am 4. Apr 2014 · letzter Beitrag vom 4. Apr 2014
Antwort Antwort
Popov
(Gast)

n/a Beiträge
 
#1

Überlauf bei Rechenoperation mitbekommen

  Alt 4. Apr 2014, 13:24
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?
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.017 Beiträge
 
Delphi 12 Athens
 
#2

AW: Überlauf bei Rechenoperation mitbekommen

  Alt 4. Apr 2014, 13:42
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
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Dejan Vu
(Gast)

n/a Beiträge
 
#3

AW: Überlauf bei Rechenoperation mitbekommen

  Alt 4. Apr 2014, 13:43
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.
  Mit Zitat antworten Zitat
gammatester

Registriert seit: 6. Dez 2005
999 Beiträge
 
#4

AW: Überlauf bei Rechenoperation mitbekommen

  Alt 4. Apr 2014, 13:47
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:
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;
Hinweise für einige Operationen bei http://www.hackersdelight.org/ oder http://graphics.stanford.edu/~seander/bithacks.html
  Mit Zitat antworten Zitat
Benutzerbild von Neutral General
Neutral General

Registriert seit: 16. Jan 2004
Ort: Bendorf
5.219 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#5

AW: Überlauf bei Rechenoperation mitbekommen

  Alt 4. Apr 2014, 13:55
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;
Michael
"Programmers talk about software development on weekends, vacations, and over meals not because they lack imagination,
but because their imagination reveals worlds that others cannot see."

Geändert von Neutral General ( 4. Apr 2014 um 13:59 Uhr)
  Mit Zitat antworten Zitat
Popov
(Gast)

n/a Beiträge
 
#6

AW: Überlauf bei Rechenoperation mitbekommen

  Alt 4. Apr 2014, 14:37
Was Du hier vorhast ist ja auch etwas merkwürdig.
Stimmt. Aber in dem speziellen Fall ist das "übliche" Verhalten gewollt (es ist ja auch die Standardeinstellung). Nur will ich es mitbekommen.

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:
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;
Es müssen zwei Funktionen sein, sonst klappt das nicht.

Geändert von Popov ( 4. Apr 2014 um 14:48 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.017 Beiträge
 
Delphi 12 Athens
 
#7

AW: Überlauf bei Rechenoperation mitbekommen

  Alt 4. Apr 2014, 15:46
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:
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;
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.
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;
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Popov
(Gast)

n/a Beiträge
 
#8

AW: Überlauf bei Rechenoperation mitbekommen

  Alt 4. Apr 2014, 22:51
Also ich weiß nicht wie das in höheren Delphi Versionen ist, aber
Delphi-Quellcode:
begin
  {$Q+}
  ...
  {$Q-}
end;
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.

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;
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:29 Uhr.
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