How can I get the floor of a large floating-point number at compile-time?

163 Views Asked by At

I'm writing a compile-time math library using c++20, I already have floor/ceiling/abs/etc. but the method I am currently using to get the floor of a float is n >= 0.0f ? (float)(long long)n : (float)(long long)n - 1.0f; which is a pretty typical fast floor function. however for floats larger than long long max value this returns junk because I cast to a long long. I know using floorf works for large floats but it isn't constexpr (until c++23 which is still in preview). However I can't just copy what the stl is doing because it calls an intrinsic which itself isn't constexpr. Any information that could point me in the right direction would be much appreciated.

1

There are 1 best solutions below

6
Zachary Peterson On BEST ANSWER

As stated by @chtz and @IgorTandetnik floats large enough to be larger than long long max value can't store a fractional part so just return the input.

For floats:

if(abs(n) > (float)(1 << 23))
{
    return n;
}
else
{
    return n >= 0.0f ? (float)(long long)n : (float)(long long)n - 1.0f;
}

For doubles:

if(abs(n) > (double)(1i64 << 52))
{
    return n;
}
else
{
    return n >= 0.0 ? (double)(long long)n : (double)(long long)n - 1.0;
}

Edit: Here is a templated version with concepts:

#include <type_traits>

template <std::floating_point Type>
static constexpr Type FloorF(const Type& n) noexcept
{
    static constexpr Type MaxPrecision = 1i64 << (std::numeric_limits<Type>::digits - 1);

    return n > MaxPrecision ? n :
        n >= (Type)0 ? (Type)(long long)n : (Type)(long long)n - (Type)1;
}