Merge remote-tracking branch

'origin/GP-3775_ghidra1_CorrectSubnormalFloatDecode' (Closes #5647)
This commit is contained in:
ghidra1 2023-08-24 18:14:26 -04:00
commit a9bd6bc771
2 changed files with 80 additions and 48 deletions

View file

@ -169,21 +169,6 @@ public class FloatFormat {
return minValue; return minValue;
} }
// Create a double given sign, 8-byte normalized mantissa, and unbiased scale
static double createDouble(boolean sgn, long mantissa, int scale) {
long exp = scale + 1023;
long bits = mantissa >>> 11;// 11 = 64 (long size) - 52 (frac size) - 1 (jbit))
if (exp != 1) { // normal
bits &= 0xfffffffffffffL;
bits |= exp << 52;
}
if (sgn) {
bits |= 0x8000000000000000L;
}
return Double.longBitsToDouble(bits);
}
FloatKind extractKind(long encoding) { FloatKind extractKind(long encoding) {
int exp = extractExponentCode(encoding); int exp = extractExponentCode(encoding);
if (exp == maxexponent) { if (exp == maxexponent) {
@ -252,8 +237,7 @@ public class FloatFormat {
// set sign bit and return the result if size <= 8 // set sign bit and return the result if size <= 8
private long setSign(long x, boolean sign) { private long setSign(long x, boolean sign) {
if (!sign) if (!sign) {
{
return x; // Assume bit is already zero return x; // Assume bit is already zero
} }
long mask = 1; long mask = 1;
@ -288,8 +272,7 @@ public class FloatFormat {
public BigFloat getBigZero(boolean sgn) { public BigFloat getBigZero(boolean sgn) {
return new BigFloat(effective_frac_size, exp_size, FloatKind.FINITE, sgn ? -1 : +1, return new BigFloat(effective_frac_size, exp_size, FloatKind.FINITE, sgn ? -1 : +1,
BigInteger.ZERO, BigInteger.ZERO, 2 - (1 << (exp_size - 1)));
2 - (1 << (exp_size - 1)));
} }
public BigInteger getBigInfinityEncoding(boolean sgn) { public BigInteger getBigInfinityEncoding(boolean sgn) {
@ -410,6 +393,16 @@ public class FloatFormat {
// Convert floating point encoding into host's double if size <= 8 // Convert floating point encoding into host's double if size <= 8
public double decodeHostFloat(long encoding) { public double decodeHostFloat(long encoding) {
if (size == 8) { // assume IEEE-754 8-byte format which matches Java double encoding
return Double.longBitsToDouble(encoding);
}
if (size > 8) {
throw new UnsupportedOperationException(
"method not supported for float size of " + size);
}
boolean sgn = extractSign(encoding); boolean sgn = extractSign(encoding);
int exp = extractExponentCode(encoding); int exp = extractExponentCode(encoding);
long frac = extractFractionalCode(encoding); long frac = extractFractionalCode(encoding);
@ -428,15 +421,42 @@ public class FloatFormat {
return Double.NaN; return Double.NaN;
} }
// Get unbiased scale and normalized mantissa
exp -= bias; exp -= bias;
long mantissa = frac << (8 * 8 - frac_size);
if (!subnormal && jbitimplied) { long msbit = 1 << (frac_size - 1); // most-significant fractional/mantissa bit
mantissa >>= 1; // Make room for 1 jbit
mantissa |= 0x8000000000000000L; // set bit in at top of normalized frac if (!subnormal && !jbitimplied) {
frac &= ~msbit; // remove explicit jbit
frac <<= 1;
--exp;
} }
return createDouble(sgn, mantissa, exp); if (subnormal) {
// attempt to normalize
exp = -bias;
while (exp > -1023 && (frac & msbit) == 0 && frac != 0) {
frac <<= 1;
--exp;
}
// establish implied jbit
if (exp > -1023 && (frac & msbit) != 0 && frac != 0) {
frac <<= 1;
}
else {
--exp;
}
// mask-off implied jbit
frac &= ~-(1 << frac_size);
}
exp += 1023;
frac <<= 52 - frac_size;
long encodedDouble = (sgn ? (1L << 63) : 0) | ((long) exp << 52) | frac;
return Double.longBitsToDouble(encodedDouble);
} }
public BigFloat decodeBigFloat(BigInteger encoding) { public BigFloat decodeBigFloat(BigInteger encoding) {

View file

@ -32,21 +32,6 @@ public class FloatFormatTest extends AbstractGenericTest {
super(); super();
} }
@Test
public void testCreateFloat() {
int i = 0;
for (double x : BigFloatTest.testDoubleList) {
if (!Double.isFinite(x)) {
continue;
}
FloatFormat.SmallFloatData data = FloatFormat.getSmallFloatData(x);
double y = FloatFormat.createDouble(data.sign < 0,
data.unscaled << (64 - data.fracbits), data.scale);
Assert.assertEquals("case #" + Integer.toString(i), x, y, 0);
++i;
}
}
@Test @Test
public void testGetEncodingMinval() { public void testGetEncodingMinval() {
FloatFormat ff = new FloatFormat(4); FloatFormat ff = new FloatFormat(4);
@ -269,6 +254,30 @@ public class FloatFormatTest extends AbstractGenericTest {
Assert.assertEquals(intbits, encoding.longValue()); Assert.assertEquals(intbits, encoding.longValue());
Assert.assertEquals(big, ff.decodeBigFloat(encoding)); Assert.assertEquals(big, ff.decodeBigFloat(encoding));
big = ff.getBigFloat(Float.MIN_VALUE);
encoding = ff.getEncoding(big);
intbits = Float.floatToRawIntBits(Float.MIN_VALUE);
Assert.assertEquals(intbits, encoding.longValue());
Assert.assertEquals(Float.MIN_VALUE, (float) ff.decodeHostFloat(intbits), 0);
big = ff.getBigFloat(Float.MAX_VALUE);
encoding = ff.getEncoding(big);
intbits = Float.floatToRawIntBits(Float.MAX_VALUE);
Assert.assertEquals(intbits, encoding.longValue());
Assert.assertEquals(Float.MAX_VALUE, (float) ff.decodeHostFloat(intbits), 0);
big = ff.getBigFloat(-Float.MIN_VALUE);
encoding = ff.getEncoding(big);
intbits = Float.floatToRawIntBits(-Float.MIN_VALUE);
Assert.assertEquals(intbits, (int) encoding.longValue());
Assert.assertEquals(-Float.MIN_VALUE, (float) ff.decodeHostFloat(intbits), 0);
big = ff.getBigFloat(-Float.MAX_VALUE);
encoding = ff.getEncoding(big);
intbits = Float.floatToRawIntBits(-Float.MAX_VALUE);
Assert.assertEquals(intbits, (int) encoding.longValue());
Assert.assertEquals(-Float.MAX_VALUE, (float) ff.decodeHostFloat(intbits), 0);
f = 3.75f; f = 3.75f;
intbits = Float.floatToRawIntBits(f); intbits = Float.floatToRawIntBits(f);
big = ff.getBigFloat(f); big = ff.getBigFloat(f);
@ -430,6 +439,12 @@ public class FloatFormatTest extends AbstractGenericTest {
Assert.assertEquals(intbits, encoding); Assert.assertEquals(intbits, encoding);
Assert.assertEquals(f, (float) ff.decodeHostFloat(encoding), 0); Assert.assertEquals(f, (float) ff.decodeHostFloat(encoding), 0);
intbits = 1; // smallest subnormal value
Assert.assertEquals(Float.MIN_VALUE, (float) ff.decodeHostFloat(intbits), 0);
intbits = 0x80000001; // smallest subnormal value
Assert.assertEquals(-Float.MIN_VALUE, (float) ff.decodeHostFloat(intbits), 0);
f = 8.908155E-39f; f = 8.908155E-39f;
intbits = Float.floatToRawIntBits(f); intbits = Float.floatToRawIntBits(f);
encoding = ff.getEncoding(f); encoding = ff.getEncoding(f);
@ -1477,7 +1492,6 @@ public class FloatFormatTest extends AbstractGenericTest {
// NOTE: BigDecimal.valueOf(Double.MAX_VALUE) produces a value greater than Double.MAX_VALUE // NOTE: BigDecimal.valueOf(Double.MAX_VALUE) produces a value greater than Double.MAX_VALUE
// doTestValueOfBigInteger(BigDecimal.valueOf(Double.MAX_VALUE)); // doTestValueOfBigInteger(BigDecimal.valueOf(Double.MAX_VALUE));
BigFloat bf = ff.decodeBigFloat(Double.doubleToRawLongBits(Double.MAX_VALUE)); BigFloat bf = ff.decodeBigFloat(Double.doubleToRawLongBits(Double.MAX_VALUE));
bf = ff.getBigFloat(bf.toBigInteger()); bf = ff.getBigFloat(bf.toBigInteger());
assertEquals("1.797693134862316E+308", ff.toDecimalString(bf)); assertEquals("1.797693134862316E+308", ff.toDecimalString(bf));
@ -1640,14 +1654,12 @@ public class FloatFormatTest extends AbstractGenericTest {
ff.toDecimalString(ff.decodeBigFloat(0x0065006700610050L))); ff.toDecimalString(ff.decodeBigFloat(0x0065006700610050L)));
assertEquals("2.123456789012346", assertEquals("2.123456789012346",
ff.toDecimalString(ff.decodeBigFloat(0x4000FCD6E9BA37B3L))); ff.toDecimalString(ff.decodeBigFloat(0x4000FCD6E9BA37B3L)));
assertEquals("0.3", assertEquals("0.3", ff.toDecimalString(ff.decodeBigFloat(0x3FD3333333333333L)));
ff.toDecimalString(ff.decodeBigFloat(0x3FD3333333333333L)));
} }
@Test @Test
public void testFloatDecodeWithToString() { public void testFloatDecodeWithToString() {
FloatFormat ff = FloatFormatFactory.getFloatFormat(4); FloatFormat ff = FloatFormatFactory.getFloatFormat(4);
assertEquals("-1.4682312", assertEquals("-1.4682312", ff.toDecimalString(ff.decodeBigFloat(0xbfbbef00L), true));
ff.toDecimalString(ff.decodeBigFloat(0xbfbbef00L), true));
} }
} }