Mad*_*Tux 5 c++ rounding undefined-behavior c++-chrono c++17
我目前正在将 a 舍入std::chrono::duration<float>为std::chrono::duration<uint32_t>,当我给它超出范围的值时,它会舍入为 ,1s而不是4294967295s。
看看标准,它说
Run Code Online (Sandbox Code Playgroud)template <class ToDuration, class Rep, class Period> constexpr ToDuration round(const duration<Rep, Period>& d);[...]
返回:其中可表示的值 tToDuration最接近d。[...]
这是我的确切代码:
#include <chrono>
#include <cstdio>
#include <limits>
#include <cstdint>
int main()
{
std::chrono::duration<float> seconds{std::numeric_limits<float>::max()};
printf("float: %f\n", seconds.count());
printf("uint32_t: %u\n", std::chrono::round<std::chrono::duration<uint32_t>>(seconds).count());
printf(" int32_t: %d\n", std::chrono::round<std::chrono::duration<int32_t>>(seconds).count());
printf("uint64_t: %lu\n", std::chrono::round<std::chrono::duration<uint64_t>>(seconds).count());
printf(" int64_t: %ld\n", std::chrono::round<std::chrono::duration<int64_t>>(seconds).count());
}
Run Code Online (Sandbox Code Playgroud)
哪个输出
float: 340282346638528859811704183484516925440.000000
uint32_t: 1
int32_t: -2147483647
uint64_t: 9223372036854775809
int64_t: -9223372036854775807
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,其他整数类型的行为也很奇怪。与等人不同的是std::lround,std::chrono::round如果浮点输入超出范围,则不会说任何未定义的内容。
我错过了什么吗?
(就上下文而言,我使用 x86_64 上的clang版本编译了此文件14.0.0-1ubuntu1.1,但我首先在使用 的 ARMv7 系统上注意到了该问题gcc。)
duration<Rep, Ratio>是一个简单的薄包装纸Rep。在你的例子中Rep是float在参数round和uint32_t结果中。
作为一个薄包装器,duration不会改变Rep溢出和转换等操作的基本行为。这样做会增加开销,而这通常是不可取的。
如果需要特定行为(例如溢出检查),chrono则可以通过允许duration<safe_int>wheresafe_int是模拟整数算术但检查溢出的假设类类型来促进这一点。此类库的现实世界示例是存在的,并且不需要特殊调整即可与chrono.
正如在这个问题中所询问的float那样uint32_t,未定义的行为产生于float和uint32_t级别,而不是级别chrono。 具体来说,当转换float为 时uint32_t,如果 中的截断值float无法在 中表示,则行为未定义uint32_t。
正如下面的评论中所讨论的,该标准是否真的这么说了,还有一个悬而未决的问题。为了进一步实现这一目标,感兴趣的各方应提交 LWG 问题:
http://cplusplus.github.io/LWG/lwg-active.html#submit_issue
然后 LWG 将决定是否存在错误,如果存在,如何最好地补救。
相关链接: