2

I am working with subtracting two bigDecimal numbers. Going into the subtraction method they both have non-zero precision but the result has precision=0.

To my knowledge a bigDecimal number with a precision of 0 is impossible. Even 0 has a precision of 1.

The precision is the number of digits in the unscaled value. For instance, for the number 123.45, the precision returned is 5.

(see also BigDecimal, precision and scale) .

The area in question:

BigDecimal test = (centerHP.getReal().subtract(inverseScale));

The centerHP.getReal() returns a bigDecimal that is created from this line

new BigDecimal(Double.toString(center.getReal()))

and for context center.real = -0.79 which is a double.

so it is effectively

new BigDecimal("-0.79")

The inverseScale is simply 1

double scale = 1;

BigDecimal inverseScale = (BigDecimal.ONE.divide(new BigDecimal(Double.toString(scale))));

I expect test to be a bigDecimal with a value of -1.79, the int representation should be -179, with a precision of 3 and a scale of 2. However, immediately following the addition operation in the subtract method in the BigDecimal class, my values are as follows:

right after addition

and test equals:

test value

Note that all other values are correct, it's only the precision that seems to be wrong.

  • 2
    Did you try calling the `precision()` method on the offending object? I don't think there are any guarantees about the values of private fields as shown in a debugger. – Dawood ibn Kareem Apr 14 '19 at 22:48

1 Answers1

4

From the javadoc for this field, 0 means the precision is unknown.

/**
 * The number of decimal digits in this BigDecimal, or 0 if the
 * number of digits are not known (lookaside information).  If
 * nonzero, the value is guaranteed correct.  Use the precision()
 * method to obtain and set the value if it might be 0.  This
 * field is mutable until set nonzero.
 *
 * @since  1.5
 */
private transient int precision;

The method precision() determines the precision lazily.

public int precision() {
    int result = precision;
    if (result == 0) {
        long s = intCompact;
        if (s != INFLATED)
            result = longDigitLength(s);
        else
            result = bigDigitLength(inflate());
        precision = result;
    }
    return result;
}
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • This seems to have solved the problem, after running `test.precision();` the precision of test was set to 3. Still curious why the precision was unknown. – The Chosen Hero Apr 14 '19 at 23:20
  • @TheChosenHero: Determining the precision takes time. So this is only done when requested, and not when the BigDecimal is created. Before it is requested, the internal data member is set to 0 to indicate: *still unknown*. Only **after** querying the precision, the value is determined and stored in the internal member. – Rudy Velthuis Apr 15 '19 at 07:10
  • @TheChosenHero any action which is performed lazily is to save computation. This field might never be needed so not calculating it in advance can save time. BTW String.hashCode() does the same thing and is only calculated on demand (it's default value is 0 before being set which means that is the string hash a hashCode of 0 it will be recalculated every time) – Peter Lawrey Apr 16 '19 at 22:28
  • @PeterLawrey Lawrey alright maybe the precision is not needed for some of the calculations. I'll have to play around with the BigDecimal class more and understand how to use it best. Thanks for the help! – The Chosen Hero Apr 17 '19 at 15:07