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

为什么多次添加0.1仍然是无损的?

祁霖
2023-03-14

我知道0.1十进制数不能精确地用有限二进制数表示(解释),因此双n=0.1将失去一些精度,并且不能精确地0.1。另一方面,0.5可以准确地表示,因为它是0.5=1/2=0.1b

可以理解的是,三次添加0.1并不能准确地给出0.3,所以下面的代码打印false:

double sum = 0, d = 0.1;
for (int i = 0; i < 3; i++)
    sum += d;
System.out.println(sum == 0.3); // Prints false, OK
double sum = 0, d = 0.1;
for (int i = 0; i < 5; i++)
    sum += d;
System.out.println(sum == 0.5); // Prints true, WHY?

如果0.1不能精确地表示,那么添加5次它怎么能精确地给出0.5可以精确地表示呢?

共有1个答案

方韬
2023-03-14

舍入误差不是随机的,它的实现方式试图将误差最小化。这意味着有时错误是不可见的,或者没有错误。

例如,0.1不完全是0.1,即new BigDecimal(“0.1”) ,但 0.5完全是 1.0/2

这个程序向你展示了所涉及的真正价值。

BigDecimal _0_1 = new BigDecimal(0.1);
BigDecimal x = _0_1;
for(int i = 1; i <= 10; i ++) {
    System.out.println(i+" x 0.1 is "+x+", as double "+x.doubleValue());
    x = x.add(_0_1);
}
0.1000000000000000055511151231257827021181583404541015625, as double 0.1
0.2000000000000000111022302462515654042363166809082031250, as double 0.2
0.3000000000000000166533453693773481063544750213623046875, as double 0.30000000000000004
0.4000000000000000222044604925031308084726333618164062500, as double 0.4
0.5000000000000000277555756156289135105907917022705078125, as double 0.5
0.6000000000000000333066907387546962127089500427246093750, as double 0.6000000000000001
0.7000000000000000388578058618804789148271083831787109375, as double 0.7000000000000001
0.8000000000000000444089209850062616169452667236328125000, as double 0.8
0.9000000000000000499600361081320443190634250640869140625, as double 0.9
1.0000000000000000555111512312578270211815834045410156250, as double 1.0

这方面的一个例子是为什么在Java6中Math.Round(0.4999999999999999994)返回1。在本例中,计算中丢失了一个位,结果与答案有很大差异。

 类似资料:
  • 问题内容: 我知道十进制数不能用有限的二进制数精确地表示(解释),因此会失去一些精度,并且不会精确地表示。另一方面,因为是,所以可以精确表示。 话虽如此,将 三遍 相加并不完全是可以理解的,因此,以下代码将输出: 但是, 五次 相加会得到确切的结果呢?以下代码显示: 如果不能精确表示,将其相加5次给出的精确表示又如何呢? 问题答案: 舍入误差不是随机的,并且它的实现方式会尝试使误差最小化。这意味着

  • 问题内容: 据我所知,使用旧的JMM来实现懒惰单调的DCL(双重检查锁定)技巧被打破了,但是我坚信它已被新的JMM和volatile字段所修复… 但是,在这篇不错的文章中,这显然已经足够新,足以引用DCL中的新旧JMM和volatile字段,表明它仍然坏了… 我在这里到那里读到它是固定的,然后我发现了这一点……有人可以最后说它是否损坏了? 我的理解是,通过波动性地在关系发生之前保证发生的先兆并有效

  • 我正在创建片段转换器助手类,对此我有一些问题。 我称之为碎片转换器 它有一个fragmentContainer,它是一个视图组,包含我想展示的所有片段。 我已经做了自己的替换(片段片段更改,布尔需要保存到堆栈) 功能是: 从碎片容器中移除旧碎片 错误如下: 如果我使用我的替换功能并保存以使其正常工作,我可以使用设备的后退按钮后退并返回到先前添加的片段,它就像一个符咒。 但是,当我想替换一个片段而不

  • 问题内容: 我必须将npm应用程序的版本从0.1更改为0.0.1,以使npm不能执行此操作。 为了完整性,这里是工作的json 出现错误时,版本以前是“ 0.1”。 这是某种需要3套版本号的API / ABI兼容性版本控制概念吗?为什么错误消息对此不友好? 问题答案: 是的,这对于语义版本控制是必需的,这是npm软件包使用的版本控制方案。这是来自的片段: 版本必须可由node-semver解析,该

  • 我正尝试在出现连接错误时添加一个控件。我的目的是通过捕捉异常来阻止程序抛出异常。 但它会在控制台中打印: 抱歉,如果我打印了太多的StackTrace... 我想知道,如果我不打印出stacktrace,我如何使异常消失?谢谢:)

  • Python有一个令人困惑的工具历史,可以用来打包和描述项目:这些工具包括标准库中的,,和(也许更多)。似乎和被停用,取而代之的是,这留下了两个相互竞争的标准。 据我所知,提供了比多得多的选项(例如,声明依赖项、测试等),但是它没有包含在Python标准库中(尚未?)。 Python打包用户指南[1]现在建议: 使用定义项目并创建源发行版。 并解释道: 尽管您可以对许多项目使用纯,但它不支持定义对