dcsimg
Results 1 to 6 of 6

Thread: Best way to deal with Fractions avoiding VARIANT Type

  1. #1

    Thread Starter
    Frenzied Member some1uk03's Avatar
    Join Date
    Jun 2006
    Location
    London, UK
    Posts
    1,504

    Question 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.



  2. #2
    PowerPoster Arnoutdv's Avatar
    Join Date
    Oct 2013
    Posts
    3,704

    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 ?

  3. #3

    Thread Starter
    Frenzied Member some1uk03's Avatar
    Join Date
    Jun 2006
    Location
    London, UK
    Posts
    1,504

    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.



  4. #4
    PowerPoster Arnoutdv's Avatar
    Join Date
    Oct 2013
    Posts
    3,704

    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

  5. #5
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    6,020

    Re: Best way to deal with Fractions avoiding VARIANT Type

    Ok, here's my 2-cents.

    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^96-1 (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 16-Byte-Variant.  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 Mixed-Endian 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 built-in four decimal points. It's a bit of a stretch to get 20 (base-10) 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 IEEE-quad-precision 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 add-on 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 mid-1970s 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 re-attach those licenses and/or attributions. To all, peace and happiness.

  6. #6
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    6,020

    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 floating-point 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 mid-1970s 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 re-attach 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
  •  



Featured


Click Here to Expand Forum to Full Width