我目前正在将
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
的值t。 [...]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());
}
输出
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 系统上注意到了这个问题。)
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
中表示,则行为未定义。