为什么 std::round 提供返回 long 和 long long 的版本,而 std::floor、std::ceil、std::trunc 则不提供?

Ale*_*zzi 10 c++ c++11

我正在 cppreference 中查看这些相关的标准函数系列:std::roundstd::floor和。std::ceilstd::trunc

有什么理由为什么std::round是唯一一个提供特定签名longlong long作为返回类型的吗?我正在努力思考除了历史之外的任何原因,但std::round最近才在 C++11 中添加了这一点。

dan*_*dam 0

这只是我的猜测,但我认为原因可能是,lll的版本可以使用rint和不同的floor入模式ceiltrunc实现。例如,可以这样实现:llfloor()

\n
#include <cfenv>\n#include <cmath>\n#pragma STDC FENV_ACCESS ON\n\nlong long llfloor(double arg) {\n    auto save_round = std::fegetround();\n    std::fesetround(FE_DOWNWARD);\n    auto ret = llrint(arg);\n    std::fesetround(save_round);\n    return ret;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

l/ versions的一个很好的属性ll是,当结果超出结果类型的范围时,它们会引发FE_INVALID 异常。我们的llfloor()也这样做:

\n
#include <iostream>\n#include <limits>\n\nint main() {\n    double input = std::nextafter(std::numeric_limits<long long>::max(), INFINITY);\n    std::cout << "input  =  " << std::fixed << input << "\\n";\n\n    std::feclearexcept(FE_ALL_EXCEPT);\n    auto result = llfloor(input);\n    if (std::fetestexcept(FE_INVALID)) {\n        std::cout <<"FE_INVALID was raised\\n";\n    }\n    std::cout << "result = " << result << "\\n";\n}\n
Run Code Online (Sandbox Code Playgroud)\n

输出是(或参见godbolt):

\n
input  =  9223372036854777856.000000\nFE_INVALID was raised\nresult = -9223372036854775808\n
Run Code Online (Sandbox Code Playgroud)\n

您可能仍然会问“不能llround用 来实现llrint吗?”。事实证明不能。FE_TONEAREST 舍入模式对于中间情况舍入为均匀round,而远离零。

\n

另请注意,编译器对访问或修改浮点环境的支持可能尚未完全实现:

\n
main.cpp:3: warning: ignoring \xe2\x80\x98#pragma STDC FENV_ACCESS\xe2\x80\x99 [-Wunknown-pragmas]\n    3 | #pragma STDC FENV_ACCESS ON\n
Run Code Online (Sandbox Code Playgroud)\n

(相关问题:两个浮点数相加

\n