[英]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.00001
与1e-5
相同。
首先,您的问题包含不正确的假设。 您将 72.7405(假设它是精确的)输入并期望 output 上的 72.741。 因此,您假设 printf 中的舍入将使 select 成为可能的二的更高候选者。 为什么?
好吧,根据一些规则(例如,在账单、税收等方面进行四舍五入的财政规范),人们可以认为这是您的任务——这很常见。 但是,当您使用 C/C++ 的标准浮点时,您应该考虑以下细节:
第二点意味着 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.