Переполнение длинного типа данных - PullRequest
2 голосов
/ 18 ноября 2008

Я пытаюсь провести некоторую простую факторизацию с моим VBA excel и достигаю предела типа данных long -

Ошибка выполнения 6 Переполнение

Есть ли способ обойти это и при этом остаться в VBA? Я знаю, что очевидным было бы использование другого, более подходящего языка программирования.


Решение Ланса работает настолько, что я могу теперь получить большие числа в переменных. Однако, когда я пытаюсь применить функцию MOD, например, bignumber MOD 2, она все равно не работает с сообщением об ошибке

Ошибка выполнения 6 Переполнение

Ответы [ 4 ]

2 голосов
/ 18 ноября 2008

Вот моя процедура «большого умножения» для умножения произвольно больших чисел (например, длиной 100 символов). Он работает путем разбиения входных чисел, которые являются строками, на куски по 7 цифр (потому что тогда он может умножить их на несколько и сохранить результаты в Double).

например, bigmultiply ("1934567803945969696433", "4483838382211678") = 8674289372323895422678848864807544574

Function BigMultiply(ByVal s1 As String, ByVal s2 As String) As String

Dim x As Long
x = 7

Dim n1 As Long, n2 As Long, n As Long
n1 = Int(Len(s1) / x + 0.999999)
n2 = Int(Len(s2) / x + 0.999999)
n = n1 + n2

Dim i As Long, j As Long
ReDim za1(n1) As Double
i = Len(s1) Mod x
If i = 0 Then i = x
za1(1) = Left(s1, i)
i = i + 1
For j = 2 To n1
 za1(j) = Mid(s1, i, x)
 i = i + x
Next j

ReDim za2(n2) As Double
i = Len(s2) Mod x
If i = 0 Then i = x
za2(1) = Left(s2, i)
i = i + 1
For j = 2 To n2
 za2(j) = Mid(s2, i, x)
 i = i + x
Next j

ReDim z(n) As Double
Dim u1 As Long, u2 As Long
Dim e As String
e = String(x, "0")

For u1 = 1 To n1
 i = u1
 For u2 = 1 To n2
   i = i + 1
   z(i) = z(i) + za1(u1) * za2(u2)
 Next u2
Next u1

Dim s As String, y As Double, w As Double, m As Long
m = n * x
s = String(m, "0")
y = 10 ^ x
For i = n To 1 Step -1
 w = Int(z(i) / y)
 Mid(s, i * x - x + 1, x) = Format(z(i) - w * y, e)
 z(i - 1) = z(i - 1) + w
Next i
'truncate leading zeros
For i = 1 To m
 If Mid$(s, i, 1) <> "0" Then Exit For
Next i
If i > m Then
 BigMultiply = ""
Else
 BigMultiply = Mid$(s, i)
End If

End Function
2 голосов
/ 18 ноября 2008

Это мои Decimals.cls (VB6):

VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
  Persistable = 0  'NotPersistable
  DataBindingBehavior = 0  'vbNone
  DataSourceBehavior  = 0  'vbNone
  MTSTransactionMode  = 0  'NotAnMTSObject
END
Attribute VB_Name = "Decimals"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = True
Attribute VB_Ext_KEY = "SavedWithClassBuilder6" ,"Yes"
Attribute VB_Ext_KEY = "Top_Level" ,"Yes"
Option Explicit

'local variable(s) to hold property value(s)
Private mvarDec As Variant 'local copy

Public Property Let Dec(ByVal vData As Variant)
'used when assigning a value to the property, on the left side of an assignment.
'Syntax: X.Dec = 5
    mvarDec = CDec(vData)
End Property

Public Property Get Dec() As Variant
Attribute Dec.VB_UserMemId = 0
'used when retrieving value of a property, on the right side of an assignment.
'Syntax: Debug.Print X.Dec
    Dec = CDec(mvarDec)
End Property

и это программа тестирования. Класс был настроен так, что вам не нужно соответствовать .Dec () при получении и отпускании.

Dim dec1 As New Std.Decimals
Dim dec2 As New Std.Decimals
Dim dec3 As New Std.Decimals
Dim modulus As New Std.Decimals

Sub main()
    dec1 = "1000.000000001"
    dec2 = "1000.00000000000001"
    dec3 = dec1 + dec2
    Debug.Print dec1
    Debug.Print dec2
    Debug.Print dec3
    Debug.Print dec3 * dec3
    Debug.Print dec3 / 10
    Debug.Print dec3 / 100
    Debug.Print Sqr(dec3)
    modulus = dec1 - Int(dec1 / dec2) * dec2
    Debug.Print modulus
End Sub

и пробный прогон

 1000.000000001 
 1000.00000000000001 
 2000.00000000100001 
 4000000.000004000040000001 
 200.000000000100001 
 20.0000000000100001 
 44.721359550007 
 0.00000000099999 
 1000.000000001 
 1000.00000000000001 
 2000.00000000100001 
 4000000.000004000040000001 
 200.000000000100001 
 20.0000000000100001 
 44.721359550007 
 0.00000000099999 
2 голосов
/ 18 ноября 2008

Вы можете использовать десятичный тип данных. Быстрый совет от Google: http://www.ozgrid.com/VBA/convert-to-decimal.htm

1 голос
/ 18 ноября 2008

MOD пытается преобразовать ваш тип DECIMAL в LONG, прежде чем работать с ним. Возможно, вам придется написать собственную функцию MOD для типа DECIMAL. Вы можете попробовать это:

r = A - Int(A / B) * B

где A & B - DECIMAL-подтип переменных VARIANT, и r, возможно, тоже должно быть таким большим (в зависимости от ваших потребностей), хотя я тестировал только на длинных.

...