Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

BigInteger-Calculation with AHK


  • Please log in to reply
1 reply to this topic
Rubberduck
  • Members
  • 97 posts
  • Last active: Jul 30 2005 12:17 AM
  • Joined: 24 Apr 2005
I have written such a thing a few years ago with Delphi
and thought it might be funny to do it with AHK.
You can now add, subtract and multiply positive or negative
Integers with hunderts of digits

Here the code:
#SingleInstance force 
Gui, Add, Text, x10 y30 w51 h15, BigNum 1:
Gui, Add, Button, x65 y24 w25 h25 gPM1, +/-
Gui, Add, Edit, vLong1 r2 Number -WantReturn x96 y20 w350 h46,63562623
Gui, Add, Button, x96 y60 w55 h23, &Swap
Gui, Add, Button, x155 y60 w55 h23, &Compare
Gui, Add, Button, x214 y60 w55 h23, B1 + B2
Gui, Add, Button, x273 y60 w55 h23, B1 - B2
Gui, Add, Button, x332 y60 w55 h23, B1 * B2
Gui, Add, Button, x391 y60 w55 h23, B1 / B2
Gui, Add, Text, x10 y101 w51 h15, BigNum 2:
Gui, Add, Button, x65 y94 w25 h25 gPM2, +/-
Gui, Add, Edit, vLong2 r2 Number -WantReturn x96 y90 w350 h42,6355334
Gui, Add, Text, x96 y130 w350 h35, 
(
Type in some large Integers (positive or negative) and test it
)
Gui, Add, Text, x10 y160 w51 h15, Result:
Gui, Add, Edit, VResultEdit readonly x96 y160 w350 h107, 
Gui, Show, x270 y110 h277 w477, BigInteger-Package by Rubberduck

Esc::exitApp
return

;**************************************************************************
;****** Internal Help-functions
;**************************************************************************
;//returns the maximum of x and y
Max(x,y) 
{ 
   IfLess x,%y%, Return y 
   Return x 
} 

;//simplyfies the use of Transform
Mod(In_Dividend,In_Divisor)
{
   Transform, Ret_Val, Mod, %In_Dividend%, %In_Divisor%
   return Ret_Val  
}

;//simplyfies the use of Transform
Div(In_Dividend,In_Divisor)
{
   Transform, Ret_Val, Floor, In_Dividend/In_Divisor
   return, Ret_Val
}

;//Also usefull for any AHK-script. Swap the values of two variables
Swap_Values(Byref val1, ByRef Val2)
{
   local dummy
   dummy:=val1
   val1:=val2
   val2:=dummy
}

;//Is removing leading zeros from an LongInt String. If the String holds
;//an leading Minus it is kept -0000123 => -123 and 00985 => 985
RemoveLeadingZeros(ByRef LongIntString)
{
  local LCh, ZCh, WS
  WS=%LongIntString%
  StringLeft, LCh, WS, 1 
  if (LCh="-")
    StringTrimLeft,WS,WS,1
  loop
  {
    StringLeft, ZCh,WS,1 
    if (ZCh="0")
      StringTrimLeft,WS,WS,1
    else
      break  
  }
  If (WS="")   ;//If it is empty now make it 0
    WS=0
  if (LCh="-") ;//Add minus again if there was one
    WS=-%WS%
  LongIntString=%WS% ;//returns result BYREF !!!!
}

