繁体   English   中英

“双 + 1e-6”是什么意思?

[英]What does "double + 1e-6" mean?

这个 cpp 的结果是72.740 ,但答案应该是72.741

mx = 72.74050000;
printf("%.3lf \n", mx);

所以我在网站上找到了解决方案,它告诉我添加"+1e-7"并且它有效

mx = 72.74050000;
printf("%.3lf \n", mx + 1e-7);

但我不知道这种方法的原因,谁能解释它是如何工作的?

而且我也尝试打印它,但没有发生什么特别的事情……结果是72.7405

mx = 72.74050003;
cout << mx + 1e-10;

如果您将 output 值如

printf( "mx = %.16f\n", mx );

你会看见

mx = 72.7404999999999973

因此,由于通过调用 printf 进行四舍五入,因此要使结果类似于 72.741,您需要使下一个数字等于 5 而不是 4。添加0.00001就足够了。

这是一个演示程序。

#include <iostream>
#include <iomanip>
#include <cstdio>

int main( void ) 
{
    double mx = 72.74050000;

    printf( "mx = %.3f\n", mx + 0.00001);

    std::cout << "mx = " << std::setprecision( 5 ) <<  mx + 0.00001 << '\n';
}

程序 output 是

mx = 72.741
mx = 72.741

0.000011e-5相同。

首先,您的问题包含不正确的假设。 您将 72.7405(假设它是精确的)输入并期望 output 上的 72.741。 因此,您假设 printf 中的舍入将使 select 成为可能的二的更高候选者。 为什么?

好吧,根据一些规则(例如,在账单、税收等方面进行四舍五入的财政规范),人们可以认为这是您的任务——这很常见。 但是,当您使用 C/C++ 的标准浮点时,您应该考虑以下细节:

  1. 它是二进制的,而不是十进制的。 结果,所有值都保留有一些错误。
  2. 标准库倾向于使用标准舍入。

第二点意味着 C 浮动中的默认舍入是四舍五入到最近的关系到偶数(或者,很快,半到偶数)。 通过这种四舍五入,72.7405 将四舍五入为 72.740,而不是 72.741(但是,72.7415 将四舍五入为 72.742)。 要要求舍入 72.7405 -> 72.741,您应该安装另一种舍入模式:round-to-nearest-ties-away-from-zero(很快:round-half-away)。 这种模式是请求,参考,在 IEEE754 中进行十进制运算。 因此,如果您使用真正的十进制算术,就足够了。

(如果我们不允许负数,相同的模式可能会被视为减半。但我假设在财务会计和类似情况下不允许负数。)

但是,这里的第一点更重要:这些值表示的不精确性可以乘以操作。 我重复你的情况和更多案例的建议解决方案:

代码:

#include <stdio.h>
int main()
{
  float mx;
  mx = 72.74050000;
  printf("%.6lf\n", mx);
  printf("%.3lf\n", mx + 1e-7);
  mx *= 3;
  printf("%.6lf\n", mx);
  printf("%.3lf\n", mx + 1e-7);
}

结果(Ubuntu 20.04/x86-64):

72.740501
72.741
218.221497
218.221

因此,您会看到,仅将示例数字乘以 3 会导致补偿总和 1e-7 不足以强制四舍五入,并且 218.2215(“精确”72.7405*3)被四舍五入为 218.221 而不是期望值218.222。 哎呀,“罗伯特·B·韦德导演”……

情况如何才能解决? 好吧,您可以从更粗略的方法开始。 如果您需要四舍五入到 3 位十进制数字,但输入看起来有 4 位数字,请添加 0.00005(结果中最低有效位的一半),而不是这个无能为力且缓慢的 1e-7。 这肯定会提高半票值。

但是,所有这些只有在舍入前的结果误差严格小于 0.00005 时才会起作用。 如果您有繁琐的计算(例如对数百个值求和),很容易得到超过此阈值的结果错误。 为避免此类错误,您会经常四舍五入中间结果(理想情况下,每个值)。

而且,最后一个结论将我们引向最后一个问题:如果我们需要对每个中间结果进行四舍五入,为什么不直接迁移到整数计算呢? 您必须将中间结果保留到 4 位十进制数字? 缩放 10000 并以整数进行所有计算。 这也将有助于避免更高指数的静默(*)精度损失。

(*) 好吧,IEEE754 需要提高“不精确”标志,但是,对于二进制浮点,几乎任何带有小数的运算都会提高它,因此,有用的信号将淹没在噪音的海洋中。

最后的结论不是对您的问题而是对上层任务的正确答案:使用定点方法。 正如我在上面展示的那样,使用 +1e-7 的方法太容易失败。 不,不要使用它,不,永远不要。 有很多适合定点算术的库,只需选择一个并使用即可。

(这也很有趣,为什么 %.6f 导致打印 72.740501 但 218.221497/3 == 72.740499。这表明“单”浮动(C 中的float )在这里太不准确了。即使没有这种错误的方法,使用double也会推迟问题,屏蔽它并伪装成正确的方式。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM