I have a big number in hex format (with decimal point) in a String
and I want to convert it to a BigDecimal.
Example value: 0xcc.ccdp+1600
In BigDecimal
class, I don't see any function which takes string representing number in hex format as input and returns corresponding BigDecimal.
Is there a way to convert a big hex number from String
to BigDecimal?
By default, BigDecimal numbers have “unlimited” precision. In fact, the maximum unscaled value is equal to 2^Integer.
intValue() is an in-built function which converts this BigDecimal to an integer value. This function discards any fractional part of this BigDecimal. If the result of the conversion is too big to be represented as an integer value, the function returns only the lower-order 32 bits.
In Java programs, hexadecimal numbers are written by placing 0x before numbers.
I'm surprised that BigDecimal
doesn't already support this. I wrote the following, which I think should work. It passes my initial tests (with 0xcc.ccdp+0
, 0xcc.ccdp+1
, 0xcc.ccdp+16
, 0xcc.ccdp+256
, and your 0xcc.ccdp+1600
, and also some negative exponents, from -1
down to -16
), but it should be tested more thoroughly before being used in production code.
private final static BigInteger TWO = BigInteger.valueOf(2);
private final static BigDecimal MINUS_ONE = new BigDecimal(-1);
public static BigDecimal toBigDecimal(String hex) {
// handle leading sign
BigDecimal sign = null;
if (hex.startsWith("-")) {
hex = hex.substring(1);
sign = MINUS_ONE;
} else if (hex.startsWith("+")) {
hex = hex.substring(1);
}
// constant must start with 0x or 0X
if (!(hex.startsWith("0x") || hex.startsWith("0X"))) {
throw new IllegalArgumentException(
"not a hexadecimal floating point constant");
}
hex = hex.substring(2);
// ... and end in 'p' or 'P' and an exponent
int p = hex.indexOf("p");
if (p < 0) p = hex.indexOf("P");
if (p < 0) {
throw new IllegalArgumentException(
"not a hexadecimal floating point constant");
}
String mantissa = hex.substring(0, p);
String exponent = hex.substring(p+1);
// find the hexadecimal point, if any
int hexadecimalPoint = mantissa.indexOf(".");
int hexadecimalPlaces = 0;
if (hexadecimalPoint >= 0) {
hexadecimalPlaces = mantissa.length() - 1 - hexadecimalPoint;
mantissa = mantissa.substring(0, hexadecimalPoint) +
mantissa.substring(hexadecimalPoint + 1);
}
// reduce the exponent by 4 for every hexadecimal place
int binaryExponent = Integer.valueOf(exponent) - (hexadecimalPlaces * 4);
boolean positive = true;
if (binaryExponent < 0) {
binaryExponent = -binaryExponent;
positive = false;
}
BigDecimal base = new BigDecimal(new BigInteger(mantissa, 16));
BigDecimal factor = new BigDecimal(TWO.pow(binaryExponent));
BigDecimal value = positive? base.multiply(factor) : base.divide(factor);
if (sign != null) value = value.multiply(sign);
return value;
}
I've released this on github under the MIT license. There are unit tests, but only a pretty minimal set.
If you find any cases for which this returns an incorrect value, please let me know.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With