我的输入浮点值为0.0f< = value< 1.0f(注意少于一个)。
当将此值乘以更大的范围时,浮点精度自然会降低,这意味着该值可能会超出等效范围。
例如,如果我从以下值开始:
0.99999983534521f
然后将它乘以100,我得到:
100.000000000000f
哪个好,但是如何将浮点表示减少为最接近的浮点值仍然小于100?
我发现了这个小手册:
union test
{
int integer;
float floating;
};
test value;
value.floating = 1.0f;
printf("%x\n", value.integer);
然后我取出那个十六进制值并将其减少一个十六进制数字,然后明确地设置它:
unsigned int almost_one = 0x3f7fffff;
float value = 1.0f;
if (value >= 1.0f) std::memcpy(&value, &almost_one, sizeof(float));
这对于这个特定的值很有效,但是我可以使用更通用的方法吗?
我希望有一条神奇的指令,我不知道我能用它来实现这个目标!
编辑:这里有很多答案,std :: nextafter看起来就像我追求的那样。不幸的是我还不能使用C ++ 11数学库,所以这对我不起作用。为了节省复杂的事情,我将用C ++ 11标记这个问题并接受Mike的答案。
我已经为C ++ 03开始了一个新问题:Alternative to C++11's std::nextafter and std::nexttoward for C++03?
答案 0 :(得分:6)
我希望有一条神奇的指令,我不知道我能用它来实现这个目标!
如果你有一个C ++ 11(或C99)标准库,那么来自std::nextafter(value, 0.0f)
(或来自<cmath>
的{{1}})的nextafter
会给你最大可表示值小于<math.h>
。
它在第一个参数之后,在第二个参数的方向上给出“下一个”不同的值;所以这里,下一个明显的值接近于零。
答案 1 :(得分:0)
对于这种困惑感到抱歉,我第一次错过了这一点。您所寻找的当然是 unit in the last place (ULP) ,与 machine epsilon 密切相关。这是演示:
#include <iostream>
#include <cmath>
#include <cassert>
float compute_eps() {
float eps = 1.0f;
// Explicit cast to `float` is needed to
// avoid possible extra precision pitfalls.
while (float(1.0f + eps) != 1.0f)
eps /= 2.0f;
return eps;
}
float ulp(float x) {
int exp;
frexp(x, &exp);
static float eps = compute_eps();
return eps * (1 << exp);
}
main() {
float x = 100.0f;
float y = x - ulp(x);
float z = nextafterf(x, 0.0f);
assert(y == z);
std::cout.precision(20);
std::cout << y << std::endl;
std::cout << z << std::endl;
}
请理解,这个答案更多是作为教育而不是实际的。我想显示必须涉及哪些数量(来自理论)以确定相邻的浮点数。例如,当然可以使用std::numeric_limits<T>::epsilon()
来确定机器epsilon。或者继续使用防弹nextafterf
(可能比我的演示更有效地实现)来直接获取相邻的浮点数。总而言之,不要太认真地判断这个答案。
注意:指数的特殊情况(如 NaN ,无穷大,次正常等)在这个演示中没有处理。但是如何扩展这个演示来支持它们非常简单。