Home > Software design >  How to bound a floating-point arithmetic result?
How to bound a floating-point arithmetic result?

Time:06-02

Floating-point operations like x=a/b are usually not exactly representable so the CPU has to do rounding. Is it possible to get the two floats x_low and x_up that are respectively the highest floating point less or equals than the exact value of a/b and the lowest floating point higher or equals than a/b?

Some of the conditions are :

  • a, b, x_low, x_up and x are float
  • a and b are positive, integers (1.0f, 2.0f, etc)

CodePudding user response:

This will give you a bounds that might be too large:

#include <cmath>
#include <utility>

template<typename T>
std::pair<T, T> bounds(int a, int b) {
    T ta = a, tb = b;
    T ta_prev = std::nexttoward(ta), ta_next = std::nextafter(ta);
    T tb_prev = std::nexttoward(tb), tb_next = std::nextafter(tb);
    return std::make_pair(ta_prev / tb_next, ta_next / tb_prev);
}

CodePudding user response:

An easy way to do it is to do the division in higher precision and get the upper/lower bound on conversion to float:

struct float_range {
    float lower;
    float upper;
};

float_range to_float_range(double d) {
    float as_float = static_cast<float>(d);
    double rounded = double{as_float};
    if (std::isnan(as_float) || rounded == d) {
        // No rounding done
        return { as_float, as_float };
    }
    if (rounded < d) {
        // rounded down
        return { as_float, std::nextafter(as_float, std::numeric_limits<float>::infinity()) };
    }
    // rounded up
    return { std::nextafter(as_float, -std::numeric_limits<float>::infinity()), as_float };
}

float_range precise_divide(float a, float b) {
    return to_float_range(double{a}/double{b});
}
  • Related