Найти тему

Эксель и большие (длинные) числа. Часть 1.

Оглавление

Всем привет, меня зовут Андрей, и это снова я!

Эксель – очень хорошая программа, но один из ее недостатков – это неумение напрямую работать с большими числами. Они либо округляются и приводятся в экспонентный вид:

Рисунок 1.
Рисунок 1.

либо выдается информация о том, что результат – это слишком большое число:

Рисунок 2.
Рисунок 2.

Но эту проблему можно решить. Начнем с простого макроса. Он будет умножать большие числа, разбитые на отдельные цифры. Первое число будет в первой строке, а второе число – во второй строке. Если результат произведения (умножения) уместится в одной строке, это будет третья строка. Если не уместиться в третьей, тогда остаток результата уместится в четвертой строке.

Вот как будут выглядеть исходные данные:

Рисунок 3.
Рисунок 3.

А вот как выглядит результат – число 9577732621223881, разбитое на отдельные цифры.

Рисунок 4.
Рисунок 4.

Мы умножили само на себя число 97865891. Назовем это число буквой n. Чем знаменито это число (n)? Однажды победителем шоу «Удивительные люди» был человек, который в уме извлек корень 9999-й степени от одного очень большого числа, в котором было почти 80 тысяч цифр. Этим корнем было именно наше число n.

В столбце A мы видим количество цифр результата, в столбце B мы видим время в секундах, которое ушло на обработку данных.

Аналогичным образом можно получить, например, третью степень числа n:

Рисунок 5.
Рисунок 5.

А вот и текст макроса, который позволяет умножать большие числа тем способом, который показан в данной статье:

Sub Итал_умн_8000_а()
tim1 = Timer()
'отключаем обновление экрана
Application.ScreenUpdating = False
'Отключаем автоматический пересчет формул
Application.Calculation = xlCalculationManual
'Отключаем отслеживание событий
Application.EnableEvents = False
'Отключаем разбиение на печатные страницы
ActiveWorkbook.ActiveSheet.DisplayPageBreaks = False
'вначале очистим строки 3, 4:
Rows("3:4").Select
Selection.ClearContents
'сначала найдем количество цифр в исходных данных
w1 = WorksheetFunction.Count(Range(Cells(1, 9), Cells(1, 16384)))
w2 = WorksheetFunction.Count(Range(Cells(2, 9), Cells(2, 16384)))
w3 = w1 + w2
MA = 16384 - 8
dop = w3 - MA
If w1 = 1 And w2 = 1 Then
rez001 = Cells(1, 9) * Cells(2, 9)
If Len(rez001) = 2 Then
p2 = 1 * Mid(rez001, 2, 1)
p1 = 1 * Mid(rez001, 1, 1)
Cells(3, 9) = p1
Cells(3, 10) = p2
Cells(3, 1) = WorksheetFunction.Count(Range(Cells(3, 9), Cells(3, 16384)))
Else
p1 = rez001
Cells(3, 9) = p1
Cells(3, 1) = WorksheetFunction.Count(Range(Cells(3, 9), Cells(3, 16384)))
End If
tim1 = Timer() - tim1
Cells(3, 2) = WorksheetFunction.Round(tim1, 2)
Exit Sub
End If
Dim uno() As Double
ReDim uno(0 To w1 - 1)
st = 9
For i = w1 - 1 To 0 Step -1
uno(i) = Cells(1, st)
st = st + 1
Next i
Dim due() As Double
ReDim due(0 To w2 - 1)
st = 9
For j = w2 - 1 To 0 Step -1
due(j) = Cells(2, st)
st = st + 1
Next j
Dim sum() As Double
ReDim sum(0 To w3 - 1)
For k = 0 To w3 - 1
sum(k) = 0
Next k
For i = 0 To w1 - 1
For j = 0 To w2 - 1
q1 = uno(i) * due(j)
If Len(q1) = 1 Then
sum(i + j) = sum(i + j) + q1
'sum(i + j + 1) = sum(i + j + 1)
Else
sum(i + j) = sum(i + j) + 1 * Mid(q1, 2, 1)
sum(i + j + 1) = sum(i + j + 1) + 1 * Mid(q1, 1, 1)
End If
Next j
Next i
Dim Rez()
ReDim Rez(2, 0 To w3 - 1)
'последняя цифра рез-та
'это всегда Rez(2, 0)
Rez(2, 0) = sum(0)
'предпосл. цифра рез-та
'всегда Rez(2, 1)
'For t = 1 To w3 - 3
Rez(2, 1) = sum(1) Mod 10
'далее в уме
Rez(1, 2) = Int(sum(1) / 10)
'еще одна цифра рез-та
For t = 2 To w3 - 2
Rez(2, t) = (sum(t) + Rez(1, t)) Mod 10
'далее в уме
Rez(1, t + 1) = Int((sum(t) + Rez(1, t)) / 10)
'далее находим первую цифру результата (финиш)
Next t
Rez(2, w3 - 1) = sum(w3 - 1) + Rez(1, w3 - 1)
If w3 <= MA Then GoTo 10
If w3 = MA + 1 And Rez(2, w3 - 1) = 0 Then GoTo 10
GoTo 20
10 'далее показать конечный результат
'если он умещается в одну строку
If Rez(2, w3 - 1) > 0 Then
st = 9
For i = w3 - 1 To 0 Step -1
'всего внутри for-next w3-1 элементов
Cells(3, st).Value = Rez(2, i)
st = st + 1
Next i
Else
st = 9
For i = w3 - 2 To 0 Step -1
'всего внутри for-next w3-1 элементов
Cells(3, st).Value = Rez(2, i)
st = st + 1
Next i
End If
Range("A1").Select
Cells(3, 1).Value = WorksheetFunction.Count(Range(Cells(3, 9), Cells(3, 16384)))
tim1 = Round(Timer() - tim1, 2)
Cells(3, 2).Value = "t=" & tim1
GoTo 100
20 'далее показать конечный результат
'если он не умещается в одну строку
If Rez(2, w3 - 1) > 0 Then
st = 9
For i = w3 - 1 To dop Step -1
'всего внутри for-next w3-1 элементов
Cells(3, st).Value = Rez(2, i)
st = st + 1
If st > 16384 Then Exit For
Next i
st = 9
For j = dop - 1 To 0 Step -1
Cells(4, st) = Rez(2, j)
st = st + 1
If st > 16384 Then Exit For
Next j
Else
st = 9
For i = w3 - 2 To dop - 1 Step -1
Cells(3, st).Value = Rez(2, i)
st = st + 1
If st > 16384 Then Exit For
Next i
st = 9
For j = dop - 2 To 0 Step -1
Cells(4, st) = Rez(2, j)
st = st + 1
If st > 16384 Then Exit For
Next j
End If
Range("A1").Select
Cells(3, 1).Value = WorksheetFunction.Count(Range(Cells(3, 9), Cells(3, 16384)))
Cells(4, 1).Value = WorksheetFunction.Count(Range(Cells(4, 9), Cells(4, 16384)))
tim1 = Timer() - tim1
Cells(3, 2) = WorksheetFunction.Round(tim1, 2)
100 'Возвращаем обновление экрана
Application.ScreenUpdating = True
'Возвращаем автоматический пересчет формул
Application.Calculation = xlCalculationAutomatic
'Включаем отслеживание событий
Application.EnableEvents = True
End Sub
  • В следующих статьях будет другая информация о работе с большими числами в Эксель.

На этом пока все, подписывайтесь на мой канал, и до новых встреч!