IBM hexadecimal floating-point
IBM 64 bit Floating Point Standard
IBM uses the same basic formula
double = mantissa * base ^ exponent
with the following differences
The manissa has increased at the expence of the exponent:
1 7 56 +-+-----------+----------------------------------------------------+ |S| Exp | Fraction | +-+-----------+----------------------------------------------------+ 63 62 56 55 0
The bias is now 64 because the exponent is smaller. Finally the base in IBM is 16 not 2. This is the same as shifting the exponent by 2 (multiply by 4) but still leaves the IBM exponent slightly smaller than the equivalent in IEEE. IBM does NOT suppress the initial bit. IBM always puts the radix point to the left of the mantissa.
Converting from IBM to/from IEEE
Here is some Java code that has been tested and works for converting IBM to/from IEEE. It does not handle the special cases of NA, and infinities. That should be added eventually
// Thom_Burnett@CognigenCorp.com public static double ibmFloat64ToDouble( long ibmFloat ) { double ieeeDouble = 0; long sign = ibmFloat & MASK_SIGN_64; long mantissaIbm = ibmFloat & MASK_MANT_IBM_64; long exponentIbm = ibmFloat & MASK_EXP_IBM_64; long exponentIeee = exponentIbm ; // The IBM exponent is 7 bits, biased 64, and used with base 64. The IEEE exponent is 11 bits, biased 1023, and used with base 2
// Move the exponent to last part of long so that we can do arithemtic with it.
exponentIeee >>>= IBM_MANTISSA_SIZE ; exponentIeee -= IBM_EXPONENT_BIAS ; exponentIeee *= IEEE_TO_IBM_BASE ; // Change from base 2 -> base 16
long mantissaIeee = mantissaIbm ; while ((mantissaIeee & MASK_IBM_MANTISSA_LEAD_BIT) == 0 ) { mantissaIeee = mantissaIeee << 1 ; // Remove the zero bits exponentIeee -= 1 ; }
// One more time to remove the lead bit mantissaIeee = mantissaIeee << 1 ; // Remove the zero bits exponentIeee -= 1 ; mantissaIeee = mantissaIeee >> IBM_MANTISSA_SIZE - IEEE_MANTISSA_SIZE ; // Move the mantissa from IBM (56th bit) -> IEEE start (52nd bit)
exponentIeee += IEEE_EXPONENT_BIAS ; exponentIeee = exponentIeee << IEEE_MANTISSA_SIZE ; // put it back
long ieeeLong = (sign & MASK_SIGN_64) | (exponentIeee & MASK_EXP_IEEE_64) | (MASK_MANT_IEEE_64 & mantissaIeee) ; ieeeDouble = Double.longBitsToDouble(ieeeLong) ; return ieeeDouble; }
static public long doubleToIbmFloatAsLong(double incomingDouble) { long ieeeDouble = Double.doubleToLongBits(incomingDouble) ;
// Convert the exponent from IEEE to IBM long ieeeExponent = ieeeDouble & MASK_EXP_IEEE_64 ; ieeeExponent = ieeeExponent >>> IEEE_MANTISSA_SIZE ; ieeeExponent = ieeeExponent - IEEE_EXPONENT_BIAS ;
long ibmSign = ieeeDouble & MASK_SIGN_64 ; long ieeeMantissa = ieeeDouble & MASK_MANT_IEEE_64 ;
ieeeMantissa = activateBit(ieeeMantissa, (int)IEEE_MANTISSA_SIZE) ; // Turn on the 1st bit for ibm since it doesn't suppress this bit long mantissaShiftNeededForBase16 = ieeeExponent % IEEE_TO_IBM_BASE ; while(mantissaShiftNeededForBase16 < 0) { mantissaShiftNeededForBase16 += IEEE_TO_IBM_BASE ; } ieeeMantissa = ieeeMantissa << mantissaShiftNeededForBase16 ; // I think there are two conflicting shifts. 4 to the left to move the mantissa // and 4 to the right because IBM using base 16 has smaller mantissas.
long ibmMantissa = ieeeMantissa ; //<< (IBM_MANTISSA_SIZE - IEEE_MANTISSA_SIZE) ; //ibmMantissa = ibmMantissa >> 1 ; // Move right 1 bit to fit the left of radix 1
long ibmExponent = ieeeExponent / IEEE_TO_IBM_BASE ; if(ieeeExponent >= 0) { ibmExponent++ ; // Move up one to cover the suppressed ieee bit }
ibmExponent += IBM_EXPONENT_BIAS ; ibmExponent = ibmExponent << IBM_MANTISSA_SIZE ;
long ibmFloatAsLong = ibmSign | ( ibmExponent & MASK_EXP_IBM_64 ) | ( ibmMantissa & MASK_MANT_IBM_64 ) ; return ibmFloatAsLong ; }