在 Java 中对双打进行四舍五入

2022-08-31 17:09:08

我找到了这个很好的舍入解决方案:

static Double round(Double d, int precise) {
    BigDecimal bigDecimal = new BigDecimal(d);
    bigDecimal = bigDecimal.setScale(precise, RoundingMode.HALF_UP);
    return bigDecimal.doubleValue();
}

但是,结果令人困惑:

System.out.println(round(2.655d,2)); // -> 2.65
System.out.println(round(1.655d,2)); // -> 1.66

为什么它给出这个输出?我使用的是 jre 1.7.0_45。


答案 1

您必须更换

BigDecimal bigDecimal = new BigDecimal(d);

BigDecimal bigDecimal = BigDecimal.valueOf(d);

您将获得预期的结果:

2.66
1.66

来自 Java API 的解释:

BigDecimal.valueOf(double val) - 使用 Double.toString() 方法提供的 double 的规范字符串表示形式。这是将双精度(或浮点数)转换为大十进制数的首选方法。

new BigDecimal(double val) - 使用双精度的二进制浮点值的精确十进制表示,因此此构造函数的结果可能有些不可预测。


答案 2

你可以尝试像这样改变你的程序:-

static Double round(Double d, int precise) 
{
BigDecimal bigDecimal = BigDecimal.valueOf(d);
bigDecimal = bigDecimal.setScale(precise, RoundingMode.HALF_UP);
return bigDecimal.doubleValue();
}

样品伊豆酮

Success  time: 0.07 memory: 381184 signal:0
Rounded: 2.66
Rounded: 1.66

Success  time: 0.07 memory: 381248 signal:0
Rounded: 2.66
Rounded: 1.66

为什么你用BigDecimal.valueOf而不是新的BigDecimal获得预期结果的原因,用Joachim Sauer的话来说:

BigDecimal.valueOf(double)将使用传入的双精度值的规范字符串表示形式来实例化 BigDecimal 对象。换句话说:对象的值将是您在执行 操作时所看到的值。BigDecimalSystem.out.println(d)

但是,如果您使用,则 BigDecimal 将尝试尽可能准确地表示双精度值。这通常会导致存储的数字比您想要的要多得多。new BigDecimal(d)

因此,导致您在程序中观看的一些混乱

来自 Java Doc:

BigDecimal.valueOf(double val) - 使用 Double.toString(double) 方法提供的 double 的规范字符串表示形式将 double 转换为 BigDecimal。

新的大十进制(双值) -

将双精度转换为 BigDecimal,这是双精度的二进制浮点值的精确十进制表示形式。返回的 BigDecimal 的小数位数是最小值,使得 (10 scale × val) 是整数。笔记:

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