📜 ⬆️ ⬇️

Sooo long whole

Nakatal a small library for arithmetic operations on natural numbers of any length. Since it was written in Visual Basic for Applications (VBA) built into Excel, it was not possible to override + + * / operations, and everything is solved by calling functions with 2 arguments of the form

Function LongADD (s1 As String, s2 As String) As String

But you can call functions (or their combination) directly from the cells of the Excel sheet - everything is clear and understandable. And yes, natural numbers are passed as strings. The maximum length of a string in VBA is approximately 2 31 = 2 147 483 648 (calculated by my LongPower function (“2”, 31)), so it’s quite enough to play with different things.
')
For example, the multiplication of two prime numbers from the landmark article by Rivest, Shamir and Aldeman, from where all modern cryptography went (in the code these are RSA1, RSA2 constants)



Under the cut is the code on VBA, it can be simply inserted into the Excel module of the file with macro support (such as * .xlsm).

PS Do not try to use the code for all sorts of contests to decompose into prime factors. Although he understands numbers with two billions of meaningful numbers, he is insanely slow for such tasks.
PPS if something happens, 10% of the winnings - me
PPPS no, better than 15%


' 2 ,
Public Const RSA1 = "3490529510847650949147849619903898133417764638493387843990820577"
Public Const RSA2 = "32769132993266709549961988190834461413177642967992942539798288533"

'
Public Function LongAdd(s1 As String, s2 As String) As String

'
Dim Carry As Byte, Digit1 As Byte, Digit2 As Byte
Dim Result As String

Carry = 0
Result = ""

'
If Len(s1) > Len(s2) Then
s2 = String(Len(s1) - Len(s2), "0") & s2
Else
s1 = String(Len(s2) - Len(s1), "0") & s1
End If

'
For i = Len(s1) To 1 Step -1
Digit1 = CByte(Mid(s1, i, 1))
Digit2 = CByte(Mid(s2, i, 1))

Result = ((Carry + Digit1 + Digit2) Mod 10) & Result
Carry = (Carry + Digit1 + Digit2) \ 10
Next

If Carry > 0 Then Result = Carry & Result

LongAdd = Result

End Function

'
Public Function LongMultiply(ByVal s1 As String, ByVal s2 As String) As String

Dim Result As String, s As String
Result = "0"

' ,
If Len(s1) < Len(s2) Then
s = s1
s1 = s2
s2 = s
End If

'
s2 = String(Len(s1) - Len(s2), "0") & s2

'
For i = Len(s2) To 1 Step -1
Result = LongAdd(Result, LongMultiplyDigit(s1, Mid(s2, i, 1)) & String(Len(s2) - i, "0"))
Next

LongMultiply = Result

End Function

'
Public Function LongMultiplyDigit(s1 As String, s2 As String) As String

'
Dim Carry As Byte, Digit1 As Byte, Digit2 As Byte
Dim Result As String

Carry = 0
Result = ""
Digit2 = CByte(Left(s2, 1))

If Digit2 = 0 Then
LongMultiplyDigit = "0"
Exit Function
End If

For i = Len(s1) To 1 Step -1
Digit1 = CByte(Mid(s1, i, 1))

Result = ((Carry + Digit1 * Digit2) Mod 10) & Result
Carry = (Carry + Digit1 * Digit2) \ 10
Next

If Carry > 0 Then Result = Carry & Result
LongMultiplyDigit = Result

End Function

'
Public Function LongSubstract(ByVal s1 As String, ByVal s2 As String) As String

'
Dim Carry As Byte, Digit1 As Byte, Digit2 As Byte
Dim Result As String

Carry = 0
Result = ""

If LongCompare(s1, s2) Then
For i = Len(s1) To 1 Step -1

Digit1 = CByte(Mid(s1, i, 1))

If i - (Len(s1) - Len(s2)) < 1 Then
Digit2 = 0
Else
Digit2 = Mid(s2, i - (Len(s1) - Len(s2)), 1)
End If

If Digit1 >= Digit2 + Carry Then
Result = CStr(Digit1 - Carry - Digit2) & Result
Carry = 0
Else
Result = CStr(10 + Digit1 - Carry - Digit2) & Result
Carry = 1
End If
Next

LongSubstract = LongTrim(Result)
Else
LongSubstract = "0"
End If

End Function

'
Public Function LongDivide(ByVal s1 As String, ByVal s2 As String) As String

' ,
Dim Dividend As String, Residue As String, Quotient As String, Digit As Byte

' ,
If Not LongCompare(s1, s2) Then
LongDivide = "0"
Exit Function
End If

Dividend = ""
Residue = s1
Quotient = ""

While Len(Residue) > 0

Dividend = LongTrim(Dividend & Left(Residue, 1))
Residue = Right(Residue, Len(Residue) - 1)

If LongCompare(Dividend, s2) Then
For Digit = 1 To 9
If Not LongCompare(Dividend, LongMultiplyDigit(s2, CStr(Digit))) Then Exit For
Next

Quotient = Quotient & CStr(Digit - 1)
Dividend = LongSubstract(Dividend, LongMultiplyDigit(s2, CStr(Digit - 1)))
Else
Quotient = Quotient & "0"
End If

Wend

LongDivide = LongTrim(Quotient)

End Function

' . 0! = 1
Public Function LongFactor(N As Long) As String

Dim Fact As String, i As Long

Fact = "1"
For i = 2 To N
Fact = LongMultiply(Fact, CStr(i))
Next
LongFactor = Fact

End Function

' .
' (), -
Public Function LongPower(s As String, p As Long) As String

Dim Power As String

Power = s

For i = 2 To p
Power = LongMultiply(Power, s)
Next

LongPower = Power

End Function

' -
' TRUE
Public Function LongCompare(s1 As String, s2 As String) As Boolean

If Len(s1) <> Len(s2) Then
LongCompare = (Len(s1) > Len(s2))
Else
For i = 1 To Len(s1)
If CByte(Mid(s1, i, 1)) <> CByte(Mid(s2, i, 1)) Then
LongCompare = CByte(Mid(s1, i, 1)) >= CByte(Mid(s2, i, 1))
Exit Function
Else
LongCompare = True
End If
Next
End If

End Function

' -
Function LongTrim(s As String) As String

Dim TrimString As String
TrimString = s

While (Left(TrimString, 1) = "0") And (Len(TrimString) > 1)
TrimString = Right(TrimString, Len(TrimString) - 1)
Wend

LongTrim = TrimString

End Function

'
Public Function GroupDigits(s As String) As String

Dim d As String
d = ""

While Len(s) > 0
d = " " & Right(s, 3) & d
s = Left(s, Len(s) - 3)

Wend

GroupDigits = d

End Function

Source: https://habr.com/ru/post/319976/


All Articles