
Jan 16th, 2020, 08:41 AM
#1
Thread Starter
Frenzied Member
Best way to deal with Fractions avoiding VARIANT Type
Just thinking of a way to optimise my code.
I'm currently dealing with lot's of fractions that need to be up to 20 decimal points!!!
I've managed to handle this with VB's VARIANT dataType but that has a huge hit on speed once I run a Loop with many calculations.
What alternatives would there be do accurately deal with LONGLONG/CDec64 in VB + Fractions/Decimal Points.
_____________________________________________________________________
If this post has helped you. Please take time to Rate it.
If you've solved your problem, then please mark it as RESOLVED from Thread Tools.

Jan 16th, 2020, 09:57 AM
#2
Re: Best way to deal with Fractions avoiding VARIANT Type
Are the values indeed with an accuracy of 20 numbers?
So like 0.123456789012334567890 or even numbers like 9876543210.123456789012334567890 ?

Jan 16th, 2020, 10:07 AM
#3
Thread Starter
Frenzied Member
Re: Best way to deal with Fractions avoiding VARIANT Type
More like: 0.123456789012334567890
_____________________________________________________________________
If this post has helped you. Please take time to Rate it.
If you've solved your problem, then please mark it as RESOLVED from Thread Tools.

Jan 16th, 2020, 11:17 AM
#4
Re: Best way to deal with Fractions avoiding VARIANT Type
I thinks it's going to be hard to beat the variant/decimal calculation with self written floating point algoritmes.
The difference between Double vs Variant calculations:
Code:
Compiled, no optimizations:
Variant: 4897ms
Double: 1641ms
Compiled, all possible optimizations:
Variant: 4756ms
Double: 610ms
So without optimizations the difference is a factor 2.9, with optimizations a factor 7.8
Code:
Option Explicit
Private Declare Function GetTickCount Lib "kernel32" () As Long
Private Sub Command1_Click()
Dim l1 As Long, l2 As Long
l1 = pCalcVariant
l2 = pCalcDouble
MsgBox "Variant: " & CStr(l1) & "ms" & vbLf & "Double: " & CStr(l2) & "ms"
End Sub
Private Function pCalcVariant() As Long
Dim v As Variant, v1 As Variant
Dim i As Long, j As Long
Dim t As Long
Dim tLoop As Long
t = GetTickCount
For i = 0 To 9999999
Next i
tLoop = 10 * (GetTickCount  t)
v1 = CDec("1,123456789012334567890")
t = GetTickCount
For j = 1 To 10
v = v1
For i = 0 To 9999999
v = v * v
v = v / 2
Next i
Next j
pCalcVariant = GetTickCount  t  tLoop
End Function
Private Function pCalcDouble() As Long
Dim v As Double, v1 As Double
Dim i As Long, j As Long
Dim t As Long
Dim tLoop As Long
t = GetTickCount
For i = 0 To 9999999
Next i
tLoop = 10 * (GetTickCount  t)
v1 = CDbl("1,123456789012334567890")
t = GetTickCount
For j = 1 To 10
v = v1
For i = 0 To 9999999
v = v * v
v = v / 2
Next i
Next j
pCalcDouble = GetTickCount  t  tLoop
End Function

