Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/334.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何解决四舍五入带来的不匹配问题?_Java_Bigdecimal_Rounding Error - Fatal编程技术网

Java 如何解决四舍五入带来的不匹配问题?

Java 如何解决四舍五入带来的不匹配问题?,java,bigdecimal,rounding-error,Java,Bigdecimal,Rounding Error,我正在开发一个具有两个端点的JavaAPI。一个端点有待支付的总金额,另一个端点有端点一中总金额的细分或组成。背后的逻辑是从DB获取货币A的值,并以货币B向用户显示,汇率为1B=18.03A。理想情况下,转换后的总金额和转换后的细分金额之和必须相同。在大多数情况下,代码运行良好。但有时我会出现不匹配的情况。举个例子,, 从一号终点算起,总金额为19370.21亿美元。细分(从终点二开始):124.5B、4245.71B、15000B。下面是我进行转换时发生的情况 BigDecimal r

我正在开发一个具有两个端点的JavaAPI。一个端点有待支付的总金额,另一个端点有端点一中总金额的细分或组成。背后的逻辑是从DB获取货币A的值,并以货币B向用户显示,汇率为1B=18.03A。理想情况下,转换后的总金额和转换后的细分金额之和必须相同。在大多数情况下,代码运行良好。但有时我会出现不匹配的情况。举个例子,, 从一号终点算起,总金额为19370.21亿美元。细分(从终点二开始):124.5B、4245.71B、15000B。下面是我进行转换时发生的情况

    BigDecimal rate = BigDecimal .valueOf(18.03);
    
    //Converting total amount to currency B
    
    BigDecimal bgtotal = BigDecimal .valueOf(19370.21);   
    BigDecimal totalToCurB= bgtotal.divide(rate, 2, RoundingMode.HALF_UP);
    System.out.println(totalToCurB);//prints 1074.33
    
   //Converting individual item amounts to currency B and summing them
    BigDecimal itemA = BigDecimal .valueOf(124.5);
    BigDecimal itemB = BigDecimal .valueOf(4245.71);
    BigDecimal itemC = BigDecimal .valueOf(15000);
    BigDecimal itemAToCurB= itemA.divide(rate, 2, RoundingMode.HALF_UP);
    BigDecimal itemBToCurB= itemB.divide(rate, 2, RoundingMode.HALF_UP);
    BigDecimal itemCToCurB= itemC.divide(rate, 2, RoundingMode.HALF_UP);
    
    BigDecimal total = itemAToCurB.add(itemBToCurB).add(itemCToCurB);
    System.out.println(total);//prints 1074.34

如何避免这种不匹配?

在操作上设置更大的比例。如果在算术运算中只使用两位小数,则会出现差异

itematorub
将为6.91、
itemtocurb
235.48和
itemtorub
831.95,这三者之和将是错误的。由于分区更像6.90515806988352745424,因此这里的问题是
itematoruble
。通过在小数点后第二位四舍五入,您只是增加了差异

当你用更多的小数位进行除法时,舍入将在不太重要的尺度上进行。您总是可以只打印两个位置

差不多

BigDecimal rate = BigDecimal .valueOf(18.03);

BigDecimal itemA = BigDecimal .valueOf(124.5);
BigDecimal itemB = BigDecimal .valueOf(4245.71);
BigDecimal itemC = BigDecimal .valueOf(15000);

BigDecimal itemAToCurB= itemA.divide(rate, 20, RoundingMode.HALF_UP);
BigDecimal itemBToCurB= itemB.divide(rate, 20, RoundingMode.HALF_UP);
BigDecimal itemCToCurB= itemC.divide(rate, 20, RoundingMode.HALF_UP);

BigDecimal total = itemAToCurB.add(itemBToCurB).add(itemCToCurB);
System.out.println(total.setScale(2, RoundingMode.HALF_UP));//prints 1074.33
如所示,该问题是按比例引入的,将其增加到小数点后3位或4位将解决该问题

或者,您可以保留小数点后2位,但对于明细和总额,只能使用一个端点。也就是说,您可以调用端点2并对细分金额求和,而不是调用端点1来获取总金额

// Option 1: Increase decimal scale to 3 or 4
BigDecimal rate = BigDecimal .valueOf(18.03);

BigDecimal total = BigDecimal.valueOf(19370.21);
BigDecimal itemA = BigDecimal.valueOf(124.5);
BigDecimal itemB = BigDecimal.valueOf(4245.71);
BigDecimal itemC = BigDecimal.valueOf(15000);

BigDecimal itemAToCurB= itemA.divide(rate, 3, RoundingMode.HALF_UP); //6.905
BigDecimal itemBToCurB= itemB.divide(rate, 3, RoundingMode.HALF_UP); //235.48
BigDecimal itemCToCurB= itemC.divide(rate, 3, RoundingMode.HALF_UP); //831.947

BigDecimal totalA = itemAToCurB.add(itemBToCurB).add(itemCToCurB);
BigDecimal totalB = total.divide(rate, 2, RoundingMode.HALF_UP); 

System.out.println(totalA.setScale(2, RoundingMode.HALF_UP)); //prints 1074.33
System.out.println(totalB.setScale(2, RoundingMode.HALF_UP)); //prints 1074.33

我还需要向客户显示细分金额。实际上,平等性检查是由客户端完成的。这里没有太多选项。若客户希望只有两位小数,那个么它总是会有舍入差异,这只是数学问题。你需要用更多的小数。然后只显示所需的数量增加小数位数无法解决问题。最后的办法是单独汇总细分数据。我想有一种方法可以使用BigDecimal属性来解决这个问题。无论如何,谢谢。
// Option 2: Use total from Endpoint 2, Carrying the rounding-off errors
BigDecimal rate = BigDecimal .valueOf(18.03);

// BigDecimal total = BigDecimal.valueOf(19370.21);
BigDecimal itemA = BigDecimal.valueOf(124.5);
BigDecimal itemB = BigDecimal.valueOf(4245.71);
BigDecimal itemC = BigDecimal.valueOf(15000);

BigDecimal itemAToCurB= itemA.divide(rate, 2, RoundingMode.HALF_UP); //6.91
BigDecimal itemBToCurB= itemB.divide(rate, 2, RoundingMode.HALF_UP); //235.48
BigDecimal itemCToCurB= itemC.divide(rate, 2, RoundingMode.HALF_UP); //831.95

BigDecimal totalA = itemAToCurB.add(itemBToCurB).add(itemCToCurB);
BigDecimal totalB = totalA; 

System.out.println(totalA.setScale(2, RoundingMode.HALF_UP)); //prints 1074.34
System.out.println(totalB.setScale(2, RoundingMode.HALF_UP)); //prints 1074.34