在两个分母的 LCM 都很大的 chrono::duration 类型之间转换

Converting between chrono::duration types where the LCM of both denominators is large

我 运行 不久前遇到了一个问题,我不得不在两种不同的持续时间类型之间进行转换,如下所示:

using MyType_T = duration<long long, ratio<1, 4294967296LL>>;
using OtherType_T = duration<long long, ratio<1, 10000000>>;

当我使用 ::boost::chrono::duration_cast<>(或 std::chrono::duration_cast<>,就此而言)时,从 MyType_T 变为 OtherType_T,反之亦然,我发现当源值超过某个限制时,这些类型的转换会产生错误的结果。

仅调用 duration_cast(tm) 存在问题的原因是两个分母的 LCM 完全以 56 位表示。在这种情况下,转换是通过将 tm 中的值除以分母的 LCM,并将其作为公因子类型传递到 OtherType_T 持续时间的构造中来完成的。这将执行乘法以获得正确的值。

如您所见,如果值足够大(在本例中为 64 或更大),这意味着除法可以将所有内容移出为零,而您什么也得不到。

除了执行以下操作之外,还有什么方法可以在不丢失所有精度的情况下进行此转换?

  1. 创建一个新类型,Interim_T,它只是两者的 common_type,去掉了分母。 typedef typename common_type<MyType_T, OtherType_T>::type CommonDuration;
  2. 对 "From" 值 tm 做一个 duration_cast 到新类型以获得一些值高位。 auto highbits = duration_cast<duration<CommonDuration::rep, ratio<CommonDuration::num>>>(tm);
  3. 将原始值tm减去highbits,得到值lowbits。 auto lowbits = tm - highbits;
  4. 到高位,加上duration_cast(低位)的结果。这是结果。 auto result = highbits + duration_cast<OtherType_T>(lowbits);

我会使用浮点类型作为临时类型:

using MyType_T = duration<long long, ratio<1, 4294967296LL>>;
using OtherType_T = duration<long long, ratio<1, 10000000>>;
using OtherType_F = duration<long double, OtherType_T::period>;

MyType_T x{0x7FFFFFFFFFFF};
auto y = duration_cast<OtherType_T>(OtherType_F{x});

语法更简单,逻辑更简单。请注意,如果结果不适合 OtherType_T.

,您仍然会溢出