;//This function is comparing IntegerStrings (also WITH leading Minus)
;//Leading Zeros are removed by default to make comparison possible
;//If First  is smaller than Second -1 is returned
;//If First and Second are equal 0 is returned
;//If First is  bigger than Second  1 is returned
;//If one of the Strings is empty it is assumed to be 0
CompareLongIntStrings(ByRef FirstLongString,Byref SecondLongString,ShowMessage)
{
  local FSize, FCh, SSize, SCh, Output, Ret_Val
  RemoveLeadingZeros(FirstLongString)
  RemoveLeadingZeros(SecondLongString)
  StringLen, FSize, FirstLongString
  StringLen, SSize, SecondLongString
  StringLeft, FCh, FirstLongString, 1 
  StringLeft, SCh, SecondLongString, 1 
  if (FCh="-")and(SCh<>"-")
     Ret_Val=-1
  else   
  if (SCh="-")and(FCh<>"-")
     Ret_Val=1
  else   
  {
    if (FSize>SSize)
    {
      if (FCh="-")and(SCh="-") 
         Ret_Val=-1
      else
         Ret_Val=1
    }
    else
    if (SSize>FSize)
    {
      if (FCh="-")and(SCh="-") 
         Ret_Val=1
      else
         Ret_Val=-1
    }
    else
    if (SSize=FSize)
    {
      Ret_Val=0 ;//assume we find no difference
      loop, %SSize%
      {
        StringMid, Dig1, FirstLongString, %A_index%, 1 
        StringMid, Dig2, SecondLongString, %A_index%, 1 
        if (Dig1<>Dig2)  ;//Found a different digit
        {
          if (Dig1>Dig2)
          {
            If (FCh="-")and(SCh="-")
               Ret_Val=-1
            else
               Ret_Val=1
            break   
          }     
          else
          if (Dig2>Dig1)
          {
            If (FCh="-")and(SCh="-")
               Ret_Val=1
            else
               Ret_Val=-1
            break   
          }     
        }
      } 
    }
  }
  if (ShowMessage=1) 
  {
    if (Ret_Val=-1)
      OutPut=BigNum 1 is smaller than BigNum 2  
    else
    if (Ret_Val=1)
      OutPut=BigNum 1 is bigger than BigNum 2  
    else
      OutPut=Both BigNum's are equal
    GuiControl,, ResultEdit, %OutPut%
  } 
  return, Ret_Val 
}

;//Returns 1 if LongIntString has a leading Minus else returns 0
IsNeg(LongIntString)
{
  local MCh
  StringLeft, MCh,LongIntString,1 
  if (MCh="-")
    return, 1
  else  
    return, 0  
}

;//Returns a LongIntString with removed Minus, what 
;//simply means it returns an ABS'd LongIntString
ABSLongintString(LongIntString)
{
  local MCh
  StringLeft, MCh, LongIntString, 1 
  if (MCh="-")
  {
    StringTrimLeft,LongIntString,LongIntString,1
    return %LongIntString%
  } 
  else
    return %LongIntString%
}

;//Is adding leading zeros to the strings so they have same length
;//leading Minus is kept. We add 3 reserve-zeros
MakeFitLength(ByRef FirstLongString,Byref SecondLongString)
{
   local LS1Size, LS2Size, FCh, SCh, Maxi, L1Diff, L2Diff
   RemoveLeadingZeros(FirstLongString)
   RemoveLeadingZeros(SecondLongString)
   StringLeft, FCh, FirstLongString, 1 
   StringLeft, SCh, SecondLongString, 1 
   ;//remove minus first if there are one
   if (FCh="-")
    StringTrimLeft,FirstLongString,FirstLongString,1
   if (SCh="-")
    StringTrimLeft,SecondLongString,SecondLongString,1
   StringLen, LS1Size, FirstLongString
   StringLen, LS2Size, SecondLongString
   Maxi:=Max(LS1Size,LS2Size)
   L1Diff:=Maxi-LS1Size+3
   L2Diff:=Maxi-LS2Size+3
   loop, %L1Diff%
      FirstLongString=0%FirstLongString%
   loop, %L2Diff%
      SecondLongString=0%SecondLongString%
   ;//Put back Minus if there was one
   if (FCh="-")
    FirstLongString=-%FirstLongString%
   if (SCh="-")
    SecondLongString=-%SecondLongString%
}

