www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Want a function that determines a double or float given its 80-bit

reply dan <dan.hitt gmail.com> writes:
Hi,

I'm parsing some files, each containing (among other things) 10 
bytes said to represent an IEEE 754 extended floating point 
number, in SANE (Standard Apple Numerical Environment) form, as 
SANE existed in the early 1990s (so, big endian).

Note that the number actually stored will probably be a positive 
even integer less than 100,000, so a better format would have 
been to store a two-byte ushort rather than a 10-byte float.  
However the spec chose to have an encoded float there.

I would like to have a function of the form

     public bool ubytes_to_double( ubytes[10] u, out double d ) { 
/* stuff */ }

which would set d to the value encoded provided that the value is 
a number and is sane, and otherwise just return false.

So my plan is just to do this: examine the first 2 bytes to check 
the sign and see how big the number is, and if it is reasonable, 
convert the remaining 8 bytes to a fractional part, perhaps 
ignoring the last 2 or 3 as not being significant.

But --- it seems like this kind of task may be something that d 
already does, maybe with some constructor of a double or 
something.

Thanks in advance for any suggestions.

dan
Aug 22 2023
parent reply z <z z.com> writes:
On Tuesday, 22 August 2023 at 22:38:23 UTC, dan wrote:
 Hi,

 I'm parsing some files, each containing (among other things) 10 
 bytes said to represent an IEEE 754 extended floating point 
 number, in SANE (Standard Apple Numerical Environment) form, as 
 SANE existed in the early 1990s (so, big endian).

 Note that the number actually stored will probably be a 
 positive even integer less than 100,000, so a better format 
 would have been to store a two-byte ushort rather than a 
 10-byte float.  However the spec chose to have an encoded float 
 there.

 I would like to have a function of the form

     public bool ubytes_to_double( ubytes[10] u, out double d ) 
 { /* stuff */ }

 which would set d to the value encoded provided that the value 
 is a number and is sane, and otherwise just return false.

 So my plan is just to do this: examine the first 2 bytes to 
 check the sign and see how big the number is, and if it is 
 reasonable, convert the remaining 8 bytes to a fractional part, 
 perhaps ignoring the last 2 or 3 as not being significant.

 But --- it seems like this kind of task may be something that d 
 already does, maybe with some constructor of a double or 
 something.

 Thanks in advance for any suggestions.

 dan
On 32bit x86 an endianness swap and pointer cast to `real` should be enough.(seems to be the same format but i could be wrong.) Else(afaik `real` on 64 bit x86 is just `double`?) you can always isolate sign mantissa and exponent to three isolated `double` values(cast from integer to `double`) and recalculate(`sign*mantissa*(2^^exponent)` according to wikipedia) the floating point number, since they mostly contain integers precision loss probably won't be a problem.
Aug 22 2023
parent dan <dan.hitt gmail.com> writes:
On Wednesday, 23 August 2023 at 03:24:49 UTC, z wrote:
 On Tuesday, 22 August 2023 at 22:38:23 UTC, dan wrote:
 Hi,

 I'm parsing some files, each containing (among other things) 
 10 bytes said to represent an IEEE 754 extended floating point 
 number, in SANE (Standard Apple Numerical Environment) form, 
 as SANE existed in the early 1990s (so, big endian).

 Note that the number actually stored will probably be a 
 positive even integer less than 100,000, so a better format 
 would have been to store a two-byte ushort rather than a 
 10-byte float.  However the spec chose to have an encoded 
 float there.

 I would like to have a function of the form

     public bool ubytes_to_double( ubytes[10] u, out double d ) 
 { /* stuff */ }

 which would set d to the value encoded provided that the value 
 is a number and is sane, and otherwise just return false.

 So my plan is just to do this: examine the first 2 bytes to 
 check the sign and see how big the number is, and if it is 
 reasonable, convert the remaining 8 bytes to a fractional 
 part, perhaps ignoring the last 2 or 3 as not being 
 significant.

 But --- it seems like this kind of task may be something that 
 d already does, maybe with some constructor of a double or 
 something.

 Thanks in advance for any suggestions.

 dan
On 32bit x86 an endianness swap and pointer cast to `real` should be enough.(seems to be the same format but i could be wrong.) Else(afaik `real` on 64 bit x86 is just `double`?) you can always isolate sign mantissa and exponent to three isolated `double` values(cast from integer to `double`) and recalculate(`sign*mantissa*(2^^exponent)` according to wikipedia) the floating point number, since they mostly contain integers precision loss probably won't be a problem.
Thank you z. My machine is 64-bit and is little-endian but the method you suggest actually gives the right answer in my case. More exactly, a real on my machine is 16-bytes (128 bits), quadruple precision, and it has a sign bit with 15 bits of exponent. But the 80-bit format also has a sign bit with 15 bits of exponent. So all i have to do is declare a real y, cast &y it to ubyte*, and copy the 10 ubytes from the file over its first 10 bytes (but backwards). Then the sign bit and exponent exactly match in position. (The remaining 6 ubytes are left in their initial state because they're way out to the least significant part of the number.) Now, for my final code, i'm not actually doing this because the size of real may be different on another machine, or the exponents may get different sizes due to a different layout, or some other problem. So i just do it by hand (although i'm ignoring the last 4 ubytes since for my usage, ultimately it gets boiled down to a 32-bit integer anyway). And "by hand" is pretty close to what you also mention in your mantissa*2^^exponent expression. Thanks again.
Aug 23 2023