提问人:Zachary Peterson 提问时间:11/12/2023 更新时间:11/17/2023 访问量:118
如何在编译时获得大浮点数的下限
How Can I Get The Floor Of A Large Floating-Point Number At Compile-Time
问:
我正在使用 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;
答:
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>;
scalebn
constexpr
0赞
Zachary Peterson
11/17/2023
我已经制作了一个模板化版本,我刚刚用我的实现更新了答案。
0赞
Red.Wave
11/17/2023
很好👍🏻考虑和未来的 C++23 版本。这样会更可靠。scalebn
radix
评论
abs(f)>(1<<23)
floor(f)==f
long long
n