【问题标题】:Are infinite std::chrono::duration objects legal?无限 std::chrono::duration 对象合法吗?
【发布时间】:2018-09-06 17:22:51
【问题描述】:

像这样制作和使用具有无穷大的std::chrono::duration<double>'s 是否合法?

std::chrono::duration<double>{ std::numeric_limits<double>::infinity() };

它会表现得“像我预期的那样”,在与其他持续时间相加或相减时保持无限值吗?

我已经挖掘了 cppreference,但我发现讨论这个问题的唯一内容是duration_cast 上的页面,并指出:

当浮点值为 NaN、无穷大或太大而无法由目标的整数类型表示时,从浮点持续时间转换为整数持续时间会受到未定义行为的影响。否则,转换为整数持续时间会被截断,就像将任何 static_cast 转换为整数类型一样。

这似乎暗示它是合法的,但只是以一种反手的方式。

(我使用该类型来表示“请在 X 秒内唤醒我”的方式,而正无穷大是一个有用的标记来表示“我真的不在乎我什么时候醒来”)

【问题讨论】:

  • 确定以无穷大作为操作数的运算结果的规则很简单:用有限数 x 代替无穷大,并在 x 趋于无穷大时取其极限。来自What Every Computer Scientist Should Know About Floating-Point Arithmetic
  • @Yola 我不是用双精度数做算术,我用std::chrono::duration&lt;double&gt; 做它,它可能对操作的域和范围有自己的看法。特别是因为std::chrono::duration&lt;some integral type&gt; 是模板的更常见用例。
  • 你会的。 constexpr duration&amp; operator+=(const duration&amp; d); Effects: As if by : rep_ += d.count();constexpr rep count() const; Returns: rep_. 在你的情况下,_repdouble
  • 还要考虑你的设计是否会更好,用一个单独的状态变量来表示“不关心”而不是一个显着的值。如果您使用双打来表示时间,我怀疑您是否担心紧凑性。我很好奇您想要使用浮点值来表示时间的原因是什么。除非您需要覆盖很大的范围并在更短的时间内具有更高的精度,否则我自己想不出一个好的用途。如果您想要更高的精度,您可以考虑使用 std::chrono::microseconds。
  • 浮点在很多方面都比量化值更方便,并且代码与一些将时间视为浮点秒数的东西互操作(即不是 std::chrono,只是双)。

标签: c++ c++11 language-lawyer chrono


【解决方案1】:

std::chrono::duration&lt;double&gt; 的值 infinity 的行为与算术运算符的预期相同。

std::chrono::duration&lt;double&gt; 很好

[time.duration] 定义了存在于 Rep 上的条件 template&lt;class Rep&gt; std::chrono::durationdouble 是明确允许的(根据 [time.duration]/2),没有不允许的特殊值:

Rep 应为算术类型或模拟算术类型的类。

std::numeric_limits&lt;double&gt;::infinity() 很好

[time.duration.arithmetic][time.duration.nonmemberdefine] 定义duration 上算术运算符的行为。对于每个operator♦ 和给定两个duration 对象AB 持有doubleabA♦B 效果就像a♦b 一样。例如+:

在后面的函数描述中,CD代表函数的返回类型。 CR(A, B) 代表common_­type_­t&lt;A, B&gt;

template<class Rep1, class Period1, class Rep2, class Period2>
  constexpr common_type_t<duration<Rep1, Period1>, duration<Rep2, Period2>>
    operator+(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);

返回:CD(CD(lhs).count() + CD(rhs).count())

这明确意味着以下将按预期运行:

const double infinity = std::numeric_limits<double>::infinity();
std::chrono::duration<double> inf{ infinity };
std::chrono::duration<double> one{ 1.0 };
inf + one; // as if std::chrono::duration<double>{ infinity + 1.0 };

【讨论】:

    【解决方案2】:

    duration_values trait 有一个 max() 值用于此目的:

        std::chrono::duration<double>::max();
    

    不要使用infinity。如果您将来碰巧将这样的持续时间转换为基于整数的类型,您最终可能会得到 UB。

    【讨论】:

    • 你写了“为此目的”。回答OP问题的目的是什么? OP 问题是“是否允许无限并按预期工作?”。你写的东西有价值,但它并没有回答我认为的问题。
    • 目的是“我真的不在乎我什么时候醒来”。
    • std::chrono::duration&lt;double&gt;::max() 确实没有合适的属性来充当(方便的)哨兵; infinity 的使用允许对返回值进行一些加/减值,而不会使其不再是标记值。
    • 我认为 inf 作用与 max 不同的地方是如果 Period(持续时间的第二个操作数)不 = 1。当然,很自然地只使用 1(秒)和 double,但它可以定义一天或微秒的时间段。当您在不同周期的双倍持续时间之间进行转换时,值 max() 将不会被保留,而值 inf 将被保留,供以后比较。
    • 查看 std::chrono::duration_cast 的实现:__cast(const duration&lt;_Rep, _Period&gt;&amp; __d) { typedef typename _ToDur::rep __to_rep; return _ToDur(static_cast&lt;__to_rep&gt;(static_cast&lt;_CR&gt;(__d.count()) * static_cast&lt;_CR&gt;(_CF::num) / static_cast&lt;_CR&gt;(_CF::den))); } 你可以看到它没有考虑 max() 并且很可能在进行类型转换或缩放时溢出信息。
    猜你喜欢
    • 1970-01-01
    • 2018-02-03
    • 2016-07-20
    • 1970-01-01
    • 2012-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多