3

在这里阅读并得出结论,double 的最小(绝对 ...)值是,1.7e-308但我的代码永远循环:

for (double d(-1.0); d <= 1.0; d+=1.7e-308)
{
}

编辑:我想以尽可能小的增量从 -1.0 循环到 1.0。

4

3 回答 3

10

在 C++11/C99 中,您可以使用它nextafter来获取下一个可表示的数字。

#include <cmath>

for (double d(-1.0); d <= 1.0; d = std::nextafter(d, 1.0) )
{
}

此外,如果我正确地进行了数学运算,那么在 -1 和 1 之间大约有 10^18 个可表示的值。

在每秒 10^6 个周期的合理假设下,执行此计算需要 32000 年。

于 2014-04-20T08:33:13.400 回答
3

TL; DR:计算机能够以浮点数存储的数字之间的差距随着数字变大而变大。您的最小数字仅在数字为零时有效。在某些时候,尝试添加这么小的数字没有任何作用,因为它不能代表数字的如此小的变化。

这是因为每个可表示的浮点数之间的差距随着数字的增加而变大。

1 与小于 1 的最接近的可表示对象之间的差异约为 1.11 × 10 -16,远大于您尝试添加的值。

发生的情况是,双精度数与一组用于数字符号的位一起存储,另一组用于表示数字本身(作为无符号整数)和乘数作为 2 的指数。

当您接近零时,指数非常小,与您的指数大得多时相比,存储的实际数字发生的变化更少。

例如, (4 - 3) × 2 99显然会大于 (4 - 3) × 2 -99,这基本上是正在发生的事情。

当您开始添加时,您会发现最终添加 1.7 × 10 -308没有任何作用,因为您的当前值是添加的最接近的可表示值,它会在无限循环中不断循环。

请注意,仅当舍入模式设置为 roundTiesToEven 或 roundTiesToAway 时,它们会舍入到最接近的可表示值,除非它们同样接近。

std::fesetround如果您通过预先调用with手动将舍入模式设置为 roundTowardPositive FE_UPWARD正如 Marc Glisse 指出的那样),如果您添加任何正数(零除外),它将继续增加。我认为 roundTowardNegative 和 roundTowardZero 是不言自明的。

顺便说一句,即使您将其替换为 1.11 × 10 -16,您仍然需要经过 18 014 398 509 481 984 (18 万亿次)迭代才能完成。如果您实际上循环遍历 -1 和 1 之间的每个值,那就是 9 223 372 036 854 775 809(9 quintillion)迭代。祝你好运。

于 2014-04-20T08:27:58.693 回答
0

我不认为 double 的最小值是 1.7e-308 它可能更像是 -1.7 e308,1.7e-308 是一个非常小的数字,但不是一个接近负无穷大的数字。这是一个非常小的数字,接近于 0。

于 2014-04-20T08:27:34.157 回答