【问题标题】:Why does std::round offer versions returning long and long long while std::floor, std::ceil, std::trunc don't?为什么 std::round 提供返回 long 和 long long 的版本,而 std::floor、std::ceil、std::trunc 不提供?
【发布时间】:2021-12-17 04:53:53
【问题描述】:

我在 cppreference 中查看了这些相关的标准函数系列:std::roundstd::floorstd::ceilstd::trunc

为什么std::round 是唯一一个为longlong long 提供特定签名作为返回类型的人?除了历史原因,我很难想出任何原因,但最近 C++11 中添加了 std::round

【问题讨论】:

  • This isn't 100% a duplicate, but it answers your question。 (“std::floor的返回值”的第一个谷歌结果)
  • 返回整数没有意义。 std::round 只是出于某种原因。
  • @asynts 这是一个有趣的阅读,但它没有回答我的问题,我会想象问题中突出显示的相同限制将适用于 std::round,但不知何故标准库提供了特定的它的功能,而不是地板。
  • 很可能是因为 c 有 exact same set of functions,但有趣的是知道为什么 c 没有为 ceil / floor / @ 添加 long / long long 版本987654341@.
  • @ALX23z std::floor 你的意思是std::trunc,对吧? :-) 不同之处在于,使用强制转换可以溢出,即 UB,而使用 std::trunc 则不能。

标签: c++ c++11


【解决方案1】:

这只是我的猜测,但我认为原因可能是,floorceiltrunclll 版本可以使用rint 和不同的rounding modes 来实现。例如,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 exception。我们的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 舍入模式对中途情况执行 rounding to even,而 round 执行远离零的情况。

另外请注意,编译器对访问或修改 floating point environment 的支持可能尚未完全实现:

main.cpp:3: warning: ignoring ‘#pragma STDC FENV_ACCESS’ [-Wunknown-pragmas]
    3 | #pragma STDC FENV_ACCESS ON

(相关问题:Adding two floating-point numbers

【讨论】:

    猜你喜欢
    • 2012-09-28
    • 1970-01-01
    • 2013-03-24
    • 2014-08-17
    • 2021-01-13
    • 2020-10-26
    • 2017-08-15
    • 2013-11-30
    相关资源
    最近更新 更多