Large Number Operations

In the past there have been many inquiries about how to perform math functions on numbers that are greatly larger that the standard variables which come embedded in Visual Basic, such as the Long. What do you do when you want to work with numbers that have a total length of digits that reach into the billions? You sure can't store those in a conventional variable, or perform normal operations on them.

The Solution is the Long Math module. In this module there are 4 functions: IntAddition, IntSubtraction, IntMultiply and IntDivide. Each takes two strings, and each performs the the operation in the title on the strings, which are suppose to contain these massively large integers.

This is version 1 of this code. I am currently working on a second version that will take and handle positive and negative numbers, be more fault tolerent, and work with decimals. The attached source code download also includes a demonstration project.

'******************************************************************
' Extra Long Integer Mathematics
'
' Programmer: Eric L. Truitte
' Contact Info: [email protected]
' Date Created: April 3, 2003
' Purpose:
'          Functions to handle mathmatics too large for
'          conventional variables and operations.
'
' Copyright notice:
'          This code is subject to the GNU General Public License.
'          If you make changes, add a Revision note.
'          This code is Open Source and should remain so.
'
'******************************************************************
' Revision Date: April 5, 2003
' Programmer: Eric L. Truitte
' Details:
'          Addition and Multiplication tested and finallized
'          Update comments
'
' Revision Date: February 19, 2005
' Programmer: Eric L. Truitte
' Details:
'          Finallized Subtraction and Division
'          Updated comments
'
'******************************************************************
'Notes:
'
'THERE IS CURRENTLY VERY LITTLE FAULT TOLERANCE IN THE FUNCTIONS
'entering a non-numeric character will cause errors.  If you intend to use these,
'make sure what you pass in is just a string of integers.
'
'To do list:
'  Decimals
'  Negatives
'  Multi-string length numbers
'
'What is the largest number that can be handled at this point?
'          A String can hold roughly the largest size of a Long value in characters.
'          That is the number of potential digits you can have in a number.
'
'I will be working on a decimal handling, possitive/negative, and arrays of strings
'containing segments of an Extra Long Integer.  I hope if you have need of such
'capacity of numbers that you have a system that can adequitely handle both
'system overhead and processor side-effects from overclocking for an extended
'period of time.
'
'******************************************************************
Public STOPNOW As Boolean 'This is a sentinel variable used in the demo form
Public Function IntAddition(ByVal FirstNum As String, ByVal SecondNum As String) As String
Dim a As Long, DifLen As Long, TempStr As String, TempNum As Integer
Dim Num1 As String, Num2 As String, TempNum1 As Integer, TempNum2 As Integer
Dim CarryOver As Integer, LeftOvers As Long
'Setup the numbers so that they are easier to handle.
'I originally had about 10 nested if statements that this block
'of code simplifies Dramatically.
  If Len(FirstNum) >= Len(SecondNum) Then
      Num1 = FirstNum
      Num2 = SecondNum
  Else
      Num2 = FirstNum
      Num1 = SecondNum
  End If
 
'Just setup some of the variables that need an initial value
  DifLen = Len(Num1) - Len(Num2)
  CarryOver = 0
  LeftOvers = DifLen
 
'Ok, now for the real math.  Looping from the end of the numbers
'just like our preschool teachers taught us, we add numbers that
'line up in the 'places' (I.E. ones, tens, hundreds, thousands, etc)
  For a = Len(Num2) To 1 Step -1
      TempNum1 = Int(Mid(Num1, a + DifLen, 1))
      TempNum2 = Int(Mid(Num2, a, 1))
      TempNum = TempNum1 + TempNum2 + CarryOver
      CarryOver = TempNum \ 10
      TempStr = (TempNum - (CarryOver * 10)) & TempStr
      DoEvents
      If STOPNOW = True Then GoTo StopAdd
  Next a
 
'What do we do if there is a 1 or a 2 that carries over outside the
'numbers that line up in the places, well, we do the following block of
'code.  The do loop is used incase we get a situation like this:
'
'    199999  When you add 1 to a set of nines it continues to
'    _+___1  Carry over until it hits the first digit
'    200000
  Do Until CarryOver = 0 Or LeftOvers = 0
      TempNum = Int(Mid(Num1, LeftOvers, 1)) + CarryOver
      CarryOver = TempNum \ 10
      TempStr = (TempNum - (CarryOver * 10)) & TempStr
      LeftOvers = LeftOvers - 1
  Loop
 
