PDA

Vollständige Version anzeigen : Rechnen mit großen Zahlen


FW
16.12.2009, 09:18
Durch diesen Beitrag (http://www.ms-office-forum.de/forum/showthread.php?t=259441) und diese Veröffentlichung (http://www.developerfusion.com/code/4670/large-number-operations/) bin ich auf die Idee gekommen, einige Funktionen zu entwickeln, die das Rechnen mit großen Zahlen ermöglichen.
Mit diesem CodePublic Function LTrim0(ByVal strVar As String) As String
Do Until Len(strVar) = 1 Or Left$(strVar, 1) <> "0"
strVar = Mid$(strVar, 2)
Loop
LTrim0 = strVar
End Function

Public Function StringAdd(ByVal strNo1 As String, ByVal strNo2 As String) As String
Dim bytSum As Byte, bytCarry As Byte
Dim lngMax As Long, lngVar As Long
Dim strSum As String

If Not (StringIsDecimal(strNo1) And StringIsDecimal(strNo2)) Then Err.Raise 5
strNo1 = LTrim0(strNo1)
strNo2 = LTrim0(strNo2)
lngMax = IIf(Len(strNo1) > Len(strNo2), Len(strNo1), Len(strNo2))
strNo1 = Right$(String$(lngMax, "0") & strNo1, lngMax)
strNo2 = Right$(String$(lngMax, "0") & strNo2, lngMax)
For lngVar = Len(strNo1) To 1 Step -1
bytSum = Val(Mid$(strNo1, lngVar, 1)) + Val(Mid$(strNo2, lngVar, 1)) + bytCarry
strSum = bytSum Mod 10 & strSum
bytCarry = bytSum \ 10
Next lngVar
If bytCarry Then strSum = bytCarry & strSum
StringAdd = strSum
End Function

Public Function StringConvertNumberToDecimal(ByVal strSrcNo As String, ByVal bytSrcBase As Byte) As String
Const cstDigits As String = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"

Dim lngVar As Long
Dim strPow As String, strRet As String

If bytSrcBase < 2 Or 36 < bytSrcBase Then Err.Raise 5
strSrcNo = UCase$(lTrim0(strSrcNo))
For lngVar = Len(strSrcNo) To 1 Step -1
If InStr(Left$(cstDigits, bytSrcBase), Mid$(strSrcNo, lngVar, 1)) = 0 Then Err.Raise 5
Next lngVar
strPow = "1"
strRet = "0"
For lngVar = Len(strSrcNo) To 1 Step -1
strRet = StringAdd(strRet, StringMultiply(CStr(InStr(cstDigits, Mid$(strSrcNo, lngVar, 1)) - 1), strPow))
strPow = StringMultiply(strPow, CStr(bytSrcBase))
Next lngVar
StringConvertNumberToDecimal = strRet
End Function

Public Function StringDivide(ByVal strNo1 As String, ByVal strNo2 As String) As String
Dim bytQuo As Byte
Dim lngVar As Long
Dim strQuo As String, strDiv As String, strVar As String

If Not (StringIsDecimal(strNo1) And StringIsDecimal(strNo2)) Then Err.Raise 5
strNo1 = LTrim0(strNo1)
strNo2 = LTrim0(strNo2)
lngVar = Len(strNo2)
strDiv = Left$(strNo1, lngVar)
Do While lngVar <= Len(strNo1)
strVar = StringSubtract(strDiv, strNo2)
bytQuo = 0
Do While Left$(strVar, 1) <> "-"
bytQuo = bytQuo + 1
strVar = StringSubtract(strVar, strNo2)
Loop
strQuo = strQuo & CStr(bytQuo)
lngVar = lngVar + 1
strDiv = StringSubtract(strNo2, Mid$(strVar, 2)) & Mid$(strNo1, lngVar, 1)
Loop
StringDivide = LTrim0(strQuo)
End Function

Public Function StringIsDecimal(ByVal strVar As String) As Boolean
Dim lngVar As Long

If strVar = "" Then Exit Function
For lngVar = Len(strVar) To 1 Step -1
If Mid$(strVar, lngVar, 1) < "0" Or "9" < Mid$(strVar, lngVar, 1) Then Exit Function
Next lngVar
StringIsDecimal = True
End Function

Public Function StringModulo(ByVal strNo1 As String, ByVal strNo2 As String) As String
If Not (StringIsDecimal(strNo1) And StringIsDecimal(strNo2)) Then Err.Raise 5
StringModulo = StringSubtract(strNo1, StringMultiply(strNo2, StringDivide(strNo1, strNo2)))
End Function

Public Function StringMultiply(ByVal strNo1 As String, ByVal strNo2 As String) As String
Dim bytPrd As Byte, bytCarry As Byte
Dim lngVar1 As Long, lngVar2 As Long
Dim strPrd As String, strVar As String

If Not (StringIsDecimal(strNo1) And StringIsDecimal(strNo2)) Then Err.Raise 5
strNo1 = LTrim0(strNo1)
strNo2 = LTrim0(strNo2)
If Len(strNo1) > Len(strNo2) Then
strVar = strNo1
strNo1 = strNo2
strNo2 = strVar
End If
strPrd = "0"
For lngVar1 = Len(strNo1) To 1 Step -1
strVar = String$(Len(strNo1) - lngVar1, "0")
bytCarry = 0
For lngVar2 = Len(strNo2) To 1 Step -1
bytPrd = Mid$(strNo1, lngVar1, 1) * Mid$(strNo2, lngVar2, 1) + bytCarry
strVar = bytPrd Mod 10 & strVar
bytCarry = bytPrd \ 10
Next lngVar2
If bytCarry Then strVar = bytCarry & strVar
strPrd = StringAdd(strPrd, strVar)
Next lngVar1
StringMultiply = strPrd
End Function

Public Function StringSubtract(ByVal strNo1 As String, ByVal strNo2 As String) As String
Dim bytDif As Byte, bytCarry As Byte
Dim lngVar As Long
Dim strDif As String, strVar As String

If Not (StringIsDecimal(strNo1) And StringIsDecimal(strNo2)) Then Err.Raise 5
strNo1 = LTrim0(strNo1)
strNo2 = LTrim0(strNo2)
If Len(strNo1) < Len(strNo2) Or (Len(strNo1) = Len(strNo2) And strNo1 < strNo2) Then
strVar = strNo1
strNo1 = strNo2
strNo2 = strVar
End If
strNo2 = Right$(String$(Len(strNo1), "0") & strNo2, Len(strNo1))
For lngVar = Len(strNo1) To 1 Step -1
bytDif = Val(Mid$(strNo1, lngVar, 1)) - Val(Mid$(strNo2, lngVar, 1)) - bytCarry + 10
strDif = bytDif Mod 10 & strDif
bytCarry = 1 - bytDif \ 10
Next lngVar
strDif = LTrim0(strDif)
If strVar > "" Then strDif = "-" & strDif
StringSubtract = strDif
End Functionkönnen folgende Operationen für ganzahlige positive Zahlen durchgeführt werden:
Addition (StringAdd)
Subtraktion (StringSubtract)
Multiplikation (StringMultiply)
Division (StringDivide)
Modulo (StringModulo)
Zahlenkonvertierung (StringConvertNumberToDecimal)
Die ersten 5 Funktionen erwarten 2 String-Parameter, die große positive Ganzzahlen darstellen und einen ebensolchen String zurückliefern.
Die 6-te Funktion erwartet 1 große positive Ganzzahl und das Zahlensystem, in dem diese Zahl dargestellt wird und liefert die Darstellung dieser Zahl im Dezimalsystem zurück.

Ein wenig Probieren sollte mehr erklären, als viele Worte.
Z. B. liefert StringConvertNumberToDecimal("", 16) den Wert "" zurück.

Wer interessiert ist, kann den Code für große negative Ganzzahlen erweitern:
Additon: -a + -b = -(a + b), a + -b = a - b, -a + b = b - a
Subtraktion: -a - -b = b - a, -a - b = -(a + b), a - -b = a + b
Multiplikation: -a * -b = a * b, -a * b = a * -b = -(a * b)
Division: -a / -b = a / b, -a / b = a / -b = -(a / b)
Modulo: -a % -b = -a % b = -(a % b), a mod -b = a mod b

Viel Spaß

FW
16.12.2009, 14:43
... der Vollständigkeit halber hier das Beispiel, was beim CopyPaste verlorengegangen ist:

Z. B. liefert StringConvertNumberToDecimal("15819a364dbe86b956083bbd1992857f", 16) den Wert "28586721999694642100505878794595370367" zurück

...

Eva08
17.12.2009, 16:23
vielen, vielen Dank. Mir hat das schon schlaflose Nächte bereitet.

Habe die Funktion eingebaut und es klappt wunderbar.