大整数加法

来源:互联网 发布:手机淘宝怎么添加客服 编辑:程序博客网 时间:2024/05/02 02:21

改自FGInt单元,将原来的

TGInt = Record
      Sign : TSign;
      Number : Array Of Int64;
定义做了修改.又用汇编做了部分优化,效率提升应该在40%左右.


Unit FBigInt;

Interface

Uses Windows, SysUtils, Controls, Math;

Type
   TCompare = (Lt, St, Eq, Er);
   TSign = (negative, positive);
   TBInt = Record
      Sign : TSign;
      Number : Array Of Longword;
   End;

   Function FBIntNew(Size:int64):TBInt;
   Procedure FBIntDestroy(Var FBInt : TBInt);
   Function FBIntAdd(Const FBInt1, FBInt2 : TBInt):TBInt;
   Function FBIntCompareAbs(Const FBInt1, FBInt2 : TBInt) : TCompare;
Implementation

{$H+}
Function FBIntNew(Size:int64):TBInt;
begin
  SetLength(Result.Number,Size);
  ZeroMemory(Result.Number,Size*8);
  Result.Number[0]:=Size-1;
  Result.Sign:=positive;
end;

Procedure FBIntDestroy(Var FBInt : TBInt);
Begin
   FBInt.Number := Nil;
End;

Function FBIntAdd(Const FBInt1, FBInt2 : TBInt):TBInt;
Var
   i, size1, size2, size : longint;
   rest : integer;
   Trest : int64;
Begin
  If FBInt1.Number[0] < FBInt2.Number[0] Then Result:=FBIntAdd(FBInt2, FBInt1) Else
  Begin
    If FBInt1.Sign = FBInt2.Sign Then
    Begin
      SetLength(Result.Number, FBInt1.Number[0] + 2);
      //rest := 0;
      asm
        clc
        mov eax,[esi+$04]
        mov ebp,[eax]
        test ebp,ebp
        jle @LoopOneEnd
        mov ecx,$00000001
        @LoopOne:
        mov eax,[ebx+$04]
        mov eax,[eax+ecx*4]
        mov edx,[esi+$04]
        adc eax,[edx+ecx*4]
        mov edx,[edi+$04]
        mov [edx+ecx*4],eax
        inc ecx
        dec ebp
        jnz @LoopOne
        @LoopOneEnd:
        pushf
        mov eax,[esi+$04]
        mov ebp,[eax]
        mov eax,[ebx+$04]
        sub ebp,[eax]
        popf
        test ebp,ebp
        jle @LoopOneEnd
        jnc @looptwoend
        mov eax,[ebx+$04]
        mov eax,[eax+ecx*4]
        adc eax,$0
        dec ebp
        jnz @LoopOneEnd
        @looptwoend:
      end;
      size := FBInt1.Number[0]+1;
//      For i := 1 To FBInt2.Number[0] Do
//      Begin
//        Trest := FBInt1.Number[i] + FBInt2.Number[i] + rest;
//        Result.Number[i] := Trest And 4294967295;
//        rest := Trest Shr 32;
//      End;
//      For i := (FBInt2.Number[0] + 1) To FBInt1.Number[0] Do
//      Begin
//        Trest := FBInt1.Number[i] + rest;
//        Result.Number[i] := Trest And 4294967295;
//        rest := Trest Shr 32;
//      End;
//      size := FBInt1.Number[0]+1;
//      Result.Number[size] := rest;
      While (Result.Number[size] = 0) And (size > 1) Do size := size - 1;
      If size <= FBInt1.Number[0] Then SetLength(Result.Number , size + 1);
      Result.Number[0] := size ;
      Result.Sign := FBInt1.Sign;
    End
    Else
    Begin
      If FBIntCompareAbs(FBInt2, FBInt1) = Lt Then Result:=FBIntAdd(FBInt2, FBInt1)
      Else
      Begin
        SetLength(Result.Number, FBInt1.Number[0] + 1);
        rest := 0;
        asm
          clc
          mov eax,[esi+$04]
          mov ebp,[eax]
          test ebp,ebp
          jle @LoopOneEnd
          mov ecx,$00000001
          @LoopOne:
          mov eax,[ebx+$04]
          mov eax,[eax+ecx*4]
          mov edx,[esi+$04]
          SBB eax,[edx+ecx*4]
          mov edx,[edi+$04]
          mov [edx+ecx*4],eax
          inc ecx
          dec ebp
          jnz @LoopOne
          @LoopOneEnd:
          pushf
          mov eax,[esi+$04]
          mov ebp,[eax]
          mov eax,[ebx+$04]
          sub ebp,[eax]
          popf
          test ebp,ebp
          jle @LoopOneEnd
          jnc @looptwoend
          mov eax,[ebx+$04]
          mov eax,[eax+ecx*4]
          SBB eax,$0
          dec ebp
          jnz @LoopOneEnd
          @looptwoend:
        end;
//        For i := 1 To FBInt2.Number[0] Do
//        Begin
//          Trest := FBInt1.Number[i] - FBInt2.Number[i] + rest;
//          Result.Number[i] := Trest And 4294967295;
//          If (FBInt1.Number[i] > FBInt2.Number[i]) Then rest := 0 Else rest := -1;
//        End;
//        For i := (FBInt2.Number[0] + 1) To FBInt1.Number[0] Do
//        Begin
//          Trest := FBInt1.Number[i] + rest;
//          Result.Number[i] := Trest And 4294967295;
//          If (FBInt1.Number[i] > FBInt2.Number[i]) Then rest := 0 Else rest := -1;
//        End;
        size := FBInt1.Number[0];
        While (Result.Number[size] = 0) And (size > 1) Do size := size - 1;
        If size <= FBInt1.Number[0] Then SetLength(Result.Number , size + 1);
        Result.Number[0] := size ;
        Result.Sign := FBInt1.Sign;
      End;
    End;
  End;
end;

// Compare 2 FBInts in absolute value, returns
// Lt if FBInt1 > FBInt2, St if FBInt1 < FBInt2, Eq if FBInt1 = FBInt2,
// Er otherwise

Function FBIntCompareAbs(Const FBInt1, FBInt2 : TBInt) : TCompare;
Var
   size1, size2, i : longint;
Begin
   FBIntCompareAbs := Er;
   size1 := FBInt1.Number[0];
   size2 := FBInt2.Number[0];
   If size1 > size2 Then FBIntCompareAbs := Lt Else
      If size1 < size2 Then FBIntCompareAbs := St Else
      Begin
         i := size2;
         While (FBInt1.Number[i] = FBInt2.Number[i]) And (i > 1) Do i := i - 1;
         If FBInt1.Number[i] = FBInt2.Number[i] Then FBIntCompareAbs := Eq Else
            If FBInt1.Number[i] < FBInt2.Number[i] Then FBIntCompareAbs := St Else
               If FBInt1.Number[i] > FBInt2.Number[i] Then FBIntCompareAbs := Lt;
      End;
End;
End.

原创粉丝点击