开发者

The Java BigDecimal vs The Financial Mans - "The 1 cent problem"

I have this problem: The financial mans says: "Error of your programation".

The official table of values and final calc from financial is

base        %              total value
667.63   -  1.5(0.015)   = 657.62
705.98   -  1.5(0.015)   = 695.39
687.77   -  1.5(0.015)   = 677.45
844.62   -  1.5(0.015)   = 831.95
743.23   -  1.5(0.015)   = 732.08
775.15   -  1.5(0.015)   = 763.52
874.82   -  1.5(0.015)   = 861.70
949.63   -  1.5(0.015)   = 935.39
987.18   -  1.5(0.015)   = 972.37
1040.28  -  1.5(0.015)   = 1024.68
1077.70  -  1.5(0.015)   = 1061.54
995.68   -  1.5(0.015)   = 980.74
1280.55  -  1.5(0.015)   = 1261.35
1140.56  -  1.5(0.015)   = 1123.45
653.23   -  1.5(0.015)   = 643.43
847.49   -  1.5(0.015)   = 834.78
995.68   -  1.5(0.015)   = 980.74

My function's return value must match the total value from that table:

public static void main(String[] args) {
    BigDecimal[] valorbase= {
        new BigDecimal("667.63"),
        new BigDecimal("705.98"),
        new BigDecimal("687.77"),
        new BigDecimal("844.62"),
        new BigDecimal("743.23"),
        new BigDecimal("775.15"),
        new BigDecimal("874.82"),
        new BigDecimal("949.63"),
        new BigDecimal("987.18"),
        new BigDecimal("1040.28"),
        new BigDecimal("1077.70"),
        new BigDecimal("995.68"),
        new BigDecimal("1280.55"),
        new BigDecimal("1140.56"),
        new BigDecimal("653.23"),
        new BigDecimal("847.49"),
        new BigDecimal("995.68")    
    };

    for (int i = 0; i < valorbase.length; i++) {
        BigDecimal desconto=new BigDecimal("0.015");
        BigDecimal valor_a_descontar=valorbase[i].mu开发者_如何转开发ltiply(desconto);

            valor_a_descontar=valor_a_descontar.setScale(2,RoundingMode.HALF_UP);
    //desconto=desconto.setScale(2,RoundingMode.HALF_UP);


    BigDecimal valortotal=valorbase[i].subtract(valor_a_descontar);
    valortotal.setScale(3,RoundingMode.HALF_UP);
    valortotal.setScale(2,RoundingMode.HALF_UP);

        System.out.println("BASE=" + valorbase[i] + " - descount=" + valor_a_descontar + " totalvalue=" + valortotal);
    }
}

system out: BASE=1077.70 - descount=16.17 totalvalue=1061.53 missing value of table! BASE=1280.55 - descount=19.21 totalvalue=1261.34 missing value of table!

The diff in some case is 0,01 cent but to financial it's impossible becouse this universe of people is 18.340 registry's the diff is 18340 x 0.01 x 365 x 2 = 4401,6 ===> R$ 4401,6 this the cost of one cent not rounded correctly! Can anyone help me? thanks JAY... This was proposed by JAY:

public static void main(String[] args){
    BigDecimal[] valorbase= {
            new BigDecimal("667.63"),
            new BigDecimal("705.98"),
            new BigDecimal("687.77"),
            new BigDecimal("844.62"),
            new BigDecimal("743.23"),
            new BigDecimal("775.15"),
            new BigDecimal("874.82"),
            new BigDecimal("949.63"),
            new BigDecimal("987.18"),
            new BigDecimal("1040.28"),
            new BigDecimal("1077.70"),
            new BigDecimal("995.68"),
            new BigDecimal("1280.55"),
            new BigDecimal("1140.56"),
            new BigDecimal("653.23"),
            new BigDecimal("847.49"),
            new BigDecimal("995.68")                

            };




    for(int i=0;i<valorbase.length;i++){

    BigDecimal desconto=new BigDecimal("0.985");

    //BigDecimal valor_a_descontar=valorbase[i].multiply(desconto);




    //valor_a_descontar=valor_a_descontar.setScale(2,RoundingMode.HALF_UP);
    //desconto=desconto.setScale(2,RoundingMode.HALF_UP);


    //BigDecimal valortotal=valorbase[i].subtract(valor_a_descontar);
    BigDecimal valortotal=valorbase[i].multiply(desconto);

    //valortotal.setScale(3,RoundingMode.HALF_UP);
    //valortotal.setScale(2,RoundingMode.HALF_EVEN);

    System.out.println("subtotal="+valortotal);

    if(valorbase[i].doubleValue()/1000>=1){
        valortotal=valortotal.setScale(8,RoundingMode.HALF_UP);
        valortotal=valortotal.setScale(7,RoundingMode.HALF_UP);
        valortotal=valortotal.setScale(6,RoundingMode.HALF_UP);
        valortotal=valortotal.setScale(5,RoundingMode.HALF_UP);
        valortotal=valortotal.setScale(4,RoundingMode.HALF_UP);
        valortotal=valortotal.setScale(3,RoundingMode.HALF_UP);
        valortotal=valortotal.setScale(2,RoundingMode.HALF_UP);
    }else{
        valortotal=valortotal.setScale(2,RoundingMode.HALF_UP);
    }       
    System.out.println("BASE="+valorbase[i]+" totalvalue="+valortotal);


    }

}

based on the Idea of Jay i make some modifications the financial guys says: "well, we never can uP de discount to clients..we need some times round the due to up on cent"..

thanks for all!...


Are you sure that you are using the appropriate RoundingMode? RoundingMode 1 is ROUND_DOWN and RoundingMode 5 is ROUND_HALF_DOWN. Perhaps you are supposed to use ROUND_HALF_EVEN (which is common in some financial scenarios)?

Also, the code would be clearer if you used these enum constants instead of the RoundingMode.valueOf method.


You always run into questions about the exact rounding rules with problems like this.

Like, do we round before or after the subtraction. Also, you might say that as a shortcut, a 1.5% discount is the same as saying that we charge 98.5% of regular price, so we should just be able to multiply the original price by 98.5% and not have to do an extra subtraction. Right?

Suppose the price is 667.00.

Method 1: 667.00 * .015 = 10.005, round up to 10.01. Then 667.00 - 10.01 = 656.99.

Method 2: 667.00 * .015 = 10.005. 667.00 - 10.005 = 656.995. Round up to 657.00. Different answer.

Method 3: 667.00 * .985 = 656.995, round up to 657.00.

Also, Roney mentioned that the table is wrong for 1077.70. It's also wrong for 1280.55.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