Накатал небольшую библиотечку для арифметических операций над натуральными числами любой длины. Поскольку писалось на Visual Basic for Applications (VBA), встроенном в Excel, переопределить операции + — * / не получилось, и все решается через вызов функций с 2-мя аргументами вида 
Function LongADD(s1 As String, s2 As String) As String
Зато можно вызывать функции (или их комбинации) прямо из ячеек экселовского листа – все наглядно и понятно. И да, натуральные числа передаются как строки. Максимальная длина строки в VBA равна примерно 231 = 2 147 483 648 (посчитано моей функцией LongPower(«2», 31)), так что на поиграться с разными штуками хватит вполне.
Для примера – умножение двух простых чисел из эпохальной статьи Ривеста, Шамира и Алдемана, откуда пошла вся современная криптография (в коде это константы RSA1, RSA2)

Под катом – код на VBA, его можно просто вставить в модуль Excel-овского файла с поддержкой макросов (типа *.xlsm).
P.S. не пробуйте использовать код для всяких конкурсов по разложению на простые множители. Он хоть и понимает числа с двумя миллиардами значащих цифр, но безумно медленный для таких задач.
P.P.S. если все же что-то получится, 10% выигрыша – мне
P.P.P.S. нет, лучше 15%
    
    Function LongADD(s1 As String, s2 As String) As String
Зато можно вызывать функции (или их комбинации) прямо из ячеек экселовского листа – все наглядно и понятно. И да, натуральные числа передаются как строки. Максимальная длина строки в VBA равна примерно 231 = 2 147 483 648 (посчитано моей функцией LongPower(«2», 31)), так что на поиграться с разными штуками хватит вполне.
Для примера – умножение двух простых чисел из эпохальной статьи Ривеста, Шамира и Алдемана, откуда пошла вся современная криптография (в коде это константы RSA1, RSA2)

Под катом – код на VBA, его можно просто вставить в модуль Excel-овского файла с поддержкой макросов (типа *.xlsm).
P.S. не пробуйте использовать код для всяких конкурсов по разложению на простые множители. Он хоть и понимает числа с двумя миллиардами значащих цифр, но безумно медленный для таких задач.
P.P.S. если все же что-то получится, 10% выигрыша – мне
P.P.P.S. нет, лучше 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
Поделиться с друзьями
              Комментарии (6)

NeoCode
20.01.2017 00:21+1Есть же всякие GMP, MPIR, MPFR… там вроде все реализовано (правда на Си, и я до сих пор не пойму чего они все три не объединятся в одну, ну да ладно).

daiver19
20.01.2017 00:51+8Не, ну вы серьёзно умножаете числа по основанию 10 в столбик? Да еще и на вба? Использовать большое основание не пробовали? А ффт для умножения?
Хабр не торт :-/
          
 
mickvav
Производительность с библиотечными реализациями сравнивали? Кроме арифметики что-то делать пробовали? Синусы там, корни?
vkomen
Нет, не думаю, что что-то выдающееся))
Другие функции — нет. Тут работа только с натуральными числами.
alexeykuzmin0
Числа как строки, 10-чная система счисления (а могла бы быть как минимум 10^9-чная), умножение за квадратичную сложность, сама реализация на VBA…
Поверьте, нет никакой необходимости оценивать производительность этого.