News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Hyper (precision) numeric data type

Started by iZ!, October 15, 2023, 07:38:52 PM

Previous topic - Next topic

iZ!

#90
hey all,
new version should work much faster

- optimized multiplication by another Hyper; it was calling the below mentioned routine before each Add operation
- removed unnecessary buffer-resizing statements called in a procedure prior to actual Add and Subtract operations
- slightly optimized Add and Subtract procedures themselves
- added option to skip boundary check altogether, e.g. hyp1.Add(hyp2, False)

At some point, I changed tactics - the +/- procedures now don't check the buffer's upper bound, it just flows until there's a remainder. But with new tactics came new mistakes :)

EDIT: In theory, it sounds nice, but after testing on the same day, I found that nothing is faster... Only way I can explain this is that ReDim(LBnd, UBnd) takes no time to execute

iZ!

my division function had an error,
If (lowVal And 1) = 0 Then instead of If lowVal And 1 = 0 Then
https://masm32.com/board/index.php?msg=133222

here's a little cleaner code, with no output messages:
Private Function QuickDivide(dividend As Hyper, d As Hyper) As Hyper
Return dividend * ReciprocalVal(d)
End Function

Private Function ReciprocalVal(d As Hyper) As Hyper

precision% = 18 'number of 64-bit digits to extract. Must be larger than exponent range
precision2% = 180 'may be zero

Dim r As New Hyper(precision, 0) ' New Hyper(0, 0)
Dim bp, r1 As Hyper

hiExp% = d.FindHighExponent
lowExp% = d.FindLowExponent '000000000000000000000000000000000000000000000 d.PartSize
lowVal& = d(lowExp)
Dim mq&
If (lowVal And 1) = 0 Then
' Debug.WriteLine("even nr")
'if the least significant bit is 0, then we can help ourselves with dividing/multiplying the dividend, and then the result, by 2^n.

' d(lowExp) = d(lowExp) Or 1
'lowVal& = d(lowExp)
d(lowExp - 1) = 1
lowVal = 1
lowExp -= 1
mq = -1
Else
mq& = GetMagicNr(lowVal)

End If

d.PartSize = 0
bp = New Hyper("1")
pos1% = 0

mainloop:
' get the sequence which, when multiplied by divisor, nullifies itself

r1 = New Hyper(pos1, pos1)
r1(pos1) = bp(pos1) * mq

r(pos1) = r1(pos1)
bp -= d * r1
bp.Negate()

pos1 += 1

If pos1 > precision Then GoTo nx
'reciprocal values of large numbers tend to repeat at very large intervals, so we'll be satisfied with our precision

GoTo mainloop

nx:
r1 = r * d

hi% = r1.FindHighExponent
r.Divide(r1(hi), precision2)
r.PartSize = hi + r1.PartSize + r.PartSize + lowExp '.PartSize
d.PartSize = -lowExp

Return r
End Function

Private Function GetMagicNr&(a&)

' Magic number or "reciprocal integer" - GET THE 64-BIT NUMBER WHICH, when multiplied by the lowest digit, gives 1 as the remainder of 2^64
' Only for odd numbers.

bt& = 1 'bit tester
d& = a 'bit mask

r& = 0 : i& = 0 : r0& = 0

For i = 0 To 63

If bt And r Then GoTo skip

r += d
r0 = r0 Or bt
skip:
bt <<= 1 : d <<= 1
Next

Return r0
End Function