# Thread: Absolute Value of a Float

1. ## 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```  Reply With Quote

2. ## Re: Absolute Value of a Float

Just use the intrinsic Abs() function.

VBA questions belong in the Office/VBA forum.  Reply With Quote

3. ## Re: Absolute Value of a Float

I know but was trying to implement the ABS logic.  Reply With Quote

4. ## 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```  Reply With Quote

5. ## 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.  Reply With Quote

6. ## 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```  Reply With Quote

7. ## Re: Absolute Value of a Float

Note that the sample C code was for a Single.  Reply With Quote

8. ## 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

Dim n As Single
n = -1234.56
Debug.Print myAbs(n)
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.  Reply With Quote

9. ## Re: Absolute Value of a Float

@dilettante; thanks.  Reply With Quote

10. ## Re: Absolute Value of a Float

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

11. ## 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.  Reply With Quote

12. ## 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

Dim n As Double
n = -1234.56
Debug.Print myAbs(n)
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.  Reply With Quote

13. ## 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

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.  Reply With Quote

14. ## 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.  Reply With Quote

#### Posting Permissions

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