;//This function is subtracting Second from first and ALWAYS awaits
;//positiveONLY Strings (leading zeros already removed), AND that First is 
;//bigger than second so the result always will be positive e.g. 1000-456=544. 
;//This function is only for internal use and called by the real ADD-SUB-Functions
ABSLongIntStringSub(FirstLongString,SecondLongString)
{
   local MaxLength, ResultString, Erg, value1, value2, Sum, Rem
   Rem = 0
   ResultString =
   StringLen, MaxLength, FirstLongString
   loop, %MaxLength%
   {
      StringMid,value1,FirstLongString,MaxLength+1-A_index,1 
      StringMid,value2,SecondLongString,MaxLength+1-A_index,1 
      Sum:=value1-(value2+rem)
      Rem:=Div((9-sum),10)
      Erg:=Mod((sum+10),10)
      ResultString=%Erg%%ResultString%
   }
  return, %Resultstring%
}

;//This is the REAL Function that is able to subtract one LongIntString
;//from another. Is subtracting Second from First (LongStrings) and returns the 
;//Result as STRING. Now is supporting positive AND negative Long-Integers
LongIntStringSub(FirstLongString,SecondLongString)
{
   local WS1, WS2, WSResult, FIsNeg, SIsNeg, ABSCompi
   ;//remember the minus
   FIsNeg:=IsNeg(FirstLongString)
   SIsNeg:=IsNeg(SecondLongString)
   ;//remove the minus on workstrings
   WS1:=ABSLongIntString(FirstLongString)
   WS2:=ABSLongIntString(SecondLongString)
   ;//compare absolute size of BigNums
   ABSCompi:=CompareLongintStrings(WS1,WS2,0)
   ;//Make Strings same length with added zeroes
   MakeFitLength(WS1,WS2)
   If (FIsNeg="0" and SIsNeg="1") ;//First pos, second neg.  "x - -y" => "(x+y)"
     WSResult:=ABSLongIntStringAdd(WS1,WS2)
   else
   If (FIsNeg="1" and SIsNeg="0") ;//First neg, sec pos. "-x - y" => "-(x+y)"
     WSResult:=-ABSLongIntStringAdd(WS1,WS2)
   else
   If (FIsNeg="1" and SIsNeg="1") ;//Both are negative
   {
      if (ABSCompi=0)  ;//Both are same ABS-size. E.G. -5 - -5 => Result 0
        return, 0
      else
      if (ABSCompi=1)  ;//E.G. -1000 - -20 = -980 => Result negative
         WSResult:=-ABSLongIntStringSub(WS1,WS2)
      else
      if (ABSCompi=-1) ;//E.G. -20 - -1000 = +980 => Result positive
         WSResult:=ABSLongIntStringSub(WS2,WS1)
   }   
   else
   If (FIsNeg="0" and SIsNeg="0") ;//Both are positive
   {
      if (ABSCompi=0)  ;//Both are same ABS-size. E.G. 5 - 5 => Result 0
        return, 0
      else
      if (ABSCompi=1)  ;//E.G. 1000 - 20 = 980 => Result positive
         WSResult:=ABSLongIntStringSub(WS1,WS2)
      else
      if (ABSCompi=-1) ;//E.G. 20 - 1000 = -980 => Result negative
         WSResult:=-ABSLongIntStringSub(WS2,WS1)
   }
   RemoveLeadingZeros(WSResult)
   return, %WSResult%
}

;//This function is adding First and Second and always awaits Strings
;//(minuses removed) and prepared with MakeFitLength()
;//This function is only for internal use and called by the real ADD-SUB-Functions
ABSLongIntStringAdd(FirstLongString,SecondLongString)
{
   local MaxLength, ResultString, Erg, value1, value2, sum, Rem
   Rem = 0
   ResultString =
   StringLen, MaxLength, FirstLongString
   loop, %MaxLength%
   {
      StringMid,value1,FirstLongString,MaxLength+1-A_index,1 
      StringMid,value2,SecondLongString,MaxLength+1-A_index,1 
      Sum:=Value1+Value2+rem
      Erg:=Mod(Sum,10)
      Rem:=Div(Sum,10)
      ResultString=%Erg%%ResultString%
   }
  return, %Resultstring%
}

