Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert big hex number (with decimal point) to BigDecimal

Tags:

java

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?

like image 224
Gunjan Aggarwal Avatar asked Dec 01 '14 17:12

Gunjan Aggarwal


People also ask

What is the limit of BigDecimal?

By default, BigDecimal numbers have “unlimited” precision. In fact, the maximum unscaled value is equal to 2^Integer.

How do you find the whole number in BigDecimal?

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.

How does Java handle hexadecimal?

In Java programs, hexadecimal numbers are written by placing 0x before numbers.


1 Answers

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.

like image 162
David Conrad Avatar answered Oct 28 '22 17:10

David Conrad