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)
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.
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).
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.
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.
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.
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.
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.
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.