我正在查看cppreference中的这些相关标准函数族:std::round
, std::floor
, std::ceil
和std::trunc
。
是否有任何理由使std::round
是唯一提供特定签名为long
和long long
的返回类型吗?除了历史原因以外,我很难想到其他的理由,但std::round
是在C++11中较近才添加的。
我正在查看cppreference中的这些相关标准函数族:std::round
, std::floor
, std::ceil
和std::trunc
。
是否有任何理由使std::round
是唯一提供特定签名为long
和long long
的返回类型吗?除了历史原因以外,我很难想到其他的理由,但std::round
是在C++11中较近才添加的。
floor
、ceil
和trunc
的l
和ll
版本可以使用rint和不同的舍入模式来实现。例如,llfloor()
可以像这样实现:#include <cfenv>
#include <cmath>
#pragma STDC FENV_ACCESS ON
long long llfloor(double arg) {
auto save_round = std::fegetround();
std::fesetround(FE_DOWNWARD);
auto ret = llrint(arg);
std::fesetround(save_round);
return ret;
}
l
/ll
版本的一个好处是,当结果超出结果类型的范围时,它们会引发 FE_INVALID 异常。我们的 llfloor()
也是如此:
#include <iostream>
#include <limits>
int main() {
double input = std::nextafter(std::numeric_limits<long long>::max(), INFINITY);
std::cout << "input = " << std::fixed << input << "\n";
std::feclearexcept(FE_ALL_EXCEPT);
auto result = llfloor(input);
if (std::fetestexcept(FE_INVALID)) {
std::cout <<"FE_INVALID was raised\n";
}
std::cout << "result = " << result << "\n";
}
输出结果为(或在godbolt中查看):
input = 9223372036854777856.000000
FE_INVALID was raised
result = -9223372036854775808
main.cpp:3: warning: ignoring ‘#pragma STDC FENV_ACCESS’ [-Wunknown-pragmas]
3 | #pragma STDC FENV_ACCESS ON
(相关问题:如何将两个浮点数相加)
std::round
只是因为某种原因而有它。 - asyntsstd::floor
的情况下,直接进行隐式转换即可完成工作。那么为什么要编写一个函数来完成它呢? - ALX23zceil
/floor
/trunc
的long
/long long
版本会很有趣。 - Turtlefightstd::floor
是指std::trunc
,对吧? :-) 区别在于使用强制转换可能会导致溢出,即未定义行为,而使用std::trunc
则不会。 - danadam