'Since there are two possible ways of exiting the Loop above, we need
'to test and apply the other variable and its associated values in the following
'two if statements.
'Handle a possible carryover that will drop off the front end creating a new place.
  If CarryOver > 0 Then TempStr = CarryOver & TempStr
'add any of the numbers that are remaining on the left side of the longer string
  If LeftOvers > 0 Then TempStr = Left(Num1, LeftOvers) & TempStr
'and return the value
StopAdd:
  IntAddition = TrimZeros(TempStr)
End Function
Public Function IntMultiply(ByVal FirstNum As String, ByVal SecondNum As String) As String
Dim ZeroStr As String
Dim a As Long, b As Long, Multiplier1 As Integer, Multiplier2 As Integer
Dim Num As Integer, CarryOver As Integer, TempStr As String, TallyStr As String
'THIS FUNCTION IS COMPLETE AND WORKS
'This function can handle two extra longs. It cycles through
'the firstnum one digit at a time from secondnum.
'this function works on the distrubution Principle of Multiplication:
' 9999 * 222 = (9999 * 2) + (9999 * 20) + (9999 * 200)
'
'The zero's are concatinated on after the multiplication takes place.
'
'This function is dependent on the IntAddition function above.
  For a = Len(FirstNum) To 1 Step -1
      'setup variables for this loop of multiplication
      TempStr = ""
      CarryOver = 0
      Multiplier1 = Mid(FirstNum, a, 1)
     
      'Multiply one digit at a time from right to left
      For b = Len(SecondNum) To 1 Step -1
        Multiplier2 = Mid(SecondNum, b, 1)
       
        Num = (Multiplier1 * Multiplier2) + CarryOver
        CarryOver = Num \ 10
        TempStr = (Num - (CarryOver * 10)) & TempStr
      Next b
       
      'Check to see if the multiplication added a new digit
      If CarryOver > 0 Then TempStr = CarryOver & TempStr
     
      'Add the zeros
      TempStr = TempStr & ZeroStr
      TallyStr = IntAddition(TempStr, TallyStr)
      ZeroStr = ZeroStr & "0"
     
      DoEvents
     
      'sentinel
      If STOPNOW = True Then GoTo StopMultiply
  Next a
 
StopMultiply:
  IntMultiply = TrimZeros(TallyStr)
End Function
Public Function TrimZeros(ByVal Num As String) As String
Dim a As Long, TempStr As String
  For a = 1 To Len(Num)
      If Mid(Num, a, 1) <> 0 Then GoTo YuckFu
  Next a
  TrimZeros = "0"
Exit Function
YuckFu:
  TrimZeros = Mid(Num, a, Len(Num) - a + 1)
End Function
Public Function IntSubtract(ByVal FirstNum As String, ByVal SecondNum As String) As String
'***
'DO NOT change the integers to bytes, there are negative values in this function
'***
Dim Num1 As String, Num2 As String, a As Long, Neg As Boolean, DifLen As Long
Dim TempStr As String, TempNum1 As Integer, TempNum2 As Integer
Dim TempNum As Integer, Barrow As Byte
'This function operates on a theory known as Two-Compliment.
'If you want to know more, look for it at www.mathforum.com
'This function works great now
'This block of code arranges the numbers into the Num1 and Num2 based on
'which number is larger.  This prevents a great number of errors if the numbers
'dont line up, or if the larger number is taken from the smaller number.
  If Len(FirstNum) > Len(SecondNum) Then
      Num1 = FirstNum
      Num2 = SecondNum
      Neg = False
  ElseIf Len(FirstNum) < Len(SecondNum) Then
      Num1 = SecondNum
      Num2 = FirstNum
      Neg = True
  Else
 
'In the case that the strings are of equal length we have this pretty little
'set of code to find which number has the first larger digit.
      For a = 1 To Len(FirstNum)
        If Int(Mid(FirstNum, a, 1)) > Int(Mid(SecondNum, a, 1)) Then
            Num1 = FirstNum
            Num2 = SecondNum
            Neg = False
            GoTo ContinSubtraction
           
        ElseIf Int(Mid(FirstNum, a, 1)) < Int(Mid(SecondNum, a, 1)) Then
            Num1 = SecondNum
            Num2 = FirstNum
            Neg = True
            GoTo ContinSubtraction
        End If
       
        DoEvents
       
        'sentinel
        If STOPNOW = True Then GoTo ExitFunction
      Next a
     
'In the case that no larger digit is found, then guess what, its a perfect
'subtraction, so we don't need to do the function, just assign a 0 outside the end.
      GoTo ExitFunction
  End If
 
