Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java, BigDecimal. Problems with division

I'm trying to calculate a percentage "factor". That is, given a 20%, convert it into 0.2 (my intention is to later multiply values by that and get the 20% of the values).

Anyway, the question is related with this piece of code:

public static void main(String[] args) {
    int roundingMode = BigDecimal.ROUND_FLOOR;
    BigDecimal hundred = new BigDecimal("100");
    BigDecimal percentageFactor = null;
    BigDecimal percentage = new BigDecimal("20");
    BigDecimal value = new BigDecimal("500");
    percentageFactor = percentage.divide(hundred, roundingMode);
    float f = percentage.floatValue() / hundred.floatValue();
    f = value.floatValue() * f;
    BigDecimal aux = value.multiply(percentageFactor);
    System.out.println("factor:"+percentageFactor.toString());
    System.out.println("final falue:"+aux.toString());
    System.out.println("Float Value:"+f);       
}

I would expect the outcome of this to be something like:

factor: 0.2
final value: 100
float value: 100

but instead percentage.divide(hundred, roundingMode); is returning zero, an hence I get:

factor:0
final falue:0
Float Value:100.0

What am I doing wrong? How can I divide two big decimals properly?

By the way, I'm using BigDecimal because I will be calculating monetary percentages, so I want control regarding rounding.

like image 386
gonso Avatar asked May 25 '09 07:05

gonso


2 Answers

I think that the best solution is to set the requested scale when dividing: In this case perhaps 2.

    var hundred = new BigDecimal(100);
    var percentage = new BigDecimal(20);
    var value = new BigDecimal(500);
    
    var percentageFactor = 
        percentage.divide(hundred,2, BigDecimal.ROUND_HALF_UP);
    
    value = value.multiply(percentageFactor);
    System.out.println("final value:"+ value);

Final value: 100.00

The multiplication is using the scale from the factors (0+2) but it can be specified too.

I'd use ROUND_HALF_UP for accounting (in my legislation) or ROUND_EVEN (for statistics) for rounding mode.

like image 161
KarlP Avatar answered Nov 01 '22 20:11

KarlP


The scale of new BigDecimal("20") is zero because you've got no decimal point in there. That means that your percentage.divide(hundred, BigDecimal.ROUND_FLOOR) will produce zero (it's effectively int(20/100) or 0).

If you really want to do fractional stuff, use new BigDecimal("20.00") so the scale is set correctly, or use one of the other constructors to set the scale specifically.

Here's the output from that simple change of 20 to 20.00, complete with your spellink misteak :-)

factor:0.20
final falue:100.00
Float Value:100.0
like image 22
paxdiablo Avatar answered Nov 01 '22 20:11

paxdiablo