当前位置: 首页 > 面试题库 >

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

薛英卫
2023-03-14
问题内容

我知道0.1十进制数不能用有限的二进制数精确地表示(解释),因此double 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

但是,0.1 五次 相加会得到确切的结果0.5呢?以下代码显示true

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表示又如何呢?


问题答案:

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

例如0.1是不完全0.1,即new BigDecimal("0.1") < newBigDecimal(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

注意:这0.3略有偏离,但是当您到达0.4位时,必须将其下移一位以适应53位的限制,并且错误将被丢弃。再次,一个错误蠕变回来为0.60.7,但对于0.81.0错误被丢弃。

将其添加5次应该累积错误,而不是取消错误。

出现错误的原因是由于精度有限。即53位。这意味着随着数字变大,数字将使用更多的比特,比特必须从末尾丢弃。这会导致舍入,这种情况下对您有利。
当获得较小的数字(例如0.1-0.0999=>)时,您会得到相反的效果,1.0000000000000286E-4 并且看到的错误比以前更多。

一个这样的例子就是为什么在Java6中Math.round(0.49999999999999994)为什么返回1的原因,在这种情况下,计算中的一点损失会导致答案有很大的不同。



 类似资料:
  • 我知道十进制数不能精确地用有限二进制数表示(解释),因此将失去一些精度,并且不能精确地。另一方面,可以准确地表示,因为它是。 可以理解的是,三次添加并不能准确地给出,所以下面的代码打印: 如果不能精确地表示,那么添加5次它怎么能精确地给出可以精确地表示呢?

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

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

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

  • 本文向大家介绍0.1 + 0.2、0.1 + 0.3和0.1 * 0.2分别等于多少?并解释下为什么?相关面试题,主要包含被问及0.1 + 0.2、0.1 + 0.3和0.1 * 0.2分别等于多少?并解释下为什么?时的应答技巧和注意事项,需要的朋友参考一下 JS中采用的IEEE 754的双精度标准,计算机内部存储数据的编码的时候,导致精度变化。不是所有浮点数都有舍入误差。二进制能精确地表示位数有

  • 我在CSV数据集配置中添加了CSV文件, 请点击网址查看图片 CSV 文件内容 将上述值传递给后请求,如下所示 点击链接查看图片 简单传递的请求数据具有参数名,而不是值,请参阅下面的示例请求