首页 文章

BigDecimal:使用setScale进行舍入的HALF_UP

提问于
浏览
4

我们有以下代码:

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

我们是单元测试这个并得到不同的结果取决于我们是否在测试类上使用 @Transactional .

我只是想知道我们是否应该期望 HALF_UP 的应用与 setScale 或之前一起考虑 .

例如:

比如说 :

price = 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 . 但是也有道理 .

有什么想法吗?

UPDATE

按照@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 回答

  • 3

    它看起来会受到影响,具体取决于你如何构建 BigDecimal

    检查public BigDecimal(double val)上的构造函数说明

    1.-这个构造函数的结果可能有些不可预测 . 有人可能会假设在Java中编写新的BigDecimal(0.1)会创建一个BigDecimal,它恰好等于0.1(未缩放值为1,标度为1),但它实际上等于0.1000000000000000055511151231257827021181583404541015625 . 这是因为0.1不能精确地表示为double(或者,就此而言,作为任何有限长度的二进制分数) . 因此,传递给构造函数的值并不完全等于0.1,尽管有外观 . 2.另一方面,String构造函数是完全可预测的:写入新的BigDecimal(“0.1”)会创建一个BigDecimal,它正好等于0.1,正如人们所期望的那样 . 因此,通常建议优先使用String构造函数 . 3.-当必须将double用作BigDecimal的源时,请注意此构造函数提供了精确的转换;它不会产生与使用Double.toString(double)方法将double转换为String然后使用BigDecimal(String)构造函数相同的结果 . 要获得该结果,请使用static valueOf(double)方法 .

相关问题