ContinSubtraction:
'If we have a difference in length then ajust with 0's that will not affect the calculations.
'This allows us to get all the digits into the final out number.
  DifLen = Len(Num1) - Len(Num2)
  Num2 = String(DifLen, "0") & Num2
  Barrow = 0
'lets do some math
  For a = Len(Num2) To 1 Step -1
 
      'Pick out the individual digit from each number
      TempNum1 = Int(Mid(Num1, a, 1)) - Barrow
      TempNum2 = Int(Mid(Num2, a, 1))
      Barrow = 0
       
      'Perform single digit subraction using the Two Compliment theory
      If TempNum1 >= TempNum2 Then
        TempNum = TempNum1 - TempNum2
       
      ElseIf TempNum1 < TempNum2 Then
        TempNum = (TempNum1 + 10) - TempNum2
        Barrow = 1
      End If
     
      'Assign new digit to the final string.
      TempStr = CStr(TempNum) & TempStr
     
      DoEvents
     
      'sentinel
      If STOPNOW = True Then GoTo ExitFunction
  Next a
'now, since we are subtracting, we need to determine if the number being returned is a negative.
'Just to note, the Trim is to remove unneccsary zero's at the head(left) of the return number.
  If Neg = True Then
      IntSubtract = "-" & TrimZeros(Trim(TempStr))
  Else
      IntSubtract = TrimZeros(Trim(TempStr))
  End If
Exit Function
ExitFunction:
  IntSubtract = 0
End Function
Public Function IntDivide(ByVal FirstNum As String, ByVal SecondNum As String) As String
'Before we even alocate memory for variables, test for some very important error values
If Len(FirstNum) < Len(SecondNum) Or InStr(1, IntSubtract(FirstNum, SecondNum), "-") > 0 Then
  MsgBox "Fault: Extra Long Division does not support dividing a shorter number by a longer number, as this requires decimals which are not currently handled."
 
ElseIf TrimZeros(SecondNum) = "" Then
  MsgBox "Fault: Cannot divide by Zero."
 
ElseIf TrimZeros(SecondNum) = "" Then
  GoTo EndFunc
 
Else
  GoTo continDivide
End If
GoTo ExitDivide
'After passing the error checking, lets get started with some division
continDivide:
Dim Num1 As String, DivTotal As String, DivMult As String
Dim DifLen As Long, DivSub As String, TempNum As String
  'Initiallize values
  Num1 = FirstNum
  DivTotal = "0"
  DifLen = (Len(Num1) - Len(SecondNum))
  DivMult = String(DifLen, "0")
  DivSub = SecondNum & DivMult
 
  'Lets do some division
  Do Until (Len(Num1) < Len(SecondNum) Or Num1 = "0" Or (InStr(1, IntSubtract(Num1, SecondNum), "-") > 0 And DivMult = "")) Or STOPNOW = True
     
      'The way this division works is it subtracts values from the divided number
      'until no more can be subtracted.  This sets up a the largest possible number
      'that can be subtracted from the number so that you remove larger chucks of
      'Numbers at a time and waste less CPU Cycles doing it.
      If DifLen >= 0 Then DivMult = String(DifLen, "0")
      DivSub = SecondNum & DivMult
     
      If InStr(1, IntSubtract(Num1, DivSub), "-") > 0 Then
        If DifLen > 0 Then
            DivMult = String(DifLen - 1, "0")
            DivSub = SecondNum & DivMult
        Else
            Exit Do
        End If
      End If
     
      'Perform the accually math.  DivTotal adds up how many times the original
      'number has been subtracted from the divided number. Num1 is the working
      'number.
      DivTotal = IntAddition(DivTotal, "1" & DivMult)
      Num1 = IntSubtract(Num1, DivSub)
      DifLen = Len(Num1) - Len(SecondNum)
     
      DoEvents
     
      'sentinel
      If STOPNOW = True Then GoTo ExitDivide
  Loop
 
  'Since there are no decimals, we return return the devide results with a remainder.
  IntDivide = DivTotal & "r" & Num1
 
EndFunc:
Exit Function
ExitDivide:
IntDivide = "NaN"
End Function

 

You might also like...

Comments

 Eric Programming since I was 12 in the mid-90's, I've gotten a taste of professional programming and never looked back at other childhood aspirations. I love writing code. It's my career.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“My definition of an expert in any field is a person who knows enough about what's really going on to be scared.” - P. J. Plauger