mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +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;
|
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 fracbits number of fractional bits (positive non-zero value)
|
||||||
* @param expbits maximum number of bits in exponent
|
* @param expbits maximum number of bits in exponent (positive non-zero value)
|
||||||
* @param kind the Kind, FINITE, INFINITE, ...
|
* @param kind the Kind, FINITE, INFINITE, ...
|
||||||
* @param sign +1 or -1
|
* @param sign +1 or -1
|
||||||
* @param unscaled the value's mantissa
|
* @param unscaled the value's mantissa (bit size <= fracbits+1)
|
||||||
* @param scale value's scale
|
* @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) {
|
int scale) {
|
||||||
this.fracbits = fracbits;
|
this.fracbits = fracbits;
|
||||||
this.expbits = expbits;
|
this.expbits = expbits;
|
||||||
|
@ -68,6 +71,15 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
||||||
|
|
||||||
this.maxScale = (1 << (expbits - 1)) - 1;
|
this.maxScale = (1 << (expbits - 1)) - 1;
|
||||||
this.minScale = 1 - this.maxScale;
|
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
|
@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() {
|
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() {
|
public BigDecimal toBigDecimal() {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case FINITE:
|
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;
|
int iscale = scale - fracbits;
|
||||||
BigDecimal x;
|
BigDecimal x;
|
||||||
if (iscale >= 0) {
|
if (iscale >= -unusedBits) {
|
||||||
x = new BigDecimal(unscaled.shiftLeft(iscale));
|
x = new BigDecimal(val.shiftLeft(iscale));
|
||||||
}
|
}
|
||||||
else {
|
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);
|
-iscale);
|
||||||
}
|
}
|
||||||
if (sign < 0) {
|
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() {
|
public void round() {
|
||||||
BigFloat half = new BigFloat(fracbits, expbits, FloatKind.FINITE, +1,
|
BigFloat half = new BigFloat(fracbits, expbits, FloatKind.FINITE, +1,
|
||||||
|
|
|
@ -253,7 +253,7 @@ public strictfp class FloatFormat {
|
||||||
return setSign(res, sgn);
|
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,
|
return new BigFloat(frac_size, exp_size, FloatKind.FINITE, sgn ? -1 : +1, BigInteger.ZERO,
|
||||||
2 - (1 << (exp_size - 1)));
|
2 - (1 << (exp_size - 1)));
|
||||||
}
|
}
|
||||||
|
@ -404,11 +404,9 @@ public strictfp class FloatFormat {
|
||||||
}
|
}
|
||||||
else if (exp == maxexponent) {
|
else if (exp == maxexponent) {
|
||||||
if (frac.signum() == 0) { // Floating point infinity
|
if (frac.signum() == 0) { // Floating point infinity
|
||||||
return new BigFloat(frac_size, exp_size, FloatKind.INFINITE, sign, BigInteger.ZERO,
|
return BigFloat.infinity(frac_size, exp_size, sign);
|
||||||
maxexponent);
|
|
||||||
}
|
}
|
||||||
return new BigFloat(frac_size, exp_size, FloatKind.QUIET_NAN, sign, BigInteger.ZERO,
|
return BigFloat.quietNaN(frac_size, exp_size, sign);
|
||||||
maxexponent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jbitimplied) {
|
if (jbitimplied) {
|
||||||
|
|
|
@ -17,6 +17,7 @@ package ghidra.pcode.floatformat;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -358,4 +359,44 @@ public class BigFloatTest extends AbstractGenericTest {
|
||||||
unaryDoubleOpTest(a -> Math.ceil(a), a -> a.ceil());
|
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