Working with floating point numbers.

G

Guest

Hi all,

I hope you don't mind me lauching straight into a question. Thanks for a
great forum, I have picked up a few good tips here! :)

Anyhow, here is my question:-
I am loading information from an array of bytes and then immediately storing
the information. In this information are bytes sequences representing Single
(4 bytes) and Double (8 byte) values. I wish to avoid calculating the
floating point numbers only to immediately save them and not use them.

For instance I know the four hexidecimal bytes C2 ED 40 00 represents
-118.625 but I just want to save the bytes into a double field. Now when I
try to use the CDbl("&HC2ED4000") functionI only get the number as an integer
rather than the floating point. Can anybody help with a sugestion?

Also in the future I thiink that I'll have to reverse the situation and
convert a double to a string of hexideciamal numbers. I am sure the internals
of Access must do this stuff all the time but I am just ignorant of how to
access the functionality.

Any help would be much appreciated,

Cheers and Happy Presidents day to our US buddies!,
Andrew
Australia
 
G

Guest

Thanks for taking the time to reply Albert,

however by using the hex function Access has rounded the number to -119 and
then expressed the number as hexidecimal integer. This is not an IEEE 754
conversion. It is just a rounding process that results in a hex integer.

It is interesting to note that Access treats it as an extra long integer (8
bytes) which is also unsupported as a data type to end users. (ie we can only
use Integer (2 bytes) or long (4 bytes).
I really need something that changes the "context" of the four bytes to
double (rather than integer). I've tried using the address (byref) technique
but that still is no good as Access seems to store the datatype with the
data. I guess this is the essence of what I need to do, that is change the
datatype of the variable without touching the data.

You link points to university level descriptions of the numerical issues
with floating point so unfortunately is also no what I'm after.
 
J

John Nurick

Hi Andrew,

A few disconnected thoughts:

Some languages let you do this sort of thing by declaring two variables
at the same address - e.g. a Double and an 8-byte array of Char. You can
then write your 8-byte slice into the array variable and immediately
retrieve the Double value from the Double variable.

VBA offers a very restricted version of this: you declare two custom
Types containing the variable types you need, and can then use the
obscure LSet statement to map one to the other. E.g.:

Type MyFloats
S As Single
D As Double
End Type
Type MyStrings
S As String * 4
D As String * 8
End Type

Sub Test32()
Dim F As MyFloats
Dim S As MyStrings
Dim ArBytes(3) As Byte

'Bytes are C2 ED 40 00, but must reverse order!
ArBytes(0) = &H0
ArBytes(1) = &H40
ArBytes(2) = &HED
ArBytes(3) = &HC2

S.S = ArBytes()
LSet F = S
Debug.Print F.S

End Sub

Alternatively, if it fits your workflow, you might consider
preprocessing your input with a Perl script that uses the powerful
unpack() function to convert your sequence of bytes into decimal string
representations of the numbers of the binary numbers.
 
A

Albert D.Kallal

You link points to university level descriptions of the numerical issues
with floating point so unfortunately is also no what I'm after.

yes..but it did/does explain the format of foats (and, to be honest..I did
not know that format).

I guess this is the essence of what I need to do, that is change the
datatype of the variable without touching the data.

Yes.....now that you point this out..we really don't have to parse out the
hex values from binary (hex) to float decimal.
(I was thining along of grabbing bytes..and then ^ 2 for each nibble, or
byte...

So, all we really have to do is stuff our pattern into somthing in
memory..and yank it back out (great of you to point this out!!!)

ok...you *can* do this!!!, but ONLY on user defined data types....

So, create a brand new module.....(call it whaqtever you want.)

paste the follwing code into the module
Option Compare Database
Option Explicit

Type FloatType
F As Single
End Type

Type LongType
L As Long
End Type

Public Function FloatToHex(dblValue As Double) As String

Dim MyFloat As FloatType
Dim MyLong As LongType

MyFloat.F = dblValue
LSet MyLong = MyFloat

FloatToHex = Hex$(MyLong.L)

End Function

Public Function HexToFloat(strHex As String) As Double

Dim MyFloat As FloatType
Dim MyLong As LongType


MyLong.L = CDbl("&H" + strHex)
LSet MyFloat = MyLong

HexToFloat = MyFloat.F

End Function


in the debug window...i test as

? floattohex(-118.625)
C2ED4000

and

? hextofloat("C2ED4000")
-118.625
 
G

Guest

Thanks Albert,

The LSet statment does the trick nicely! Very happy here!

Greatly appreciated,
Andrew
 
G

Guest

Thank you John,

The LSet method is prefect for what I want. Once again VBA manages to come
through again for me!

Cheers,
Andrew
 
G

Guest

Hi John,

Thank you again for this technique. I have been going great guns with this
mechanism but now need to reverse the situation and convert a double to the
array. This can be done with a single easily enough but not with a double.

I have reversed the code but come stuck when I try to assign the array to
string and Access gives the can't assign to array error.

ie in terms of belows code
the ArBytes()=S.S is giving the problem.

I've tried to Asc(Mid$(S.S,...,1)) the string but it didn't work and when I
print out the array it is wrong.

I'm figuring a bit shift command onto the single approximate number might be
my next option. Ie to play around with mantissa and bias bits of the single
float to double float but this doesn't seem like the most elegant solution
and I don't think Access has the bit manipulation commands in any case.

Would you have any suggestions please?

All the best,
Andrew
 
G

Guest

Argh,

the difficult part is to decide to use ones brain!

For those interested the solution is as follows:-

Option Compare Database
Option Explicit

Type DoubleFloatType
F As Double
End Type

Type EightByteType
Byte1 As Byte
Byte2 As Byte
Byte3 As Byte
Byte4 As Byte
Byte5 As Byte
Byte6 As Byte
Byte7 As Byte
Byte8 As Byte
End Type

Public Function DoubleFloatTo8Bytes(DblValue As Double) As EightByteType
Dim MyFloat As DoubleFloatType
Dim Bytes8 As EightByteType

MyFloat.F = DblValue
LSet Bytes8 = MyFloat
DoubleFloatTo8Bytes.Byte1 = Bytes8.Byte8
DoubleFloatTo8Bytes.Byte2 = Bytes8.Byte7
DoubleFloatTo8Bytes.Byte3 = Bytes8.Byte6
DoubleFloatTo8Bytes.Byte4 = Bytes8.Byte5
DoubleFloatTo8Bytes.Byte5 = Bytes8.Byte4
DoubleFloatTo8Bytes.Byte6 = Bytes8.Byte3
DoubleFloatTo8Bytes.Byte7 = Bytes8.Byte2
DoubleFloatTo8Bytes.Byte8 = Bytes8.Byte1

End Function
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top