问题
I need to do IBM-IEEE floating point conversions of byte arrays in Java. I was able to successfully do conversions of single-precision float bytes using http://www.thecodingforums.com/threads/c-code-for-converting-ibm-370-floating-point-to-ieee-754.438469.
But I also need to convert bytes of double-precision doubles. Everywhere I look seems to only show the single-precision conversion. The closest I've gotten is the r8ibmieee function in http://spdf.sci.gsfc.nasa.gov/pub/documents/old/miscellaeous_documents_from_nssdc/b46645.txt, but it uses C unions/bitfields and only converts IBM to IEEE (and not the reverse). I was hoping for a solution similar to the first link that takes a byte array or hex string and outputs a byte array or hex string. Does anyone have an algorithm for converting double-precision bytes from IBM to IEEE and vice versa that will work in Java?
回答1:
I've never seen one, but I'll try, after looking at the formats. (https://en.wikipedia.org/wiki/IBM_Floating_Point_Architecture#Double-precision_64-bit; https://en.wikipedia.org/wiki/Double-precision_floating-point_format)
I recommend that you work with long
(64-bit integer) values; it will be much easier. You'll convert a byte array to a long
, work with that to convert the floating-point format, and then convert the resulting long
back to a byte array. I won't tell you how to convert between long
and byte array values, since I don't know whether your byte arrays are little-endian or big-endian.
An IBM 64-bit float has the format
1 sign bit
7 exponent bits (power of 16), bias = 64
56 mantissa bits
If the exponent is X and the mantissa bits are bbbbb...bbbbb, then the value of the float (if the sign bit is 0) is 16^(X-64) * 0.bbbbb...bbbbb.
An IEEE 754 64-bit float has the format
1 sign bit
11 exponent bits (power of 2), bias = 1023
52 mantissa bits, with an implied a bit
If the exponent is X and the mantissa bits are bbbbb...bbbbb, the value of the float (if the sign bit is 0) is 2^(X-1023) * 1.bbbbb...bbbbb.
So now you need to figure out how to express the same value in the IEEE format (as close as possible; it's possible you might lose a few bits of precision, since the IBM mantissa is longer).
The sign bit will be the same in both formats.
To compute an initial value for the IEEE exponent: If the IBM exponent is X1, and the IEEE exponent is X2, we need to find X2 such that 16^(X1-64) = 2^(X2-1023). The left side will be equal to 2^(4*X1-256), so since the powers of 2 must be the same, this gives us X2 = 4*X1-256+1023 = 4*X1+767.
At this point, if the mantissa of the IBM float is bbbbb...bbbbb, the floating-point value is sign * 2^(X2-1023) * 0.bbbbb...bbbbb. However, for an IEEE float, we have to arrange the mantissa bits so that we're multiplying by 1.bbbbb...bbbbb. This means that we need to shift the mantissa bits of the IBM mantissa until we shift a 1 into the bit place to the left of the binary point. Every time we shift the mantissa, we double it, which means that we have to compensate by subtracting 1 from X2. Thus, suppose that after step 2, we have X2=1031 and mantissa = 0011 0111 1100 ... The number we're representing is 28 * 0.001101111100..... We will need to shift the mantissa left 3 places to get the 1 into the bit left of the binary point; the number is thus equal to 25 * 1.101111100.... Thus, X2 after this step will be 1031 - 3 = 1028; that's the value that will go into the exponent field of the IEEE float.
The 1 to the left of the binary point does not go into the IEEE float. It's an "implied 1". The mantissa bits of the IEEE float will be 101111100..... Note that the IBM mantissa has 56 bits; the value you're left with, not counting the implied 1, will still have 56 bits. You will need to chop off the lower 4 bits to get it down to 52 for the IEEE float, and you may want to round.
After all this, you now have the sign bit, the exponent field (X2), and the mantissa bits you need to construct the 64-bit IEEE float.
来源:https://stackoverflow.com/questions/37982757/java-ibm-ieee-double-precision-floating-point-byte-conversion