Forum: PC-Programmierung Pascal, 32-bit-Longword, wieso kein Überlauf?


von Peter B. (olduri)


Lesenswert?

Hallo allerseits,

Bei ein paar Zahlenspielerein mit FP fiel mir auf, dass ein 32-bit-Wert 
anscheinend trotz Überlauf korrekt berechnet wurde. Die Addition von 2 
** 31 + 2 ** 31 sollte doch bereits einen Überlauf erzeugen? Ich hätte 
zwar eine Idee, warum, möchte aber trotzdem die Frage in den Raum 
stellen - vielleicht interessiert sie noch jemanden. (Vielleicht ist die 
Antwort auch zu trivial, keine Ahnung)
1
function Pwert (ba, exp : LongWord) : LongWord; // natürliche Zahlen potenzieren
2
var i : word;
3
begin
4
Pwert := 1;
5
for i := 1 to exp do
6
  Pwert := Pwert * ba;
7
end;
8
9
begin
10
writeln ('MaxZahl für LongWord ...........: 4294967295'); //Maximalwert
11
writeln ('Pwert (2, 32) ..................: ', 
12
          Pwert (2, 32));                                 // Überlauf, 0
13
writeln ('Pwert (2, 31) + Pwert (2, 31) -1: ', 
14
      Pwert (2, 31) + Pwert (2, 31) -1);      // geht wieso?
15
writeln ('Pwert (2, 31) -1 + Pwert (2, 31): ', 
16
          Pwert (2, 31) -1 + Pwert (2, 31));              // so wärs korrekt
17
18
----------------------
19
Ergebnissse:
20
21
MaxZahl für LongWord ...........: 4294967295
22
Pwert (2, 32) ..................: 0
23
Pwert (2, 31) + Pwert (2, 31) -1: 4294967295
24
Pwert (2, 31) -1 + Pwert (2, 31): 4294967295

MfG, OldUri

von (prx) A. K. (prx)


Lesenswert?

Welche Folgen sollte ein Überlauf denn deiner Ansicht nach haben?

Wenn du Pech hast, dann rechnet der Compiler den ganzen Kram ausserdem 
schon selbst aus.

von Mathias A. (mrdelphi)


Lesenswert?

Anscheinend wird in beiden Fällen erst die Subtraktion von 1 
durchgeführt, vor der Addition des zweiten Funktionsergebnisses.

Pascal ist lange her bei mir, ist da etwas definiert bzgl Reihenfolge in 
der solche Rechnungen durchgeführt werden? Oder ist es dem Compiler 
überlassen? Wenn letzteres, könnte sich das Ergebnis evtl bei anderen 
Optimierungen auch unterscheiden...

von Mathias A. (mrdelphi)


Lesenswert?

Äh ne Quatsch...nehme es zurück und behaupte das Gegenteil ^^

Die Reihenfolge ist tatsächlich doch egal, da auch wenn zuerst addiert 
wird -- also Zwischenergebnis 0, wegen Überlauf -- die anschließende 
Subtraktion der 1 zum angezeigten Resultat führt (LongWord ist ja 
unsigned).

von Dirk B. (dirkb2)


Lesenswert?

Lass das -1 weg oder schreib es überall hin.

Bei Words sollte 0-1 MaxWord sein.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Der Prozessor rechnet modulo 2**n, wobei n die Datenwortbreite ist, im
vorliegenden Fall also 32. Damit entsprechen die Ergebnisse voll den
Erwartungen.

Mit {$R+} {$Q+} kannst du die Laufzeitprüfung von Overflows aktivieren.

von Peter B. (olduri)


Lesenswert?

A. K. schrieb:
> rechnet der Compiler den ganzen Kram außerdem
> schon selbst aus

Klar, aber sollte er dann nicht genauso rechnen wie das Compilat?

Mathias A. schrieb:
> die anschließende
> Subtraktion der 1 zum angezeigten Resultat führt

Ok, das wars. Danke.
1
Writeln (Longword (0-1));
 ergibt den gleichen Wert 2^32-1, und es ist eigentlich egal, ob es der 
Compiler oder erst zu Laufzeit gerechnet wird. Will noch mal schauen, 
wie ich den Range-Check einschalte, wahrscheinlich $R+ oder so ähnlich.

Hatte noch in eine andere Richtung gedacht, nämlich dass in einer 
halbwegs modernen 64er CPU sowieso mit voller Breite gerechnet wird, und 
das Ergebnis erst nachher beschnippelt wird.

mfG, OldUri

p.s. Hat sich mit der Antwort überschnitten - danke.

: Bearbeitet durch User
von Peter B. (olduri)


Lesenswert?

Ich nochmal:
Also mit $R+ fliegt er zur Laufzeit mit 2 ^ 32 raus, die anderen 
einschließlich 0 - 1 werden bearbeitet. Auch wenn dass Zwischenergebnis 
zu groß sein sollte.

Weiterhin skurril:
Writeln (Longword (0-1));
// writeln (Pwert (2, 32));
Writeln (Longword (Pwert (2, 31) + Pwert (2, 31)));
Der auskommentierte Bef. fliegt mit Runtimeerror, die anderen nicht. 
Passiert dann vermutlich in der selbstgebastelten Funktion.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Hab nochmal nachgeschaut:

Free Pascal führt auf einem 64-Bit-System sämtliche Integer-Berechnungen
mit 64 Bit durch. Deswegen gibt es in dem Beispiel überhaupt keine
Overflows, sondern lediglich Range-Errors. Diese entstehen u.a. bei
Zuweisungen, wenn der zugewiesene Wert außerhalb des Wertebereichs der
Zielvariablen liegt. Das Hauptprogramm enthält keine Zuweisungen oder
sonstige Anweisungen, die einen Range-Error auslösen könnten, deswegen
läuft dort alles glatt. Einen Range-Error kann es nur in Pwert geben,
nämlich dann, wenn die Operanden zu groß sind. Das ist aber nur im
ersten Aufruf (Pwert(2, 32) der Fall, deswegen wird auch nur dort eine
Fehlermeldung ausgegeben.

von Peter B. (olduri)


Lesenswert?

Ok, dann war meine Vermutung oben, dass in einer "64er CPU sowieso mit 
voller Breite gerechnet wird" doch gar nicht so falsch - Nochmals danke, 
für mich ist das Thema jetzt abgefrühstückt.

Schönen Tag noch - Peter B.

von (prx) A. K. (prx)


Lesenswert?

Peter B. schrieb:
> Klar, aber sollte er dann nicht genauso rechnen wie das Compilat?

Das muss er nur innerhalb der Sprachdefinition. Was darin offengelassen 
ist, kann sich zwischen Compiler und Laufzeit im Verhalten 
unterscheiden.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.