std::chrono::round 对超出范围的值的行为是否符合预期?

问题描述 投票:0回答:1

我目前正在将

std::chrono::duration<float>
舍入为
std::chrono::duration<uint32_t>
,当我给它超出范围的值时,它会舍入为
1s
而不是
4294967295s

看看标准,上面写着

template <class ToDuration, class Rep, class Period>   
constexpr ToDuration round(const duration<Rep, Period>& d);

[...]
返回:

ToDuration
中可表示的最接近于
d
的值t。 [...]

这是我的确切代码:

#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());
}

输出

float:    340282346638528859811704183484516925440.000000
uint32_t: 1
 int32_t: -2147483647
uint64_t: 9223372036854775809
 int64_t: -9223372036854775807

如您所见,其他整数类型的行为也很奇怪。与

std::lround
等人不同,
std::chrono::round
没有说明如果浮点输入超出范围,则未定义。

我错过了什么吗?

(就上下文而言,我在 x86_64 上使用

clang
版本
14.0.0-1ubuntu1.1
编译了这个,但我首先在使用
gcc
的 ARMv7 系统上注意到了这个问题。)

c++ c++17 rounding undefined-behavior c++-chrono
1个回答
0
投票

duration<Rep, Ratio>
是围绕
Rep
的简单薄包装纸。在您的示例中,
Rep
float
的参数中的
round
和结果中的
uint32_t

作为一个薄包装器,

duration
不会改变
Rep
的基本行为,例如溢出和转换。这样做会增加开销,而这通常是不可取的。

如果需要诸如溢出检查之类的特定行为,

chrono
可以通过允许
duration<safe_int>
来实现这一点,其中
safe_int
是模拟整数算术但检查溢出的假设类类型。此类库的现实世界示例存在,并且不需要需要特殊调整才能与
chrono
一起使用。

对于本问题中所询问的

float
uint32_t
,未定义的行为会导致
float
uint32_t
级别,而不是
chrono
级别。 具体来说,将
float
转换为
uint32_t
时,如果
float
中的截断值无法在
uint32_t
中表示,则行为未定义。

© www.soinside.com 2019 - 2024. All rights reserved.