Pascal, 32-bit-Longword, wieso kein Überlauf?

OP #6280117
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
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...
Ä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).
Moderator
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.
OP
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.
OP
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.
Moderator
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.
OP
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.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 6 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.