提问人:jorgbrown 提问时间:8/6/2016 最后编辑:Jarod42jorgbrown 更新时间:8/7/2016 访问量:6848
最接近 1.0 的双倍是多少,不是 1.0?
What's the closest double to 1.0, that isn't 1.0?
问:
有没有办法以编程方式获得最接近 1.0 但实际上不是 1.0 的双精度值?
一种笨拙的方法是将双精度值转换为相同大小的整数,然后减去一。浮点格式的工作方式IEEE754,这最终会将指数减少 1,同时将小数部分从所有零 (1.000000000000) 更改为所有 1 (1.1111111111111)。但是,有些机器的整数存储在小端序,而浮点数存储在大端序,因此这并不总是有效。
答:
157赞
Jarod42
8/6/2016
#1
从 C++11 开始,您可以使用 nextafter
在给定方向上获取下一个可表示的值:
std::nextafter(1., 0.); // 0.99999999999999989
std::nextafter(1., 2.); // 1.0000000000000002
评论
14赞
Johannes Schaub - litb
8/6/2016
这也是将双精度递增到下一个可表示整数的好方法:.std::ceil(std::nextafter(1., std::numeric_limits<double>::max()))
45赞
Lightness Races in Orbit
8/6/2016
下一个问题是“如何在 stdlib 中实现”:P
19赞
Cornstalks
8/7/2016
看完@LightnessRacesinOrbit的评论后,我很好奇。这就是 glibc 在 nextafter
中实现的方式,也是 musl 实现它的方式,以防其他人想看看它是如何完成的。基本上:原始位摆弄。
3赞
Matthieu M.
8/8/2016
@Cornstalks:我并不感到惊讶,这归结为一点点的摆弄,唯一的其他选择是拥有 CPU 支持。
6赞
Rudy Velthuis
8/8/2016
IMO,Bit Twiddling 是正确执行此操作的唯一方法。你可以做很多测试尝试,试图慢慢接近它,但这可能非常慢。
23赞
barak manos
8/6/2016
#2
在 C 语言中,您可以使用以下命令:
#include <float.h>
...
double value = 1.0+DBL_EPSILON;
DBL_EPSILON
是 1 与可表示的大于 1 的最小值之间的差值。
您需要将其打印到几位数才能看到实际值。
在我的平台上,给.printf("%.16lf",1.0+DBL_EPSILON)
1.0000000000000002
评论
9赞
barak manos
8/6/2016
@Jarod42:你说得对,但OP特别问了.顺便说一句,它还给出了大于 1 的最接近值,而不是绝对最接近 1 的值(可能小于 1)。所以我同意这是一个部分答案,但我认为它仍然可以做出贡献。1.0
0赞
Jarod42
8/6/2016
@LưuVĩnhPhúc:我给出了答案的限制的精确度,以及另一个方向的最接近性。
8赞
celtschk
8/6/2016
这并不能给出最接近 1.0 的双倍,因为(假设以 2 为基数)1.0 之前的双倍距离仅为 1.0 之后的双倍(即您计算的双倍)的一半。
0赞
barak manos
8/6/2016
@celtschk:你是对的,我在上面的评论中已经解释过了。
4赞
phuclv
8/6/2016
#3
在 C++ 中,你也可以使用它
1 + std::numeric_limits<double>::epsilon()
评论
1赞
zwol
8/7/2016
就像巴拉克·马诺斯的回答一样,这不适用于 1 以外的任何值。
2赞
Random832
8/7/2016
@zwol,对于典型的二进制浮点实现,它适用于 1 到 2-epsilon 之间的任何值。但是,是的,你是对的,它只保证适用于 1。
9赞
HelloGoodbye
8/7/2016
从技术上讲,它不适用于 1,因为最接近 1 的数字是 1 之前的数字,而不是紧随其后的数字。double 在 0.5 和 1 之间的精度是其在 1 和 2 之间的精度的两倍,因此 1 之前的数字最终更接近 1。
26赞
celtschk
8/7/2016
#4
在 C 和 C++ 中,以下给出最接近 1.0 的值:
#include <limits.h>
double closest_to_1 = 1.0 - DBL_EPSILON/FLT_RADIX;
但请注意,在更高版本的 C++ 中,已弃用,取而代之的是 .但是,如果您仍然使用 C++ 特定的代码,则可以使用limits.h
climits
#include <limits>
typedef std::numeric_limits<double> lim_dbl;
double closest_to_1 = 1.0 - lim_dbl::epsilon()/lim_dbl::radix;
正如 Jarod42 在他的回答中所写,从 C99 或 C++11 开始,您还可以使用:nextafter
#include <math.h>
double closest_to_1 = nextafter(1.0, 0.0);
当然,在 C++ 中,您可以(对于以后的 C++ 版本应该)包含并使用。cmath
std::nextafter
评论
nextafter()
1.0000...
0.111111....
1.11111...