Talen Kylon
Talen Kylon

Reputation: 1958

BigDecimal division is rounding up

I'm trying to calculate the following:

(1 - (1/365)) * (1 - (2/365) = 0.99727528617

I would like to store the entire decimal. Here is my code, but it is giving me an answer of 1:

public BigDecimal probability(int t){
    BigDecimal probT; // holds our probability of a single (1-(t/365))
    BigDecimal result; // holds our result
    result = BigDecimal.ONE; // initialize result to 1

    // for 1 to t-1
    for (int n = 1; n < t; n++){            
        int numerator = n; // numerator the value of n

        int denominator = 365; // denominator 365 

        // numberator / denominator (round down)
        probT = BigDecimal.valueOf(numerator).divide(BigDecimal.valueOf(denominator), RoundingMode.DOWN);

        // 1-answer
        probT = BigDecimal.ONE.subtract(probT);

        // multiply the probabilities together 
        result = result.multiply(probT);

    }
    return result;
}

BigDecimal ans2 = bc.probability(3);
System.out.println("P(3) = " + ans2.toString());  

Output:

P(3) = 1

Upvotes: 1

Views: 2825

Answers (2)

Naruto
Naruto

Reputation: 4329

From the java doc

When a MathContext object is supplied with a precision setting of 0 (for example, MathContext.UNLIMITED), arithmetic operations are exact, as are the arithmetic methods which take no MathContext object. (This is the only behavior that was supported in releases prior to 5.)

As a corollary of computing the exact result, the rounding mode setting of a MathContext object with a precision setting of 0 is not used and thus irrelevant. In the case of divide, the exact quotient could have an infinitely long decimal expansion; for example, 1 divided by 3.

If the quotient has a nonterminating decimal expansion and the operation is specified to return an exact result, an ArithmeticException is thrown. Otherwise, the exact result of the division is returned, as done for other operations.

To fix, you need to do something like this:

   // numberator / denominator (round down)
        probT = BigDecimal.valueOf(numerator).divide(BigDecimal.valueOf(denominator), 10,RoundingMode.DOWN);

where 10 is precision(decimal places precision) and RoundingMode.DOWN is rounding mode

Upvotes: 2

Tunaki
Tunaki

Reputation: 137064

That's because the division you are computing is made with a scale of 0. Quoting the method divide(divisor, roundingMode) Javadoc:

Returns a BigDecimal whose value is (this / divisor), and whose scale is this.scale().

In this case, this.scale() refers to the scale of the numerator, which is 0 because the numerator is BigDecimal.valueOf(n), with n being an integer.

You need to change this division to use divide(divisor, scale, roundingMode) instead and specify the scale you want.

Upvotes: 6

Related Questions