我试图从一个 float 精确地循环到下一个。说,我需要从 std::numeric_limits<float>::epsilon()
开始循环至 1
, 它们都是完全可表示的 IEEE754 数字。我的代码是:
using nld = std::numeric_limits<float>;
auto h = nld::epsilon();
for (; h < 1; h = std::nextafter(h, 1)) {
std::cerr << "h: " << h << std::endl;
}
无限循环因为 h 是完全可表示的,所以 nextafter
不断返回。我也知道在循环中将机器 epsilon 添加到 h 不会削减它: float 不是等间距的。如何遍历 IEEE754 数字的精确表示?
not equally spaced
问题出现在这里:
using nld = std::numeric_limits<float>;
auto h = nld::epsilon();
for (; h < 4; h += nld::epsilon()) {
if (h = h + nld::epsilon()) {
std::cerr << "h: " << h << std::endl;
}
}
不断打印2
对我来说
最佳答案
根据评论:
nextafter
的方法正是您应该做的。然而,它有一些并发症,可能会导致意想不到的结果。
引用 cppreference std::nextafter
:
float nextafter( float from, float to );
(1) (since C++11)
double nextafter( double from, double to );
(2) (since C++11)
long double nextafter( long double from, long double to );
(3) (since C++11)
Promoted nextafter( Arithmetic from, Arithmetic to );
(4) (since C++11)...
4) A set of overloads or a function template for all combinations of arguments of arithmetic type not covered by (1-3). If any argument has integral type, it is cast to
double
. If any argument islong double
, then the return typePromoted
is alsolong double
, otherwise the return type is alwaysdouble
.
由于您的to
是1
,属于int
类型,您得到重载版本4,返回类型为double
。现在,完全有可能给定一个 float f
,(float)nextafter((double)f, 1)
完全等于原始 f
:double
类型的下一个可表示数字很可能无法用 float
表示,并且转换回 float
会向下舍入。
返回 float
的唯一重载是 to
的类型为 float
的重载。要使用该重载,请使用 1.0f
而不是 1
。
关于c++ - 如何遍历 float 的精确表示?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27329921/