Results 1 to 14 of 14

Thread: Absolute Value of a Float

  1. #1

    Thread Starter
    New Member
    Join Date
    Nov 2019
    Posts
    15

    Absolute Value of a Float

    I want to convert the below c code to VBA. I have attempted but the output is not what it should be. Any suggestions?
    Code:
    01: float myAbs(float x)
    02: {
    03:   // copy and re-interpret as 32 bit integer
    04:   int casted = *(int*) &x;
    05:   // clear highest bit
    06:   casted &= 0x7FFFFFFF;
    07:
    08:   // re-interpret as float
    09:   return *(float*)&casted;
    10: }
    Code:
    Sub AbsF()
    
        Dim x As Double, y As Double, casted As Long
    
        x = -3.14
    
        casted = Int(x) And &H7FFFFFFF
    
        y = x And casted
    
        Debug.Print x, y, casted
    
    End Sub

  2. #2
    PowerPoster
    Join Date
    Feb 2006
    Posts
    22,486

    Re: Absolute Value of a Float

    Just use the intrinsic Abs() function.

    VBA questions belong in the Office/VBA forum.

  3. #3

    Thread Starter
    New Member
    Join Date
    Nov 2019
    Posts
    15

    Re: Absolute Value of a Float

    I know but was trying to implement the ABS logic.

  4. #4
    Frenzied Member
    Join Date
    Feb 2003
    Posts
    1,369

    Re: Absolute Value of a Float

    Code:
    Function myAbs(x As Double) As Double
       'copy and re-interpret as 32 bit integer
       Dim Casted As Integer = CInt(x)
    
       'clear highest bit
       casted = casted And &H7FFFFFFF%
    
       're-interpret as float
       Return CDbl(casted)
    End Function
    I haven't tested it but this direct translation of the C code should work. There isn't much logic to it, all it does is cast a float to an int, zero the sign, and return it as a float again. Perhaps this is of use: https://www.codeproject.com/Articles...Language-Progr?

    EDIT:
    It seems I mixed up vb6 and vb.net. And as pointed out this should be for single precision floating point numbers. So:

    Code:
    Function myAbs(x As Single) As Single
       'copy and re-interpret as 32 bit integer
       Dim casted As Long
       casted = CLng(x)
    
       'clear highest bit
       casted = casted And &H7FFFFFFF&
    
       're-interpret as float
       myAbs = CSng(casted)
    End Function
    Last edited by Peter Swinkels; Jun 15th, 2021 at 05:31 AM.

  5. #5
    PowerPoster
    Join Date
    Feb 2006
    Posts
    22,486

    Re: Absolute Value of a Float

    VB (and VBA) have no cast operations, so for that you'd need to use GetMem8() or PutMem8() calls into msvbvm60 (or something else) on Doubles.

    But then the question is "cast as what?" Currency would be the most obvious.

    But VB doesn't have bitwise boolean operations on any 64-bit type including Currency.

    Sure, with enough fiddling you might come up with something. You might split the Double into two Longs, bit-fiddle, then reassemble them into a Double again.

  6. #6
    PowerPoster
    Join Date
    Feb 2006
    Posts
    22,486

    Re: Absolute Value of a Float

    One possibility:

    Code:
    Option Explicit
    
    Private Type AS_DOUBLE
        Value As Double
    End Type
    
    Private Type AS_2_LONGS
        dwLow As Long
        dwHigh As Long
    End Type
    
    Private Function AbsF(ByVal Value As Double) As Double
        Dim AS_DOUBLE As AS_DOUBLE
        Dim AS_2_LONGS As AS_2_LONGS
    
        AS_DOUBLE.Value = Value
        LSet AS_2_LONGS = AS_DOUBLE
        AS_2_LONGS.dwHigh = AS_2_LONGS.dwHigh And &H7FFFFFFF
        LSet AS_DOUBLE = AS_2_LONGS
        AbsF = AS_DOUBLE.Value
    End Function
    
    Private Sub Main()
        Debug.Print AbsF(-3.84123567E-38)
    End Sub

  7. #7
    PowerPoster
    Join Date
    Feb 2006
    Posts
    22,486

    Re: Absolute Value of a Float

    Note that the sample C code was for a Single.

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

    Re: Absolute Value of a Float

    IMHO, the following is about as direct a translation as you can do.

    Code:
    
    Option Explicit
    Private Declare Function GetMem4 Lib "msvbvm60" (ByRef Source As Any, ByRef Dest As Any) As Long ' Always ignore the returned value, it's useless.
    
    Function myAbs(x As Single) As Single
        ' copy and re-interpret as 32 bit integer
        Dim casted As Long              ' VB6 can't declare and assign in one statement.
        GetMem4 x, casted               ' So, we copy memory as a second step.
        ' clear highest bit
        casted = casted And &H7FFFFFFF  ' VB6 also doesn't have the +? operators so we must state our variable twice.
        ' re-interpret as float
        GetMem4 casted, myAbs           ' And we copy memory to our return value.
    End Function
    
    Private Sub Form_Load()
        Dim n As Single
        n = -1234.56
        Debug.Print myAbs(n)
        Unload Me
    End Sub
    
    Also, IMHO, VB6 does have cast ability (but as functions rather than prefix operators, CLng, CSng, etc). It also has a reference function (VarPtr), but it doesn't allow you to combine all that stuff in a single statement the way C does, so we have to resort to memory copying API functions.

    Also, as noted, VB6 doesn't allow you to both declare and assign in a single statement, so you have to break it into two statements, nor does it have the very nice +=, -=, &= type operators, so you have to repeat the variable name when doing that, but it's the same thing but probably does a bit more work at the machine-code level.

    Also, as mentioned, we've got the Abs() function that does this for us, but the Abs() function does use a variant whereas the above code doesn't so I'm not sure which would be fastest.
    Last edited by Elroy; Jun 15th, 2021 at 05:57 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.

  9. #9

    Thread Starter
    New Member
    Join Date
    Nov 2019
    Posts
    15

    Re: Absolute Value of a Float

    @dilettante; thanks.

  10. #10

    Thread Starter
    New Member
    Join Date
    Nov 2019
    Posts
    15

    Re: Absolute Value of a Float

    @Elroy; can your translation be modified to handle doubles?

  11. #11
    PowerPoster
    Join Date
    Feb 2006
    Posts
    22,486

    Re: Absolute Value of a Float

    Calling VBA.Math.Abs() doesn't necessarily compile to the same code that Abs() does. Some intrinsic calls are more direct than their VBA counterparts and may call strongly-typed runtime entrypoints or even emit inline code. Disassembling a native-compiled test program would tell us though.

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

    Re: Absolute Value of a Float

    Code:
    
    Option Explicit
    
    Private Declare Function GetMem8 Lib "msvbvm60" (ByRef Source As Any, ByRef Dest As Any) As Long ' Always ignore the returned value, it's useless.
    
    Function myAbs(x As Double) As Double
        Dim casted(3) As Integer            ' We use an array to get all 8 bytes and still have something we can AND.
        GetMem8 x, casted(0)                ' Move DOUBLE to array.
        casted(3) = casted(3) And &H7FFF    ' Switch off the Double's sign bit.
        GetMem8 casted(0), myAbs            ' Stuff array into what's returned (as a DOUBLE).
    End Function
    
    Private Sub Form_Load()
        Dim n As Double
        n = -1234.56
        Debug.Print myAbs(n)
        Unload Me
    End Sub
    
    We don't have an 8 byte integer in VB6 (other than a "trick" whereby you can put it in a variant). We do have the Currency type which is 8 bytes, but we can't use the AND operator on those. (Well, we can, but it converts them to LONG to use it, which will possibly cause overflow errors.)

    So, using an array is about the closest we can come to what C would do. We could use either a Byte, Integer, or Long array. I just chose Integer as the AND was easy that way (no type casting for the AND execution).

    I just "knew" we were focusing on the high-bit, so that's what I turned off with the AND.
    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.

  13. #13
    PowerPoster
    Join Date
    Feb 2006
    Posts
    22,486

    Re: Absolute Value of a Float

    As long as we're being goofy, might as well use GetMem1() just to flip 1 bit though:

    Code:
    Option Explicit
    
    Private Declare Sub GetMem1 Lib "msvbvm60" (ByRef Source As Any, ByRef Dest As Any)
    
    Private Function Abs1(ByVal Value As Double) As Double
        Dim UpperByte As Byte
    
        'Fiddling the pointer offset in case of LARGEADDRESSAWARE linking:
        GetMem1 ByVal (VarPtr(Value) Xor &H80000000) + 7 Xor &H80000000, UpperByte
        UpperByte = UpperByte And &H7F
        GetMem1 UpperByte, ByVal (VarPtr(Value) Xor &H80000000) + 7 Xor &H80000000
        Abs1 = Value
    End Function
    
    Private Sub Main()
        Debug.Print Abs1(-3.84123567E-38)
    End Sub

    See http://www.xbeat.net/vbspeed/i_VBVM6Lib.html for an interesting typelib.

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

    Re: Absolute Value of a Float

    And, just for grins, here's the C version of doing it for a double (also with no confusion of the length of the long as an unsigned long should always be 8 bytes).

    Code:
    double myAbsD(double x)
    {
        unsigned long long casted = *(unsigned long long*)&x; // Move double's bits to an unsigned long.
        casted &= 0x7FFFFFFFFFFFFFFF;               // Mask off the double's sign bit.
        return *(double*)&casted;                   // Move unsigned long's bits to "temp" double and return that.
    }
    EDIT: I initially made a mistake. It's the unsigned long long that should always be unambiguous. Also, just as an FYI, depending on the compiler and/or the OS, your original C code may not always work. In some cases, an int will just be two bytes, which won't hold a float.
    Last edited by Elroy; Jun 15th, 2021 at 06:05 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.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width