mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
Merge remote-tracking branch 'origin/GP-1850_ghidra1_BigFloat_Fixes--SQUASHED'
This commit is contained in:
commit
f89cf0c62e
3 changed files with 95 additions and 18 deletions
|
@ -48,16 +48,19 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
int scale;
|
||||
|
||||
/**
|
||||
* Construct a BigFloat. If kind is FINITE, the value is <code>sign*unscaled*2^(scale-fracbits)</code>
|
||||
* Construct a BigFloat. If kind is FINITE, the value is <code>sign*unscaled*2^(scale-fracbits)</code>.
|
||||
* <p>
|
||||
* NOTE: Requires that normal values are constructed in a normal form as with denormal values.
|
||||
*
|
||||
* @param fracbits number of fractional bits
|
||||
* @param expbits maximum number of bits in exponent
|
||||
* @param fracbits number of fractional bits (positive non-zero value)
|
||||
* @param expbits maximum number of bits in exponent (positive non-zero value)
|
||||
* @param kind the Kind, FINITE, INFINITE, ...
|
||||
* @param sign +1 or -1
|
||||
* @param unscaled the value's mantissa
|
||||
* @param scale value's scale
|
||||
* @param unscaled the value's mantissa (bit size <= fracbits+1)
|
||||
* @param scale value's scale (signed value with the biased range of expbits)
|
||||
* @throws IllegalArgumentException if invalid unscaled and scale values are specified based upon the fracbits and expbits values.
|
||||
*/
|
||||
public BigFloat(int fracbits, int expbits, FloatKind kind, int sign, BigInteger unscaled,
|
||||
BigFloat(int fracbits, int expbits, FloatKind kind, int sign, BigInteger unscaled,
|
||||
int scale) {
|
||||
this.fracbits = fracbits;
|
||||
this.expbits = expbits;
|
||||
|
@ -68,6 +71,15 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
|
||||
this.maxScale = (1 << (expbits - 1)) - 1;
|
||||
this.minScale = 1 - this.maxScale;
|
||||
|
||||
if (unscaled.bitLength() > (fracbits + 1)) {
|
||||
throw new IllegalArgumentException("unscaled value exceeds " + (fracbits + 1) +
|
||||
" bits in length (length=" + unscaled.bitLength() + ")");
|
||||
}
|
||||
if (scale < minScale || scale > maxScale) {
|
||||
throw new IllegalArgumentException(
|
||||
"scale out of bounds " + minScale + " to " + maxScale + " (scale=" + scale + ")");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -219,10 +231,28 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if this BigFloat is FINITE and normal
|
||||
* Determine if the state of this BigFloat reflects a normalized value.
|
||||
* <p>NOTE: This method relies on the manner of construction and
|
||||
* only checks for {@link FloatKind#FINITE} and that full size of the
|
||||
* fractional bits is used for the unscaled value.
|
||||
*
|
||||
* @return {@code true} if this BigFloat is FINITE and normal.
|
||||
*/
|
||||
public boolean isNormal() {
|
||||
return kind == FloatKind.FINITE && unscaled.bitLength() >= fracbits + 1;
|
||||
return kind == FloatKind.FINITE && unscaled.bitLength() == (fracbits + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the state of this BigFloat reflects a subnormal/denormal value.
|
||||
* <p>NOTE: This method relies on the manner of construction and
|
||||
* only checks for {@link FloatKind#FINITE} and that the non-zero
|
||||
* unscaled valued does not use all fractional bits.
|
||||
*
|
||||
* @return {@code true} if this BigFloat is FINITE and denormal
|
||||
*/
|
||||
public boolean isDenormal() {
|
||||
return kind == FloatKind.FINITE && !unscaled.equals(BigInteger.ZERO) &&
|
||||
unscaled.bitLength() <= fracbits;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -293,14 +323,22 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
public BigDecimal toBigDecimal() {
|
||||
switch (kind) {
|
||||
case FINITE:
|
||||
// sign * unscaled * 2^(scale-fracbits)
|
||||
if (isZero()) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
int unusedBits = Math.max(unscaled.getLowestSetBit(), 0);
|
||||
BigInteger val = unscaled;
|
||||
int iscale = scale - fracbits;
|
||||
BigDecimal x;
|
||||
if (iscale >= 0) {
|
||||
x = new BigDecimal(unscaled.shiftLeft(iscale));
|
||||
if (iscale >= -unusedBits) {
|
||||
x = new BigDecimal(val.shiftLeft(iscale));
|
||||
}
|
||||
else {
|
||||
x = new BigDecimal(unscaled.multiply(BigInteger.valueOf(5).pow(-iscale)),
|
||||
if (unusedBits > 0) {
|
||||
val = unscaled.shiftRight(unusedBits);
|
||||
iscale += unusedBits;
|
||||
}
|
||||
x = new BigDecimal(val.multiply(BigInteger.valueOf(5).pow(-iscale)),
|
||||
-iscale);
|
||||
}
|
||||
if (sign < 0) {
|
||||
|
@ -941,7 +979,7 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
}
|
||||
|
||||
/**
|
||||
* {@code this=round(this)}
|
||||
* Round this value to the nearest whole number
|
||||
*/
|
||||
public void round() {
|
||||
BigFloat half = new BigFloat(fracbits, expbits, FloatKind.FINITE, +1,
|
||||
|
|
|
@ -253,7 +253,7 @@ public strictfp class FloatFormat {
|
|||
return setSign(res, sgn);
|
||||
}
|
||||
|
||||
public Object getBigZero(boolean sgn) {
|
||||
public BigFloat getBigZero(boolean sgn) {
|
||||
return new BigFloat(frac_size, exp_size, FloatKind.FINITE, sgn ? -1 : +1, BigInteger.ZERO,
|
||||
2 - (1 << (exp_size - 1)));
|
||||
}
|
||||
|
@ -404,11 +404,9 @@ public strictfp class FloatFormat {
|
|||
}
|
||||
else if (exp == maxexponent) {
|
||||
if (frac.signum() == 0) { // Floating point infinity
|
||||
return new BigFloat(frac_size, exp_size, FloatKind.INFINITE, sign, BigInteger.ZERO,
|
||||
maxexponent);
|
||||
return BigFloat.infinity(frac_size, exp_size, sign);
|
||||
}
|
||||
return new BigFloat(frac_size, exp_size, FloatKind.QUIET_NAN, sign, BigInteger.ZERO,
|
||||
maxexponent);
|
||||
return BigFloat.quietNaN(frac_size, exp_size, sign);
|
||||
}
|
||||
|
||||
if (jbitimplied) {
|
||||
|
|
|
@ -17,6 +17,7 @@ package ghidra.pcode.floatformat;
|
|||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -358,4 +359,44 @@ public class BigFloatTest extends AbstractGenericTest {
|
|||
unaryDoubleOpTest(a -> Math.ceil(a), a -> a.ceil());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToBigDecimal() {
|
||||
|
||||
assertEquals(BigDecimal.ZERO, FloatFormat.toBigFloat(0.0d).toBigDecimal());
|
||||
assertEquals(BigDecimal.ONE, FloatFormat.toBigFloat(1.0d).toBigDecimal());
|
||||
assertEquals(BigDecimal.ONE.negate(), FloatFormat.toBigFloat(-1.0d).toBigDecimal());
|
||||
|
||||
assertEquals(new BigDecimal(Double.MIN_VALUE),
|
||||
FloatFormat.toBigFloat(Double.MIN_VALUE).toBigDecimal());
|
||||
assertEquals(new BigDecimal(Double.MIN_NORMAL),
|
||||
FloatFormat.toBigFloat(Double.MIN_NORMAL).toBigDecimal());
|
||||
assertEquals(new BigDecimal(Double.MAX_VALUE),
|
||||
FloatFormat.toBigFloat(Double.MAX_VALUE).toBigDecimal());
|
||||
|
||||
assertEquals(new BigDecimal(0.5d), FloatFormat.toBigFloat(0.5d).toBigDecimal());
|
||||
assertEquals(new BigDecimal(2.5d), FloatFormat.toBigFloat(2.5d).toBigDecimal());
|
||||
assertEquals(new BigDecimal(-0.5d), FloatFormat.toBigFloat(-0.5d).toBigDecimal());
|
||||
assertEquals(new BigDecimal(-2.5d), FloatFormat.toBigFloat(-2.5d).toBigDecimal());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalAndDenormal() {
|
||||
|
||||
BigFloat bf = FloatFormat.toBigFloat(0.0d);
|
||||
assertFalse(bf.isNormal());
|
||||
assertFalse(bf.isDenormal());
|
||||
|
||||
bf = FloatFormat.toBigFloat(Double.MIN_NORMAL);
|
||||
assertTrue(bf.isNormal());
|
||||
assertFalse(bf.isDenormal());
|
||||
|
||||
bf = FloatFormat.toBigFloat(Double.MAX_VALUE);
|
||||
assertTrue(bf.isNormal());
|
||||
assertFalse(bf.isDenormal());
|
||||
|
||||
bf = FloatFormat.toBigFloat(Double.MIN_VALUE);
|
||||
assertFalse(bf.isNormal());
|
||||
assertTrue(bf.isDenormal());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue