Home > Software engineering >  1.0 / 0.0 - valid statement?
1.0 / 0.0 - valid statement?

Time:12-31

I just wanted to apply an infinity load-factor to a std::set<> because I wanted to have a fixed number of buckets. So I used a load-factor of 1.0f / 0.0f because it's shorter to write than numeric_limits<float>::infinity(). MSVC give an error because of the division by zero. clang-cl and clang compiled the code without errors. So which compiler is right ?

CodePudding user response:

C 20 Standard

According to the C standard division / modulo with the second operand being 0 is always undefined behavior, both for integral & floating point types:

7.6.5 Multiplicative operators (emphasis mine)

(4) The binary / operator yields the quotient, and the binary % operator yields the remainder from the division of the first expression by the second. If the second operand of / or % is zero the behavior is undefined. For integral operands the / operator yields the algebraic quotient with any fractional part discarded; if the quotient a/b is representable in the type of the result, (a/b)*b a%b is equal to a; otherwise, the behavior of both a/b and a%b is undefined.

So from a pure standard perspective dividing by 0 is always undefined behavior.


What the compilers do

Given that it's undefined behavior you can't rely on any compiler to produce a consistent result for this - but nonetheless here's what currently happens:

Sample program: godbolt

#include <limits>

int main() {
    float f = 1.0f / 0.0f;
    //float f = std::numeric_limits<float>::infinity();
    if(f == std::numeric_limits<float>::infinity())
        return 123;
    else
        return 345;
}
  • clang & icc: no warnings / errors, will assume 1.0 / 0.0 is infinity, can do constant folding
  • gcc: no warnings / errors, but won't do constant folding for it (so the division 1.0 / 0.0 will happen at runtime!)
  • msvc: produces an error: error C2124: divide or mod by zero

So 3 different results, depending on which compiler you're using.

In comparison to std::numeric_limits<float>::infinity(), which will work correctly for all 4 of them.


Conclusion

Always use std::numeric_limits<float>::infinity(), since dividing by zero is always undefined behavior.

If you want to shorten it you can easily do so, e.g.:

template<std::floating_point T>
constexpr T Inf = std::numeric_limits<T>::infinity();

// usage:
float f = Inf<float>;
double d = Inf<double>;

or

constexpr float fInf = std::numeric_limits<float>::infinity();
constexpr double dInf = std::numeric_limits<double>::infinity();

// usage:
float f = fInf;
double d = dInf;

or something similar.

CodePudding user response:

There's a nice workaround: 1.0 / []() constexpr { return 0.0; }()

  • Related