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;
|
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) {
|
||||||
|
|
|
@ -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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue