Zufällig bin ich auf die Seite "projecteuler" gestoßen und habe mich mit großer Begeisterung auf die dort zu knobelnden Algorithmen-Aufgaben gestürzt. Selbstverständlich war es eine Frage der Ehre, BlitzMax zu verwenden .
Rasch und immer wieder stieß ich jedoch auf Probleme mit sehr großen Zahlen wie etwa 2^1000, für die BlitzMax (bekanntermaßen ) keine Datentypen bereitstellt. Kurzerhand habe ich mir dann die grundlegenden Funktionen selbst geschrieben. Wie im Titel beschrieben, geht es um die Menge der ganzen Zahlen, die man mit meinen Funktionen addieren, subtrahieren, multiplizieren, dividieren, Wurzelziehen, vergleichen, potenzieren und die Fakultät errechnen kann. Der Weg läuft - selbstverständlich - über String-Zeichenketten. Superstrict ist erforderlich.
Zum schnellen Ausprobieren sei hier erst einmal ein kleiner Demo-Code eingefügt:
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] SuperStrict Include "Calculate_StringInts.bmx" Local a:String = "230498170394817039847220938470950002347873438404" Local b:String = "-120928700037409384700128372877293204793749823394870233" Local c:String Print Print "----------------------------------------------------------" Print "Demonstration BM's StringInt-Functions fuer Ganze Zahlen" Print "----------------------------------------------------------" Print Print "Beispielzahl a = " + a Print "Beispielzahl b = " + b Print Print "Addition:" c = Add_StringInts(a, b) Print "c := a + b = " + c Print Print "Subtraktion:" Print "c - b = a = " + Subtract_StringInts(c, b) Print Print "Multiplikation:" c = Multiply_StringInts(a, b) Print "c := a * b = " + c Print Print "Division:" Print "c / b = a = " + Divide_StringInts(c, b) Print Print "Vergleich (0 = gleich, 1 = 1.Wert groesser, 2 = 2.Wert groesser):" Print "Compare_StringInts(a, b) = " + Compare_StringInts(a, b) Print Print "Potenzen:" Print "2 hoch 1000 = " + Power_Ints(2,1000) Print Print "Quadratwurzeln (falls noetig, abgerundet auf ganze Zahlen):" Print "Wurzel aus a = " + Sqr_StringInt(a) Print Print "Fakultaet:" Print "200! = " + Fac_Int(200) Print Print "----------------------------------------------------------" Print "Und beliebige Kombinationen und Tests:" Print "----------------------------------------------------------" Print Print "Die Wurzel aus 17 hoch 258:" Print Sqr_StringInt(Power_Ints(17, 258)) Print "sollte dasselbe sein wie 17 hoch 129" Print Power_Ints(17,129) Print Print "Die Wurzel aus 3 hoch 648:" Print Sqr_StringInt(Power_Ints(3, 648)) Print "sollte dasselbe sein wie 81 hoch 81" Print Power_Ints(81,81) Print Print "Die Wurzel aus 28561 hoch 74:" Print Sqr_StringInt(Power_Ints(28561, 74)) Print "sollte dasselbe sein wie 13 hoch 148" Print Power_Ints(13, 148) Print Print "----------------------------------------------------------" Print "Viel Spass beim 'Spielen'..." Print "----------------------------------------------------------"
Und hier kommt dann die ziemlich große "Calculate_StringInts.bmx"-Datei, die alle Funktionen bereitstellt:
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] Function Compare_StringInts:Int(StringInt1:String, StringInt2:String)
Local sign1:String = Left(StringInt1,1) Local sign2:String = Left(StringInt2,1) If sign1 <> "-" Then If sign2 = "-" Then Return 1 Else If sign2 <> "-" Then Return 2 Else StringInt1 = Right(StringInt1, Len(StringInt1)-1) StringInt2 = Right(StringInt2, Len(StringInt2)-1) End If End If Local Len1:Int = Len(StringInt1) Local Len2:Int = Len(StringInt2) If Len1 = Len2 Then Local single_digit:Int = 1 While single_digit =< Len1 If Int(Mid(StringInt1, single_digit, 1)) <> Int(Mid(StringInt2, single_digit, 1)) Then If Int(Mid(StringInt1, single_digit, 1)) > Int(Mid(StringInt2, single_digit, 1)) Then If sign1 <> "-" Then Return 1 Return 2 Else If sign1 <> "-" Then Return 2 Return 1 End If End If single_digit = single_digit + 1 Wend Return 0 ElseIf Len1 > Len2 Then If sign1 <> "-" Then Return 1 Return 2 Else If sign1 <> "-" Then Return 2 Return 1 End If
End Function
Function Power_Ints:String(integer1:Int, integer2:Int)
If integer2 > 1 Then Local sign:String If integer1 < 0 Then integer1 = -integer1 If integer2 / 2 * 2 <> integer2 Then sign = "-" End If Local TempStringInt:String = power_Ints(integer1, integer2/2) If integer2 / 2 * 2 = integer2 Then Return sign + multiply_StringInts(TempStringInt, TempStringInt) TempStringInt = multiply_StringInts(TempStringInt, TempStringInt) Return sign + multiply_StringInts(TempStringInt, integer1) ElseIf integer2 = 1 Then Return String(integer1) ElseIf integer2 = 0 Then Return "1" Else Return "0" End If
End Function
Function Sqr_StringInt:String(StringInt:String)
Local LeftDigit:String = Left(StringInt, 1) If LeftDigit = "-" Then Return "ERROR" Local count_digits:Int = Len(StringInt) If count_digits < 18 Then Return String(Long(Sqr(Long(StringInt)))) Local x0:String, y0:String, x:String, y:String, Memo_x:String If count_digits / 2 * 2 = count_digits Then Local Top:String = "1000000000" Local Length:String = "68377224" Local d:Int = 9 While d < count_digits/2 Top = Top + "0" Length = Length + "0" d = d + 1 Wend x = subtract_StringInts(Top, multiply_StringInts(Length, LeftDigit)) Else Local Down:String = "1000000000" Local Length:String = "216227766" Local d:Int = 9 While d < count_digits/2 Down = Down + "0" Length = Length + "0" d = d + 1 Wend x = add_StringInts(Down, multiply_StringInts(Length, LeftDigit)) End If y = multiply_StringInts(x, x) Repeat x = subtract_StringInts(x, divide_StringInts(subtract_StringInts(y, StringInt), add_StringInts(x, x))) y = multiply_StringInts(x, x) x0 = subtract_StringInts(x, "1") y0 = multiply_StringInts(x0, x0) If y = StringInt Or Memo_x = x Then Return x ElseIf compare_StringInts(y, StringInt) = 1 And compare_StringInts(y0, StringInt) <> 1 Then Return x0 End If Memo_x = x Forever
End Function
Function Fac_Int:String(integer:Int)
If integer > 12 Then Local StringInt:String = "479001600" For Local i:Int = 13 To integer StringInt = multiply_StringInts(StringInt, i) Next Return StringInt ElseIf integer > 0 Then Local simple_fac:Int = 1 For Local i:Int = 2 To integer simple_fac = simple_fac * i Next Return String(simple_fac) Else Return "0" End If
End Function
Function Multiply_StringInts:String(StringInt1:String, StringInt2:String)
Local StringInt3:String, TempLong:Long[2], digits9_1:Int, digits9_2:Int, zero9:Int Local TempString:String, sign:String = "" If Left(StringInt1, 1) <> "-" Then If Left(StringInt2, 1) = "-" Then sign = "-" StringInt2 = Right(StringInt2, Len(StringInt2)-1) End If Else StringInt1 = Right(StringInt1, Len(StringInt1)-1) If Left(StringInt2, 1) <> "-" Then sign = "-" Else StringInt2 = Right(StringInt2, Len(StringInt2)-1) End If End If Local Len1:Int = Len(StringInt1) Local Len2:Int = Len(StringInt2) Repeat digits9_1 = digits9_1 + 9 TempLong[0] = Long(Mid(StringInt1, Len1 + 1 - digits9_1, 9)) digits9_2 = 9 Repeat TempLong[1] = Long(Mid(StringInt2, Len2 + 1 - digits9_2, 9)) TempString = String(TempLong[0] * TempLong[1]) zero9 = (digits9_1 - 9) / 9 + (digits9_2 - 9) / 9 For Local z:Int = 1 To zero9 TempString = TempString + "000000000" Next StringInt3 = add_StringInts(StringInt3, TempString) If digits9_2 >= Len2 Then Exit digits9_2 = digits9_2 + 9 Forever If digits9_1 >= Len1 Then Exit Forever Return sign + StringInt3
End Function
Function Divide_StringInts:String(StringInt1:String, StringInt2:String)
If StringInt2 = 0 Then Return "ERROR" Local sign:String = "" If Left(StringInt1, 1) <> "-" Then If Left(StringInt2, 1) = "-" Then sign = "-" StringInt2 = Right(StringInt2, Len(StringInt2)-1) End If Else StringInt1 = Right(StringInt1, Len(StringInt1)-1) If Left(StringInt2, 1) <> "-" Then sign = "-" Else StringInt2 = Right(StringInt2, Len(StringInt2)-1) End If End If Local comparison:Int = compare_StringInts(StringInt1, StringInt2) If comparison = 1 Then Local multiplied_StringInt2:String[10] multiplied_StringInt2[1] = StringInt2 For Local mSI:Int = 2 To 9 multiplied_StringInt2[mSI] = add_StringInts(multiplied_StringInt2[mSI - 1], StringInt2) Next Local StringInt3:String Local Len1:Int = Len(StringInt1) Local Len2:Int = Len(StringInt2) Local index:Int = Len2 Local rest:String = Left(StringInt1, Len2-1) While index =< Len1 Local Part_from_StringInt1:String If rest <> "0" Then Part_from_StringInt1 = rest + Mid(StringInt1, index, 1) Else Part_from_StringInt1 = Mid(StringInt1, index, 1) End If Local TestFactor:Int = 0 Repeat TestFactor = TestFactor + 1 If TestFactor = 10 Then Exit Until compare_StringInts(Part_from_StringInt1, multiplied_StringInt2[TestFactor]) = 2 TestFactor = TestFactor - 1 If Part_from_StringInt1 <> multiplied_StringInt2[TestFactor] Then rest = subtract_StringInts(Part_from_StringInt1, multiplied_StringInt2[TestFactor]) Else rest = "" End If StringInt3 = StringInt3 + String(TestFactor) index = index + 1 Wend If Left(StringInt3, 1) = "0" Then Return sign + Right(StringInt3, Len(StringInt3)-1) Return sign + StringInt3 ElseIf comparison = 0 Then Return sign + "1" End If Return "0"
End Function
Function Add_StringInts:String(StringInt1:String, StringInt2:String)
Local Len1:Int = Len(StringInt1) Local Len2:Int = Len(StringInt2) Local StringInt3:String, TempInt:Int[3], Addition_to_Next:Int, digits8:Int = 8 Local sign1:String = Left(StringInt1,1) Local sign2:String = Left(StringInt2,1) If sign1 <> "-" Then If sign2 <> "-" Then sign1 = "" Else Return subtract_StringInts(StringInt1, Right(StringInt2, Len2-1)) End If Else If sign2 <> "-" Then Return subtract_StringInts(StringInt2, Right(StringInt1, Len1-1)) Else sign1 = "-" StringInt1 = Right(StringInt1, Len1-1) Len1 = Len1 - 1 StringInt2 = Right(StringInt2, Len2-1) Len2 = Len2 - 1 End If End If Repeat TempInt[0] = Int(Mid(StringInt1, Len1 + 1 - digits8, 8)) TempInt[1] = Int(Mid(StringInt2, Len2 + 1 - digits8, 8)) TempInt[2] = TempInt[0] + TempInt[1] + Addition_to_Next Addition_to_Next = TempInt[2] / 100000000 Local TempString:String = String(TempInt[2] Mod 100000000) While Len(TempString) < 8 TempString = "0" + TempString Wend StringInt3 = TempString + StringInt3 If digits8 > Len1 And digits8 > Len2 Then Exit digits8 = digits8 + 8 Forever While Left(StringInt3,1) = "0" And Len(StringInt3) > 1 StringInt3 = Right(StringInt3, Len(StringInt3)-1) Wend If Addition_to_Next = 0 Then If StringInt3 <> "0" Then Return sign1 + StringInt3 Return "0" Else Return sign1 + String(Addition_to_Next) + StringInt3 End If
End Function
Function Subtract_StringInts:String(StringInt1:String, StringInt2:String)
Local Len1:Int = Len(StringInt1) Local Len2:Int = Len(StringInt2) Local StringInt3:String, TempInt:Int[3], Subtraction_to_Next:Int, digits8:Int = 8 Local sign1:String = Left(StringInt1,1) Local sign2:String = Left(StringInt2,1) If sign1 <> "-" Then If sign2 <> "-" Then If Len1 = Len2 Then Local single_digit:Int = 1 While single_digit =< Len1 If Int(Mid(StringInt1, single_digit, 1)) <> Int(Mid(StringInt2, single_digit, 1)) Then If Int(Mid(StringInt1, single_digit, 1)) < Int(Mid(StringInt2, single_digit, 1)) Then sign1 = "-" Exit End If single_digit = single_digit + 1 Wend End If If sign1 = "-" Or Len1 < Len2 Then Local MemoString:String = StringInt1 StringInt1 = StringInt2 StringInt2 = MemoString Len1 = Len(StringInt1) Len2 = Len(StringInt2) sign1 = "-" Else sign1 = "" End If Else Return add_StringInts(StringInt1, Right(StringInt2, Len2-1)) End If Else If sign2 <> "-" Then Return add_StringInts(StringInt1, "-" + StringInt2) Else Len1 = Len1 - 1 Len2 = Len2 - 1 StringInt1 = Right(StringInt1, Len1) StringInt2 = Right(StringInt2, Len2) If Len1 = Len2 Then Local single_digit:Int = 1 While single_digit =< Len1 If Int(Mid(StringInt1, single_digit, 1)) <> Int(Mid(StringInt2, single_digit, 1)) Then If Int(Mid(StringInt1, single_digit, 1)) < Int(Mid(StringInt2, single_digit, 1)) Then sign1 = "" Exit End If single_digit = single_digit + 1 Wend End If If sign1 = "" Or Len1 < Len2 Then Local MemoString:String = StringInt1 StringInt1 = StringInt2 StringInt2 = MemoString Len1 = Len(StringInt1) Len2 = Len(StringInt2) sign1 = "" End If End If End If Repeat TempInt[0] = Int(Mid(StringInt1, Len1 + 1 - digits8, 8)) TempInt[1] = Int(Mid(StringInt2, Len2 + 1 - digits8, 8)) TempInt[2] = TempInt[0] - TempInt[1] - Subtraction_to_Next If TempInt[2] < 0 Then If Len1 - digits8 > 0 Then TempInt[2] = TempInt[2] + 100000000 Else TempInt[2] = TempInt[2] + 10^Len(String(TempInt[2])) End If Subtraction_to_Next = 1 Else Subtraction_to_Next = 0 End If Local TempString:String = String(TempInt[2] Mod 100000000) While Len(TempString) < 8 TempString = "0" + TempString Wend StringInt3 = TempString + StringInt3 If digits8 > Len1 And digits8 > Len2 Then Exit digits8 = digits8 + 8 Forever While Left(StringInt3,1) = "0" And Len(StringInt3) > 1 StringInt3 = Right(StringInt3, Len(StringInt3)-1) Wend If Subtraction_to_Next = 0 Then If StringInt3 <> "0" Then Return sign1 + StringInt3 Return "0" Else Return sign1 + String(Subtraction_to_Next) + StringInt3 End If
End Function
|