Finding the closest floating point value less than a specific integer value in C++?

前端 未结 2 429
说谎
说谎 2020-12-22 03:18

I have an input floating point value that is 0.0f <= value < 1.0f (note less than one).

When multiplying this value up to a larger range, naturally the floatin

相关标签:
2条回答
  • 2020-12-22 03:48

    I'm hoping there's a magic instruction I'm not aware of that I can use to achieve this!

    If you've got a C++11 (or C99) standard library, then std::nextafter(value, 0.0f) from <cmath> (or nextafter from <math.h>) will give you the largest representable value smaller than value.

    It gives the "next" distinct value after the first argument, in the direction of the second; so here, the next distinct value closer to zero.

    0 讨论(0)
  • 2020-12-22 03:48

    Sorry for the confusion, I've missed the point at the first time. What you are looking for is of course unit in the last place (ULP), which is closely related to machine epsilon. Here is the demo:

    #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;
    }
    

    Please, understand that this answer was intended more as educational rather than practical. I wanted to show which quantities (from theory) have to be involved in order to determine neighbouring floating-point numbers. Of course one could use std::numeric_limits<T>::epsilon() to determine machine epsilon, for example. Or go ahead and use the bullet-proof nextafterf (which is likely to be implemented much more efficiently than my demo) to directly get the neighbouring floating-point number. All in all, don't judge this answer too seriously.

    NOTE: Special cases of exponent (like NaN, infinity, subnormal, and etc.) are not handled in this demo. But it's pretty straightforward how to extend this demo to support them.

    0 讨论(0)
提交回复
热议问题