为什么std::round有返回long和long long的版本,而std::floor、std::ceil和std::trunc没有?

10

我正在查看cppreference中的这些相关标准函数族:std::round, std::floor, std::ceilstd::trunc

是否有任何理由使std::round是唯一提供特定签名为longlong long的返回类型吗?除了历史原因以外,我很难想到其他的理由,但std::round是在C++11中较近才添加的。


这不是完全重复,但它回答了你的问题(“std :: floor”返回值的第一个谷歌搜索结果)。 - asynts
1
返回整数没有意义。std::round 只是因为某种原因而有它。 - asynts
@asynts 这是一篇有趣的阅读,但它并没有回答我的问题。我想象中,与问题中强调的限制相同的限制将适用于 std::round,但标准库以某种方式为其提供了特定的函数,而不是 floor。 - Alessandro Teruzzi
std::floor的情况下,直接进行隐式转换即可完成工作。那么为什么要编写一个函数来完成它呢? - ALX23z
6
很可能是因为 C 语言有完全相同的函数集合,但了解为什么 C 没有添加 ceil / floor / trunclong / long long 版本会很有趣。 - Turtlefight
1
@ALX23z 你说的 std::floor 是指 std::trunc,对吧? :-) 区别在于使用强制转换可能会导致溢出,即未定义行为,而使用 std::trunc 则不会。 - danadam
1个回答

0
这只是我的猜测,但我认为原因可能是,floorceiltrunclll版本可以使用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

你可能仍然在问:“无法使用llrint实现llround吗?” 结果证明不能。 FE_TONEAREST舍入模式对于一半的情况采用偶数舍入,而round则采用远离零。
此外,请注意编译器访问或修改浮点环境的支持可能还不够完善:
main.cpp:3: warning: ignoring ‘#pragma STDC FENV_ACCESS’ [-Wunknown-pragmas]
    3 | #pragma STDC FENV_ACCESS ON

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接