问题
I need to read values from a binary file, the data format is IBM single Precision Floating Point (4-byte Hexadecimal Exponent Data) and use the value as a decimal number. I have C++ code that reads from the file and takes out each byte and stores it like so
unsigned char buf[BUF_LEN];
for (long position = 0; position < fileLength; position += BUF_LEN) {
file.read((char* )(&buf[0]), BUF_LEN);
// printf("\n%8ld: ", pos);
for (int byte = 0; byte < BUF_LEN; byte++) {
// printf(" 0x%-2x", buf[byte]);
}
}
This prints out the hexadecimal values of each byte.
this picture specifies IBM single precision floating point IBM single precision floating point I do not understand what a 24-bit positive binary fraction is. I do know how to convert between hex<->dec<->binary so my basic understanding would be to take all the q's and treat them as one very long binary segment that would use Q24(2)^(23) as the largest value while adding all the preceding values together, and then just times the number by 10^-24 . But my intuition tells me this is wrong. Clarification on what a radix point or MSB is would be helpful.
回答1:
The format is actually quite simple, and not particularly different than IEEE 754 binary32 format (it's actually simpler, not supporting any of the "magic" NaN/Inf values, and having no subnormal numbers, because the mantissa here has an implicit 0 on the left instead of an implicit 1).
As Wikipedia puts it,
The number is represented as the following formula: (−1)sign × 0.significand × 16exponent−64.
If we imagine that the bytes you read are in a uint8_t b[4]
, then the resulting value should be something like:
uint32_t mantissa = (b[1]<<16) | (b[2]<<8) | b[3];
int exponent = (b[0] & 127) - 64;
double ret = mantissa * exp2(-24 + 4*exponent);
if(b[0] & 128) ret *= -1.;
Notice that here I calculated the result in a double
, as the range of a IEEE 754 float
is not enough to represent the same-sized IBM single precision value (also the opposite holds). Also, keep in mind that, due to endian issues, you may have to revert the indexes in my code above.
Edit: @Eric Postpischil correctly points out that, if you have C99 or POSIX 2001 available, instead of mantissa * exp2(-24 + 4*exponent)
you should use ldexp(mantissa, -24 + 4*exponent)
, which should be more precise (and possibly faster) across implementations.
来源:https://stackoverflow.com/questions/45227913/ibm-single-precision-floating-point-data-conversion-to-intended-value