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;
}
// 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) {
int exp = extractExponentCode(encoding);
if (exp == maxexponent) {
@ -252,8 +237,7 @@ public class FloatFormat {
// set sign bit and return the result if size <= 8
private long setSign(long x, boolean sign) {
if (!sign)
{
if (!sign) {
return x; // Assume bit is already zero
}
long mask = 1;
@ -288,8 +272,7 @@ public class FloatFormat {
public BigFloat getBigZero(boolean sgn) {
return new BigFloat(effective_frac_size, exp_size, FloatKind.FINITE, sgn ? -1 : +1,
BigInteger.ZERO,
2 - (1 << (exp_size - 1)));
BigInteger.ZERO, 2 - (1 << (exp_size - 1)));
}
public BigInteger getBigInfinityEncoding(boolean sgn) {
@ -410,6 +393,16 @@ public class FloatFormat {
// Convert floating point encoding into host's double if size <= 8
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);
int exp = extractExponentCode(encoding);
long frac = extractFractionalCode(encoding);
@ -428,15 +421,42 @@ public class FloatFormat {
return Double.NaN;
}
// Get unbiased scale and normalized mantissa
exp -= bias;
long mantissa = frac << (8 * 8 - frac_size);
if (!subnormal && jbitimplied) {
mantissa >>= 1; // Make room for 1 jbit
mantissa |= 0x8000000000000000L; // set bit in at top of normalized frac
long msbit = 1 << (frac_size - 1); // most-significant fractional/mantissa bit
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) {

View file

@ -32,21 +32,6 @@ public class FloatFormatTest extends AbstractGenericTest {
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
public void testGetEncodingMinval() {
FloatFormat ff = new FloatFormat(4);
@ -269,6 +254,30 @@ public class FloatFormatTest extends AbstractGenericTest {
Assert.assertEquals(intbits, encoding.longValue());
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;
intbits = Float.floatToRawIntBits(f);
big = ff.getBigFloat(f);
@ -430,6 +439,12 @@ public class FloatFormatTest extends AbstractGenericTest {
Assert.assertEquals(intbits, encoding);
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;
intbits = Float.floatToRawIntBits(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
// doTestValueOfBigInteger(BigDecimal.valueOf(Double.MAX_VALUE));
BigFloat bf = ff.decodeBigFloat(Double.doubleToRawLongBits(Double.MAX_VALUE));
bf = ff.getBigFloat(bf.toBigInteger());
assertEquals("1.797693134862316E+308", ff.toDecimalString(bf));
@ -1640,14 +1654,12 @@ public class FloatFormatTest extends AbstractGenericTest {
ff.toDecimalString(ff.decodeBigFloat(0x0065006700610050L)));
assertEquals("2.123456789012346",
ff.toDecimalString(ff.decodeBigFloat(0x4000FCD6E9BA37B3L)));
assertEquals("0.3",
ff.toDecimalString(ff.decodeBigFloat(0x3FD3333333333333L)));
assertEquals("0.3", ff.toDecimalString(ff.decodeBigFloat(0x3FD3333333333333L)));
}
@Test
public void testFloatDecodeWithToString() {
FloatFormat ff = FloatFormatFactory.getFloatFormat(4);
assertEquals("-1.4682312",
ff.toDecimalString(ff.decodeBigFloat(0xbfbbef00L), true));
assertEquals("-1.4682312", ff.toDecimalString(ff.decodeBigFloat(0xbfbbef00L), true));
}
}