Einzelnen Beitrag anzeigen

Benutzerbild von himitsu
himitsu

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

Überlauf bei Berechnung erkennen

  Alt 22. Mai 2008, 20:55
N'aben ihr,

wie ihr vielleicht bemerkt habt, arbeite ich grad an 'ner (anfangs) kleinen BigInt-Implementation.

Und obwohl erstmal (hoffentlich) richtig gerechnet wird,
hab ich Probleme einen Integerüberlauf ( {$R+} ) zu erkennen ... ich seh einfach den Wald vor lauter Bäumen nicht mehr

hier mal einige Werte und deren Ergebnisse:
Code:
.                       # OverflowValue

*10000 +    100 = 10100 # $00000000
-10000 +    100 = -9900 # $00000000
-10000 +   -100 = -10100 # $00000001
*10000 +   -100 =  9900 # $00000001
*10000 +  20000 = 30000 # $00000000
*10000 + -20000 = -10000 # $00000000
-10000 + -20000 = -30000 # $00000001
-10000 +  20000 = 10000 # $00000001

*10000 -    100 =  9900 # $00000000
-10000 -    100 = -10100 # $00000000
-10000 -   -100 = -9900 # $ffffffff
*10000 -   -100 = 10100 # $ffffffff
*10000 -  20000 = -10000 # $ffffffff
*10000 - -20000 = 30000 # $ffffffff
-10000 - -20000 = 10000 # $00000000
-10000 -  20000 = -30000 # $00000000

//     MinBigInt = -67...03042048
//     MaxBigInt = 67...03042047

MinBigInt +  100 = -67...03041948 # $00000000
MaxBigInt + -100 = 67...03041947 # $00000001
MinBigInt - -100 = -67...03041948 # $ffffffff
MaxBigInt -  100 = 67...03041947 # $00000000

// reIntOverflow
MinBigInt + -100 = 67...03041948 # $00000001
MaxBigInt +  100 = -67...03041949 # $00000000
MinBigInt -  100 = 67...03041948 # $00000000
MaxBigInt - -100 = -67...03041949 # $ffffffff
Welche Werte ich nach der Berechnung noch zur Verfügung hab:
Code:
X +/- Y = Z
Sign(X), Y, Z und OverflowValue
und natürlich auch Sign(Y) und Sign(Z)

da ich direkt mit X rechne, geht dieses verloren und ich würde gern verhindern dieses extra zu speichern


ich hatte zwar schon versucht etwas zusammenzubekommen
und bei einer Berechnung ohne Überlauf stimmte es inzwischen auch,
allerdings liefert B auch bei einem Überlauf true (also speziell bei den letzten 4 Berechnungen)
Delphi-Quellcode:
// für Addition
B := X.isNegaive;
// Berechnung ... Z := X + Y;
B := not (((B = Z.isNegaive) and (B = Y.isNegaive))
  or ((Z.isNegaive <> Y.isNegaive) and (Abs(Z) > Abs(Y)))
  or ((Z.isNegaive = Y.isNegaive) and (Abs(Z) < Abs(Y))));
If B Then Integer_Overflow;


// für Subtraktion
B := X.isNegaive;
// Berechnung ... Z := X - Y;
B := not (((B = Z.isNegaive) and (B <> Y.isNegaive))
  or ((Z.isNegaive = Y.isNegaive) and (Abs(Z) > Abs(Y)))
  or ((Z.isNegaive <> Y.isNegaive) and (Abs(Z) < Abs(Y))));
meine Addition sieht aktuell etwa so aus
werd' es demnächst auf von Pascal mit 64 Bit auf ASM mit 32 Bit und ADC(SBB) umstellen, wo ich im Carry zumindestens den interen den Überlauf drin hab ... mal sehn wie es nach dem letzen Wert (High Byte) aussieht,
aber auch so (in Pascal) sollte es doch zum Funktionieren bekommen?

Delphi-Quellcode:
Procedure TBigInt._Add(Const i: TBigInt);
  Var B: Boolean;
    i2: LongInt;
    T: TLargeWordRec;

  Begin
    B := LongInt(Data[High(Data)]) < 0;
    i2 := 0;
    T.Hi := 0;
    Repeat
      T.Org := LargeWord(Data[i2]) + i.Data[i2] + T.Hi;
      Data[i2] := T.Lo;
      Inc(i2);
    Until i2 = Length(Data);
      B := not (((B = (LongInt(Data[High(Data)]) < 0)) and (B = (LongInt(i.Data[High(Data)]) < 0)))
        or (((Data[High(Data)] and $80000000) <> (i.Data[High(Data)] and $80000000)) and (Abs(Self) > Abs(i)))
        or (((Data[High(Data)] and $80000000) = (i.Data[High(Data)] and $80000000)) and (Abs(Self) < Abs(i))));
      {$IFOPT R+} If B Then Error(reIntOverflow) {$ENDIF};
    End;
$2B or not $2B
  Mit Zitat antworten Zitat