;//Is adding two LongIntSTRINGS
LongIntStringAdd(FirstLongString,SecondLongString)
{
   local WS1, WS2, WSResult, FIsNeg, SIsNeg, ABSCompi
   ;//remember the minus
   FIsNeg:=IsNeg(FirstLongString)
   SIsNeg:=IsNeg(SecondLongString)
   ;//remove the minus on workstrings
   WS1:=ABSLongIntString(FirstLongString)
   WS2:=ABSLongIntString(SecondLongString)
   ;//compare absolute size of BigNums
   ABSCompi:=CompareLongintStrings(WS1,WS2,0)
   ;//Make Strings same length with added zeroes
   MakeFitLength(WS1,WS2)
   If (FIsNeg="0" and SIsNeg="0") ;//Both positive =>Result positive
     WSResult:=ABSLongIntStringAdd(WS1,WS2)
   else
   If (FIsNeg="1" and SIsNeg="1") ;//Both negative =>Result negative
     WSResult:=-ABSLongIntStringAdd(WS1,WS2)
   else
   If (FIsNeg="1" and SIsNeg="0") ;//First negative, Second positive, further checking
   {
      if (ABSCompi=0)  ;//Both are same ABS-size. E.G. -5 + 5 => Result 0
        return, 0
      else
      if (ABSCompi=1)  ;//E.G. -1000 + 20 = -980 => Result negative
         WSResult:=-ABSLongIntStringSub(WS1,WS2)
      else
      if (ABSCompi=-1) ;//-20 + 1000 = +980 => Result positive
         WSResult:=ABSLongIntStringSub(WS2,WS1)
   }
   else
   If (FIsNeg="0" and SIsNeg="1") ;//First positive, Second negative, further checking
   {
      if (ABSCompi=0)  ;//Both are same ABS-size. E.G. 5 + -5 => Result 0
        return, 0
      else
      if (ABSCompi=1)  ;//E.G. 1000 + -20 = +980 => Result positive
         WSResult:=ABSLongIntStringSub(WS1,WS2)
      if (ABSCompi=-1) ;//E.G. 20 + -1000 = -980 => Result negative
         WSResult:=-ABSLongIntStringSub(WS2,WS1)
   }
   RemoveLeadingZeros(WSResult)
   return, %WSResult%
}


StringGetChar(In_String,In_Posi,Param3)
{
  local Length, Ret_Val
  Ret_Val = 
  StringLen, Length, In_String
  if (In_Posi>Length)or(length=0)or(In_Posi<1)
     return Ret_Val
  If (Param3=R)
     StringMid,Ret_Val,In_String,Length+1-In_Posi,1 
  else        
     StringMid,Ret_Val,In_String,In_Posi,1 
  return, %Ret_Val%   
}

