I know the ranges. But, I need to go beyond 1.7E308. I could not see
anything on this on help. As you can see 1000! = 4.02E+2567, which is
outside the range of a double.
Bob
> I know the ranges. But, I need to go beyond 1.7E308.
> I could not see anything on this on help. As you can see
> 1000! = 4.02E+2567, which is outside the range of a double.
As Paul said, no other way than to either use a lib with "long-math"
support (there should be many of these libs out there - and IIRC
e.g. Java has this builtin) - or to write your own, based on Strings
or ByteArrays...
It's somewhat like you've learned to multiply or divide in
school ... to get an idea, what optimizations can be done
"on top" of such a scool-like algo (you don't need to process
each digit on a 10th-base)...
Here's a (somewhat rusty) LongMul-routine, wich I wrote ca.
10 years ago. It is able to multiply two 600-digit-numbers in
under 4 msec on an old PIII 500.
'****Into a Form
Option Explicit
Private Declare Function QueryPerformanceFrequency& Lib "kernel32" (X@)
Private Declare Function QueryPerformanceCounter& Lib "kernel32" (X@)
Private Sub Form_Click()
Dim R$, Factor$: Const L& = 600
Factor = String(L, "9")
R = LongMul(Factor, Factor)
'small test for "pure" 9'er
If R = String(L - 1, "9") & 8 & String(L - 1, "0") & 1 Then
Print "correct result for 'square-niners'"
End If
End Sub
Private Function LongMul$(S1$, S2$)
Dim i&, j&, d&, m&, JArr$(), L1&(), L2&(), Sum@(), S, t#
t = HPTimer
If S1 = "" Then S1 = "0"
If S2 = "" Then S2 = "0"
If Left(S1, 1) = "-" Then S1 = Mid(S1, 2): S = True
If Left(S2, 1) = "-" Then S2 = Mid(S2, 2): S = Not S
'Convert to Long-Array
m = Len(S1) + 1: d = 4: i = 0
Do: m = m - 4: If m <= 0 Then d = 4 + m - 1: m = 1
ReDim Preserve L1(i): L1(i) = Mid(S1, m, d): i = i + 1
Loop Until m = 1
m = Len(S2) + 1: d = 4: i = 0
Do: m = m - 4: If m <= 0 Then d = 4 + m - 1: m = 1
ReDim Preserve L2(i): L2(i) = Mid(S2, m, d): i = i + 1
Loop Until m = 1
Print "Transform to LongArr: " & CLng((HPTimer - t) * 1000)
'Multiply and Group-accumulation
t = HPTimer
ReDim Sum(UBound(L1) + UBound(L2))
For i = 0 To UBound(L1)
For j = 0 To UBound(L2)
Sum(i + j) = Sum(i + j) + L1(i) * L2(j)
Next j
Next i
Print "Multiply: " & CLng((HPTimer - t) * 1000)
'Reconvert to String-Parts
t = HPTimer
ReDim JArr(UBound(Sum))
For i = 0 To UBound(Sum) - 1
JArr(UBound(Sum) - i) = Right("000" & Sum(i), 4)
Sum(i + 1) = Sum(i + 1) + Int(Sum(i) / 10000)
Next i
JArr(UBound(Sum) - i) = IIf(S, "-", "") & Sum(i)
Print "Prepare for Output: " & CLng((HPTimer - t) * 1000)
'Join&Exit
t = HPTimer
LongMul = Join(JArr, "")
Print "Join&Exit: " & CLng((HPTimer - t) * 1000)
End Function
Private Function HPTimer#()
Dim X@: Static Frq@
If Frq = 0 Then QueryPerformanceFrequency Frq
If QueryPerformanceCounter(X) Then HPTimer = X / Frq
End Function
Olaf
Bob - 01 Sep 2008 20:48 GMT
Thank you Olaf. In the next few days, I will take a look at your code, and
expand on it. Thanks for all your help.
Bob
>> I know the ranges. But, I need to go beyond 1.7E308.
>> I could not see anything on this on help. As you can see
[quoted text clipped - 80 lines]
>
> Olaf
Use logs Bob, e.g the following calculates your 1000!
Dim i As Integer, fRes As Double
i = 1000
Do While i > 1
fRes = fRes + Log(i) / Log(10)
i = i - 1
Loop
Debug.Print "Answer = " & 10 ^ (fRes - Int(fRes)) & "E" & Int(fRes)
Tony Proctor
>I know the ranges. But, I need to go beyond 1.7E308. I could not see
>anything on this on help. As you can see 1000! = 4.02E+2567, which is
[quoted text clipped - 13 lines]
>> How about VB's own Help for a resource? It lists the ranges of all data
>> types.
Bob - 06 Sep 2008 18:55 GMT
Thanks Tony.
Bob
> Use logs Bob, e.g the following calculates your 1000!
>
[quoted text clipped - 26 lines]
>>> How about VB's own Help for a resource? It lists the ranges of all data
>>> types.