Java BigDecimal 与 Financial Mans - “1 美分问题”
我有这个问题:财务人员说:“您的程序错误”。
财务的官方值表和最终计算是
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
我的函数的返回值必须与该表中的总值匹配:
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].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);
valortotal.setScale(3,RoundingMode.HALF_UP);
valortotal.setScale(2,RoundingMode.HALF_UP);
System.out.println("BASE=" + valorbase[i] + " - descount=" + valor_a_descontar + " totalvalue=" + valortotal);
}
}
系统输出: <代码> BASE=1077.70 - descount=16.17 总计值=1061.53 表缺失值! BASE=1280.55 - descount=19.21 Totalvalue=1261.34 缺少表值!
在某些情况下的差异是 0,01 美分,但对于财务来说这是不可能的,因为这个人群是 18.340 注册表的差异为 18340 x 0.01 x 365 x 2 = 4401,6 ===> R$ 4401,6 这是一美分的成本,未正确四舍五入!有人可以帮助我吗? 谢谢杰... 这是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);
}
}
根据Jay的想法我做了一些修改 财务人员说:“好吧,我们永远无法给客户增加折扣……我们需要在到期日期间增加几分”……
谢谢大家!...
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].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);
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!...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您确定您使用的是适当的 RoundingMode? RoundingMode 1 为
ROUND_DOWN
,RoundingMode 5 为ROUND_HALF_DOWN
。也许您应该使用ROUND_HALF_EVEN
(这在某些金融场景中很常见)?此外,如果您使用这些枚举常量而不是 RoundingMode.valueOf 方法,代码会更清晰。
Are you sure that you are using the appropriate RoundingMode? RoundingMode 1 is
ROUND_DOWN
and RoundingMode 5 isROUND_HALF_DOWN
. Perhaps you are supposed to useROUND_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.对于此类问题,您总是会遇到有关精确舍入规则的问题。
比如,我们是在减法之前还是之后舍入。另外,你可能会说,作为一种捷径,1.5%的折扣相当于我们收取正常价格的98.5%,所以我们应该能够将原价乘以98.5%,而不必进行额外的减法。正确的?
假设价格为 667.00。
方法 1:667.00 * .015 = 10.005,向上舍入为 10.01。那么 667.00 - 10.01 = 656.99。
方法 2:667.00 * .015 = 10.005。 667.00 - 10.005 = 656.995。四舍五入为 657.00。不同的答案。
方法 3:667.00 * .985 = 656.995,向上舍入为 657.00。
另外,Roney 提到该表的 1077.70 是错误的。 1280.55 也是错误的。
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.