;//Is multiplying FirstLongString and SecondLongString
LongIntStringMult(FirstLongString,SecondLongString)
{
  local ResultString, MulRes, RightVal, LeftVal, Loop1Count, OutLoopCounter
  local Loop2Count, InLoopCounter, ABSCompi, Help, ZeroAdd, FIsNeg, SIsNeg
  ;//remember the minus
  FIsNeg:=IsNeg(FirstLongString)
  SIsNeg:=IsNeg(SecondLongString)
  ;//remove the minus on workstrings
  WS1:=ABSLongIntString(FirstLongString)
  WS2:=ABSLongIntString(SecondLongString)
  ;//compare absolute size of BigNums
  ABSCompi:=CompareLongintStrings(WS1,WS2,0)
  if (ABSCompi=1)   ;//We do BiggerNum * SmallerNum
      Swap_Values(WS1,WS2)
  StringLen, Loop1Count, WS1
  StringLen, Loop2Count, WS2
  OutLoopCounter=0
  loop, %Loop1Count% 
  {
     OutLoopCounter+=1
     Help =
     Rem = 0
     InLoopCounter=0
     loop, %loop2Count%
     {
        InLoopCounter+=1
        RightVal:=StringGetChar(WS2,InLoopCounter,R)
        LeftVal:=StringGetChar(WS1,OutLoopCounter,R)
        MulRes:=(LeftVal*RightVal)+rem
        rem:=Div(Mulres,10)
        Rest:=Mod(Mulres,10)
        Help=%Rest%%Help%
     }     
     Help=%rem%%Help%  ;/Not sure if thies right ???
     ZeroAdd:=OutLoopCounter-1
     loop, %ZeroAdd%
        Help=%Help%0          
     MakeFitLength(ResultString,Help)
     ResultString:=ABSLongIntStringAdd(ResultString,Help)
  }
  RemoveLeadingZeros(ResultString)
  If ((FIsNeg="1") and (SIsNeg="0")) or ((FIsNeg="0") and (SIsNeg="1"))
    return, -%Resultstring%
  else
    return, %Resultstring%
}

ButtonCompare:
  Gui, Submit, NoHide
  CompareLongIntStrings(Long1,Long2,1)
  ;//Both are written back without leading zeros
  GuiControl,,Long1,%Long1% 
  GuiControl,,Long2,%Long2% 
return

ButtonSwap:
  Gui, Submit, NoHide
  Swap_Values(Long1,Long2)
  GuiControl,,Long1,%Long1%
  GuiControl,,Long2,%Long2%
return

PM1:
  Gui, Submit, NoHide
  if (IsNeg(Long1)="1")
  {
    Long1:=ABSLongintString(Long1)
    GuiControl,,Long1,%Long1%
  }
  else    
    GuiControl,,Long1,-%Long1%
return

PM2:
  Gui, Submit, NoHide
  if (IsNeg(Long2)="1")
  {
    Long2:=ABSLongintString(Long2)
    GuiControl,,Long2,%Long2%
  }
  else    
    GuiControl,,Long2,-%Long2%
return

ButtonB1+B2:
  Gui, Submit, NoHide
  Summy:=LongIntStringAdd(Long1,Long2)
  GuiControl,, ResultEdit, %Summy%`n`nHopefully the result is OK :)
return

ButtonB1-B2:
  Gui, Submit, NoHide
  Summy:=LongIntStringSub(Long1,Long2)
  GuiControl,, ResultEdit, %Summy%`n`nHopefully the result is OK :)
return

ButtonB1*B2:
  Gui, Submit, NoHide
  Summy:=LongIntStringMult(Long1,Long2)
  GuiControl,, ResultEdit, %Summy%`n`nHopefully the result is OK :)
return

ButtonB1/B2:
  MsgBox, Are you crazy ?`nThe Result mostly will be a float`n`nOk, I will work on this later :)
return


Greetings From Rubberduck
Wer keine Antworten hat muss nicht dumm sein,
dumm ist nur der welcher keine Fragen hat.

Rubberduck
  • Members
  • 97 posts
  • Last active: Jul 30 2005 12:17 AM
  • Joined: 24 Apr 2005
I changed the code. Now all calculation is done only with Strings.

This means you can add, subtract or multiply two string in the form:

-923892368893478973489349857938475983475893457..............or
1872364782634908092348902348092384092834094233..............

I thought this would be useful ti handle really larger integers.

If there is interest, I try to modify it for Floats and add also divison.
There is no guarantie that calculation is done properly, but I think it
is calculating right. If you find bugs post it.
Wer keine Antworten hat muss nicht dumm sein,
dumm ist nur der welcher keine Fragen hat.