假设我们有一个以纳秒为单位的时间戳,我们需要从中减去 2.5 秒。所以我创建了这样的代码:
nanoseconds current_ts{1645546551805673592};
float diff = 2.5;
nanoseconds target_ts = duration_cast<nanoseconds>(current_ts - (seconds{1} * diff));
但它返回的是
1645546549305673592
,而不是预期结果 (1645546556876652544
)。经过一些实验,我发现问题在某种程度上与 float
类型有关,因为如果我将其更改为 double ,它就可以正常工作。如果我将 current_ts
移到 duration_cast
之外,它也可以正常工作
为什么会发生这种情况?跟float精度有关系吗?
这是最小的例子:
#include <chrono>
#include <iostream>
#include <list>
int main() {
using namespace std::chrono;
nanoseconds current_ts{1645546551805673592};
float context_pre_event_image_sec_ = 2.5;
nanoseconds target_ts = current_ts - duration_cast<nanoseconds>((seconds{1} * context_pre_event_image_sec_));
nanoseconds target_ts_2 = duration_cast<nanoseconds>(current_ts - (seconds{1} * context_pre_event_image_sec_));
std::cout << current_ts.count() << std::endl;
std::cout << target_ts.count() << std::endl;
std::cout << target_ts_2.count() << std::endl;
}
第二个输出是预期的,第三个是意外的
std::duration
对象由Period
(表示为秒的分数)和Rep
(任意数字类型)参数化。
operator-
的 std::duration
使用 std::common_type
辅助模板类型来推导出周期的最佳类型(直观上,最大公约数)和 Rep
。
对于
Rep
,使用以下规则:
如果
是有效类型,则 [std::common_type] 的成员类型表示该类型std::decay<decltype(false ? std::declval<T1>() : std::declval<T2>())>::type
在您的情况下,T1 和 T2 分别是
int64_t
和 float
。三元运算符的类型是对两种类型应用隐式转换的结果,这又是float
。
当然,浮点数无法准确表示预期结果。您可以通过将 1645546549305673592 插入这个方便的 IEEE-754 工具来快速验证这一点。