mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Merge remote-tracking branch
'origin/GP-3775_ghidra1_CorrectSubnormalFloatDecode' (Closes #5647)
This commit is contained in:
commit
a9bd6bc771
2 changed files with 80 additions and 48 deletions
|
@ -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) {
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue