Найти в Дзене

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

Всем привет, меня зовут Андрей, и это снова я! Продолжаю рассказывать про эксель и большие (длинные) числа. Напомню, что моя предыдущая статья на эту тему была расположена по этому адресу. В данной статье - продолжение этой темы. Итак, если тот макрос, о котором я говорил в прошлой статье, мог умножать большие числа, но таким образом, что конечный результат каждый раз умещался на одних и тех же строчках эксель (строка 3, если результат умещался в одну строку, или строки 3-4, если результат не умещался в одну строку). Мы решим многие проблемы, создав копию макроса под названием Итал_умн_8000_б(). Эта версия макроса будет искать первую свободную строку эксель, и помещать один результат под другим. Приведем пример. Допустим, что мы вначале умножили 32768 на 32: Результат: 2097152. А затем нужно умножить 3125 на 625: Результат: 1953125. Хотя мы для примера использовали не очень большие числа, те макросы, что производили расчеты, способны справиться и с длинными числами тоже. В столбце A мы
Оглавление

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

Продолжаю рассказывать про эксель и большие (длинные) числа.

Напомню, что моя предыдущая статья на эту тему была расположена по этому адресу.

В данной статье - продолжение этой темы.

Итак, если тот макрос, о котором я говорил в прошлой статье, мог умножать большие числа, но таким образом, что конечный результат каждый раз умещался на одних и тех же строчках эксель (строка 3, если результат умещался в одну строку, или строки 3-4, если результат не умещался в одну строку).

Мы решим многие проблемы, создав копию макроса под названием Итал_умн_8000_б(). Эта версия макроса будет искать первую свободную строку эксель, и помещать один результат под другим.

Приведем пример. Допустим, что мы вначале умножили 32768 на 32:

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

Результат: 2097152.

А затем нужно умножить 3125 на 625:

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

Результат: 1953125.

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

Итак, мы видим оба результата. Каждый следующий результат будет располагаться под предыдущим. Или даже еще ниже, потому что макрос просто ищет первую свободную строку, то есть: если мы между запусками этого макроса будем заполнять ячейки эксель другой информацией, все равно наш макрос найдет первую свободную строку.

А вот, кстати, и текст этого макроса:

Sub Итал_умн_8000_б()
tim1 = Timer()
'отключаем обновление экрана
Application.ScreenUpdating = False
'Отключаем автоматический пересчет формул
Application.Calculation = xlCalculationManual
'Отключаем отслеживание событий
Application.EnableEvents = False
'Отключаем разбиение на печатные страницы
ActiveWorkbook.ActiveSheet.DisplayPageBreaks = False

'сначала найдем количество цифр в исходных данных

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

'LR1 - это не последняя заполненная строка, а первая свободная
LR1 = Cells.SpecialCells(xlLastCell).Row + 1

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(LR1, 9) = p1
Cells(LR1, 10) = p2
Cells(LR1, 1) = WorksheetFunction.Count(Range(Cells(LR1, 9), Cells(LR1, 16384)))
Else
p1 = rez001
Cells(LR1, 9) = p1
Cells(LR1, 1) = WorksheetFunction.Count(Range(Cells(LR1, 9), Cells(LR1, 16384)))
End If
tim1 = Timer() - tim1
Cells(LR1, 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
Else
sum(i + j) = sum(i + j) + Mid(q1, 2, 1)
sum(i + j + 1) = sum(i + j + 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)

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 'далее показать конечный результат
'если он умещается в одну строку
st = 9
If Rez(2, w3 - 1) > 0 Then
For i = w3 - 1 To 0 Step -1
'всего внутри for-next w3-1 элементов
Cells(LR1, st).Value = Rez(2, i)
st = st + 1
Next i
Else
For i = w3 - 2 To 0 Step -1
'всего внутри for-next w3-1 элементов
Cells(LR1, st).Value = Rez(2, i)
st = st + 1
Next i
End If
Range("A1").Select
Cells(LR1, 1).Value = WorksheetFunction.Count(Range(Cells(LR1, 9), Cells(LR1, 16384)))

tim1 = Timer() - tim1

Cells(LR1, 2) = WorksheetFunction.Round(tim1, 2)

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(LR1, 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(LR1 + 1, 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(LR1, 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(LR1 + 1, st) = Rez(2, j)
st = st + 1
If st2 > 16384 Then Exit For
Next j
End If
Range("A1").Select
Cells(LR1, 1).Value = WorksheetFunction.Count(Range(Cells(LR1, 9), Cells(LR1, 16384)))
Cells(LR1 + 1, 1).Value = WorksheetFunction.Count(Range(Cells(LR1 + 1, 9), Cells(LR1 + 1, 16384)))

tim1 = Timer() - tim1

Cells(LR1 + 1, 2) = WorksheetFunction.Round(tim1, 2)
100 'Возвращаем обновление экрана
Application.ScreenUpdating = True
'Возвращаем автоматический пересчет формул
Application.Calculation = xlCalculationAutomatic
'Включаем отслеживание событий
Application.EnableEvents = True

End Sub

А теперь рассмотрим еще несколько примеров работы этого макроса. Пусть, например, нам надо умножить число, в котором (16384-8), то есть 16376, девяток, на число, в котором столько же семерок:

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

В принципе, это число можно вычислить "в уме": если мы прибавим к тому числу, что состоит из одних девяток, единицу, а затем умножим на то число, что состоит из одних семерок, то получим число, в котором 16376 семерок, а вслед за ними будет столько же нолей. Но если из этого числа отнять 16376 семерок, то мы получим: 16375 семерок в начале, затем 6 (одна цифра, шестерка), затем 16375 двоек и одна тройка в конце. Так что в нашем конкретном случае можно точно сказать, какие цифры находятся в скрытых столбцах. Но такие ситуации, когда все скрытые цифры длинного числа очевидны, встречаются не очень часто.

Итак, мы получили конечный результат, он занял две строчки эксель.

Но это еще не всё, о многом из того, что еще можно сделать c большими числами, я расскажу в следующих статьях на эту тему.

А потому,

  • Продолжение следует...

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