如何在编译时获得大浮点数的下限

How Can I Get The Floor Of A Large Floating-Point Number At Compile-Time

提问人:Zachary Peterson 提问时间:11/12/2023 更新时间:11/17/2023 访问量:118

问:

我正在使用 c++20 编写一个编译时数学库,我已经有 floor/ceiling/abs/etc.,但我目前用来获取浮点数底部的方法是这是一个非常典型的快速底部函数。但是,对于大于 long long max 值的浮点数,这将返回垃圾,因为我转换为 long long。我知道使用 floorf 适用于大型浮点数,但它不是 constexpr(直到仍处于预览阶段的 c++23)。但是,我不能只复制 stl 正在做的事情,因为它调用了一个内部函数,它本身不是 constexpr。任何能为我指明正确方向的信息将不胜感激。n >= 0.0f ? (float)(long long)n : (float)(long long)n - 1.0f;

C Visual-C++ 浮点 C++20 地板

评论

4赞 chtz 11/12/2023
假设您有 IEEE754 float32,则如果 , .abs(f)>(1<<23)floor(f)==f
2赞 Igor Tandetnik 11/12/2023
无论如何,大于 64 位的 64 位浮点数不可能有小数部分:尾数中没有足够的位来表示它。也许您可以添加一个案例,如果足够大,则将其原封不动地返回。long longn

答:

1赞 Zachary Peterson 11/12/2023 #1

如 @chtz 和 @IgorTandetnik 所述,浮点数大到足以大于 long、long max 值,不能存储小数部分,因此只需返回输入即可。

对于浮标:

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

对于双打:

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

编辑:这是一个带有概念的模板化版本:

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

评论

0赞 Red.Wave 11/12/2023
请使用 中的定义代替幻数。它是处理算术类型的可移植方式。std::numeric_limits<float><limits>
1赞 Zachary Peterson 11/14/2023
我最终确实为此创建了一个常量,因为不使用幻数,但是numeric_limits这个常数在哪里?我假设您的意思是执行 1 << (std::numeric_limits<float>::d igits - 1),但无论哪种方式,我都会定义一个单独的常量。
0赞 Red.Wave 11/14/2023
您可以将其设置为模板以避免重复。可移植的方式将不是简单的shift()。但不是在 C++23 之前。std::scalebn(lim::radix, lim::digits -1)using lim=std:: numeric_limits<float>;scalebnconstexpr
0赞 Zachary Peterson 11/17/2023
我已经制作了一个模板化版本,我刚刚用我的实现更新了答案。
0赞 Red.Wave 11/17/2023
很好👍🏻考虑和未来的 C++23 版本。这样会更可靠。scalebnradix