BigDecimal:使用setScale

时间:2018-07-31 16:33:55

标签: java bigdecimal

我们有以下代码:

BigDecimal net = price
.divide(taxCumulative, RoundingMode.HALF_UP)
.setScale(2, BigDecimal.ROUND_UP); 

我们正在对此进行单元测试,并根据是否在测试类上使用@Transactional来获得不同的结果。

我只是想知道我们是否应该将HALF_UP的应用与setScale一起或在其之前考虑。

例如:

说:

价格= 4.00

taxCumulative = 1.20

您希望计算结果如下:

a)4.00 / 1.20 = 3.33333333... --> HALF_UP --> 3 --> setScale --> 3

b)4.00 / 1.20 = 3.33333333... --> HALF_UP with setScale 2 --> 3.33

就像我说过的那样,我们对此代码进行了单元测试,无论我们是否拥有@Transactional,它们的行为都不同。因此我们无法得出结论。在现实世界中,结果为 b 。但是 a 也很有意义。

有什么想法吗?

更新

根据@Mark的建议,我在spring上下文之外创建了一个测试。 (但我想没有办法像Codepen一样在线共享它)。

package com.company;

import java.math.BigDecimal;
import java.math.RoundingMode;

public class Main {

    public static void main(String[] args) {
        BigDecimal price = new BigDecimal("4.00");
        BigDecimal taxCumulative = new BigDecimal("1.20");
        BigDecimal net = price.divide(taxCumulative, RoundingMode.HALF_UP).setScale(2, BigDecimal.ROUND_UP);
        System.out.println("With String constructor, the net =  " + net.toString());
        // prints 3.33
        price = new BigDecimal(4.00);
        taxCumulative = new BigDecimal(1.20);
        net = price.divide(taxCumulative, RoundingMode.HALF_UP).setScale(2, BigDecimal.ROUND_UP);
        System.out.println("With doubles, the net =  " + net.toString());
        // prints 3.00
    }
}

因此,正如@gtgaxiola指出的那样,String构造函数有所不同。

关于将setScale用于除法运算的问题。我还做了一些测试:

price = new BigDecimal("4.000000");
taxCumulative = new BigDecimal("1.2000000");
net = price.divide(taxCumulative, RoundingMode.HALF_UP).setScale(2, BigDecimal.ROUND_UP);
// 3.34

price = new BigDecimal("4.000000");
taxCumulative = new BigDecimal("1.2000000");
net = price.divide(taxCumulative, RoundingMode.HALF_UP);
// 3.333333

price = new BigDecimal("4");
taxCumulative = new BigDecimal("1.2");
net = price.divide(taxCumulative, RoundingMode.HALF_UP);
// 3

因此,结果高度取决于字符串输入的精度,并且在除后产生 后将应用setScale。

1 个答案:

答案 0 :(得分:3)

它似乎会受到影响,具体取决于您构建BigDecimal

的方式

检查public BigDecimal(double val)上的构造函数注释

  

1。-此构造函数的结果可能无法预测。有人可能会假设用Java编写新的BigDecimal(0.1)会创建一个BigDecimal,它精确地等于0.1(未缩放的值1,小数位数为1),但实际上等于0.1000000000000000055511151231257827021181583404541015625。这是因为0.1无法精确表示为双精度(或就此而言,表示为任何有限长度的二进制分数)。因此,尽管出现,传递给构造函数的值并不完全等于0.1。

     

2。-另一方面,String构造函数是完全可预测的:就像期望的那样,编写新的BigDecimal(“ 0.1”)会创建一个完全等于0.1的BigDecimal。因此,通常建议优先使用String构造函数。

     

3.-当必须将double用作BigDecimal的源时,请注意此构造函数提供了精确的转换;它与使用Double.toString(double)方法然后使用BigDecimal(String)构造函数将double转换为String的结果不同。要获得该结果,请使用静态valueOf(double)方法。