Jan 16th, 2020, 12:38 PM
#5
Re: Best way to deal with Fractions avoiding VARIANT Type
Ok, here's my 2cents.
First, it's not my experience that the use of Variants is any "huge hit" on performance. However, I think we need to be more specific. If we're using Variants to hold a Decimal type, then you might get a substantial hit on performance, particularly if you're doing lots of math with these Decimals. Here's the structure of a Decimal:
Code:
Private Type DecimalStructure ' (when sitting in a Variant)
'
' Largest Decimal: +/ 79228162514264337593543950335. 2^961 (sign bit handled separately)
' Smallest Decimal: +/ 0.0000000000000000000000000001 Notice that both largest and smallest are same width.
'
VariantType As Integer ' Reserved, to act as the Variant Type when sitting in a 16ByteVariant. Equals vbDecimal(14) when it's a Decimal type.
Base10NegExp As Byte ' Base 10 exponent (0 to 28), moving decimal to right (smaller numbers) as this value goes higher. Top three bits are never used.
sign As Byte ' Sign bit only. Other bits aren't used.
Hi32 As Long ' Mantissa.
Lo32 As Long ' Mantissa.
Mid32 As Long ' Mantissa.
End Type
Now, one thing to notice is that it's got a MixedEndian byte order. That's just horrible for doing math, and it also tells us that there's software involved in getting any math done.
Now, another option is to use the Currency type, and possibly have an implicit understanding with yourself that you're going to treat them as if they've got more than the builtin four decimal points. It's a bit of a stretch to get 20 (base10) decimal points with a Currency. But, we could get, say, 14 somewhat easily. We'd just multiply our input numbers by 10000000000 going in, and divide out output numbers by 10000000000 when they come back out.
Currency ranges from 922,337,203,685,477.5808 to 922,337,203,685,477.5807. So, with that suggestion, your numbers could range from 92233.72036854775808 to 92233.72036854775807. If the integer portion of your numbers was always small, you could stretch those decimal points to 18 using Currency.
Also, even if you did go the Currency route, you may have to use Variant_Decimal going in and out, so you don't lose precision in that process. However, the Currency math would be quite fast as it'd mostly be done in hardware registers (particularly +  * /).
Beyond those suggestions, you're probably going to need some library that can do IEEEquadprecision for you.
Good Luck,
Elroy
EDIT1: Out of curiousity, I took at look at the current state of the FPU unit in modern CPUs. Apparently the Quad Precision hasn't really caught on that much, and isn't an option in most CPUs. This means that IEEE Quad math is going to be done in software, which will be a substantial slowdown. There are some addon quad FPU hardware devices, but you'd have to be sure and utilize the software library that came with those to utilize them. If your software is to be distributed, I doubt that's a good option. So, the quad precision doesn't really look like a great option. You may do better to just stick with Variant_Decimals.
Last edited by Elroy; Jan 16th, 2020 at 01:51 PM.
Any software I post in these forums written by me is provided “AS IS” without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. Please understand that I’ve been programming since the mid1970s and still have some of that code. My contemporary VB6 project is approaching 1,000 modules. In addition, I have a “VB6 random code folder” that is overflowing. I’ve been at this long enough to truly not know with absolute certainty from whence every single line of my code has come, with much of it coming from programmers under my employ who signed intellectual property transfers. I have not deliberately attempted to remove any licenses and/or attributions from any software. If someone finds that I have inadvertently done so, I sincerely apologize, and, upon notice and reasonable proof, will reattach those licenses and/or attributions. To all, peace and happiness.

Jan 16th, 2020, 01:31 PM
#6
Re: Best way to deal with Fractions avoiding VARIANT Type
Regarding the use of the LongLong data type, here's a thread that discusses that. However, if you're thinking about it for floatingpoint fractions, there's hardly any advantage to just using Currency. Currency and LongLong are basically the same thing, with the only difference is that Currency has a decimal point "plunked" into it at the fourth decimal when it's reported. If you're going to multiply/divide by a factor when going in/out, why not just appreciate the four decimal points in the factor (as I did above).
Any software I post in these forums written by me is provided “AS IS” without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. Please understand that I’ve been programming since the mid1970s and still have some of that code. My contemporary VB6 project is approaching 1,000 modules. In addition, I have a “VB6 random code folder” that is overflowing. I’ve been at this long enough to truly not know with absolute certainty from whence every single line of my code has come, with much of it coming from programmers under my employ who signed intellectual property transfers. I have not deliberately attempted to remove any licenses and/or attributions from any software. If someone finds that I have inadvertently done so, I sincerely apologize, and, upon notice and reasonable proof, will reattach those licenses and/or attributions. To all, peace and happiness.
Tags for this Thread
Posting Permissions
 You may not post new threads
 You may not post replies
 You may not post attachments
 You may not edit your posts

Forum Rules

Click Here to Expand Forum to Full Width
