当前位置: 首页 > 知识库问答 >
问题:

java舍入错误,对x.715和x.915使用half\u偶数

卫学真
2023-03-14

使用圆化模式时。java的半偶数(默认值)。文本DecimalFormat,我在返回值中看到异常。

我意识到存在精度错误,请参见:Java BigDecimal setScale和舍入为半偶数

然而,由于这是java.text.DecimalFormat,我希望它会被处理

定义:

HALF_EVEN
Rounding mode to round towards the "nearest neighbor" unless both neighbors are equidistant, in which case, round towards the even neighbor.

这是检查双倍舍入的示例:

import java.text.DecimalFormat;
import java.math.RoundingMode;

public class MyClass {
    public static void main(String args[]) {
        String[] dStrings= new String[] { "1548.015", "1548.115", "1548.215", "1548.515", "1548.715", "1548.815", "1548.915",    "1548.705", "1548.715", "1548.725", "1548.755", "1548.775", "1548.785", "1548.795",   "1548.710", "1548.711", "1548.712", "1548.715", "1548.717", "1548.718", "1548.719" } ;
        DecimalFormat df = new DecimalFormat("0.00");
        df.setMaximumFractionDigits(2);

        Double dValue;
        System.out.println("round mode:half_even...");
        System.out.println("String   => str-frmt| dec-frmt");
        //df.setRoundingMode(RoundingMode.CEILING);
        for (String dStr : dStrings) {
            //dValue = new Double(dStr);
            //dValue = Double.parseDouble(dStr);
            dValue = Double.valueOf(dStr);
            System.out.println(String.format("%s => %.2f | BD: %s |DF %s", dStr, dValue, BigDecimal.valueOf(dValue).setScale(2, RoundingMode.HALF_EVEN), df.format(dValue) ));
        }
    }
}

使用java对第4个值进行四舍五入。文本十进制格式,第一个值为原始值

1548.015 => 1548.02 | BD: 1548.02 |DF 1548.02
1548.115 => 1548.12 | BD: 1548.12 |DF 1548.12
1548.215 => 1548.22 | BD: 1548.22 |DF 1548.21 - not ok
1548.515 => 1548.52 | BD: 1548.52 |DF 1548.52
1548.715 => 1548.72 | BD: 1548.72 |DF 1548.71 - not ok
1548.815 => 1548.82 | BD: 1548.82 |DF 1548.82
1548.915 => 1548.92 | BD: 1548.92 |DF 1548.91 - not ok

上面列出的每种情况下,最近邻是1,5是等距的,对吗?所以所有这些情况都应该变成2,对吗?

我在多个当前和过去的JDK版本上进行了测试,都得到了相同的结果。我是误解了还是这是一个错误?请解释为什么java.text.DecimalFormat没有注意浮点精度,因为这似乎是问题所在。

还有为什么字符串中使用基本舍入模型。格式<代码>'%。2f’,未在java中表示。数学圆形模式?i、 e.当5岁及以上时,将最近的邻居四舍五入。

共有1个答案

宗冷勋
2023-03-14

答案很复杂,不足之处在于无法依赖基于浮点的舍入,所看到的行为是正确的,正如巴兹尔所指出的那样。舍入输入时,不应使用浮点。

最佳解决方案,是最简单和明显的使用示例:String.format("%s=

Oracle SR响应:

html" target="_blank">JDK7是错误行为(请参阅JDK-7131459),以及。JDK8是正确的行为。

问题是“0.5555”,我们都理解为十进制值0.5555,不能用任何二进制表示(包括IEEE-754)来表示。可以获得的这个数字的最精确的二进制表示是0.55549999999999999378275106209912337362766265869140625。使用BigDecimal可以得到这个最好的近似,它提供了无限的精度:

System.out.println("BigDecimal输出为0.5555:"new BigDecimal(0.5555). toString());

上面将返回:“0.5555的BigDecimal输出:0.555499999939378275106209912337362766265869140625”

因此,我们可以看到,0.5555的最接近二进制表示略小于0.5555(0.555499…)。

因此,即使程序员打算使用十进制0.5555,计算机也可以使用IEEE-754的最佳近似值,即0.5554999999999。。。这同样小于0.5555十进制值。

在HALF-EVEN舍入规则下,当在小数点后的第3位小数位舍入时,即上述程序中的情况,不应对该小数位进行舍入,此处的正确结果是“55.5%”

这里JDK7是错误的,JDK8是正确的。

使用-XX:AggressiveOpts选项(从7u14-b13开始)可以获得正确的JDK7行为。

***非常重要的是要理解几乎所有浮点值都不能被任何二进制表示精确记录(如这里的IEEE-754)。使用浮点,你看到的不是你得到的!

根据我的发现以及我从其他工程师那里得到的信息,这不是java 8及更高版本的问题,而是关于浮动小数的预期行为。该实现基于IEEE-754标准。

 类似资料:
  • 我正在尝试实现一个新的等级舍入到BigDecimal类,并且我得到了一个可能的错误,一定是我做错了什么。下面的代码暴露了我的问题: 我的疑问是,BigDecimal对于double和String构造函数是否不同? 我不能理解这个“bug”,至少,我只是用了一个简单的字符串conat来“解决”它,如下所示: 知道是什么导致了这种奇怪的行为吗?

  • 我正在创建一个用百分比计算分数平均值的应用程序,但问题是BigDecimal并不总是对平均值进行四舍五入,例如,如果分数平均值是3.85 BigDecimal ROUND\u HALF\u,那么在量表1中应该四舍五入到3.9,但它显示的平均值像3.8,这只发生在某些特定的时间,有时BigDecimal ROUND 4.95,比如5.0,这很好,但我不知道为什么会这样,问题出在哪里。这是一个示例代码

  • 我将以下代码与java BigDecimal setScale方法结合使用,并使用半\u偶数舍入模式,得到以下结果。 结果:1.11 预计:1.12 由于距离5最近的偶数数字应该是2,因此我预期的结果是1.12。但结果是1.11。再一次, 结果:1.15 预期:1.14 因为5左边的偶数是4,所以我希望结果是1.14。对此有什么解释吗?

  • 问题内容: 我只是在重新阅读Python 3.0的新增功能,它指出: 函数的舍入策略和返回类型已更改。现在,精确的中途案例将舍入到最接近的偶数结果,而不是从零舍入。(例如,round(2.5)现在返回2而不是3。) 以及关于round的文档: 对于支持的内置类型,将值四舍五入为乘幂n的最接近10的倍数;如果两个倍数相等接近,则四舍五入取整为偶数选择 因此,在v2.7.3下: 如我所料 但是,现在在

  • 和Round的文档: 对于支持round()的内置类型,值被舍入到10的最接近倍数的幂减N;如果两个倍数相等接近,则向偶数选择四舍五入 因此,在V2.7.3下: null

  • 问题内容: 我遇到了(我怀疑是)舍入错误。 我有一个字符串,我正尝试将其转换为双精度型。我已经可以使用函数将其拆分,并且可以很好地捕获基数和指数值。但是,一旦我尝试将它们适当地相乘,就会得到以下结果:。 这是我的相关代码: 那么,如何避免舍入错误?(我有多种方法可以解决此问题,但如果有可能,那么我想知道如何解决该问题) 谢谢。 问题答案: 您不需要拆分它,可以很好地处理这些数字。 看到?有用!