在C ++中查找最接近的浮点值小于特定的整数值?

时间:2013-05-01 16:42:08

标签: c++ c++11 floating-point floating-accuracy

我的输入浮点值为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?

2 个答案:

答案 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 无穷大次正常等)在这个演示中没有处理。但是如何扩展这个演示来支持它们非常简单。