This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.

### 3503. `chrono::ceil` has surprising requirement

Section: 27.5.8 [time.duration.cast] Status: New Submitter: Jonathan Wakely Opened: 2020-11-18 Last modified: 2020-11-29

Priority: 3

View all other issues in [time.duration.cast].

View all issues with New status.

Discussion:

27.5.8 [time.duration.cast] p7 requires that the return value is "The least result `t` representable in `ToDuration` for which `t >= d`".

This means that `chrono::ceil<chrono::microseconds>(chrono::duration<float, milli>(m)).count()` is required to be the smallest integer `n` such that `(float)n == m*1000.0f`, which might be less than the mathematically correct value of `m x 1000`.

(The specific values below assume `float` uses the IEEE binary32 format and default rounding, but similar problems will exist for other formats, even if the specific values are different.)

For example, if `m == 13421772.0f` then the naively expected result is `n == 13421772000`, but the standard requires `n == 13421771265`, a significantly lower value. This surprising result is a consequence of how the `chrono::ceil` spec interacts with floating-point arithmetic, due to the fact that for the integers in the range `[13421770753, 13421772799]`, only one can be exactly represented as 32-bit `float`. All but that one will be rounded to a different value when converted to `float`.

A straightforward implementation of `chrono::ceil` will produce `(long long)(13421772.0f * 1000)` which is `13421771776`, which is less than the expected result, but compares equal using the `t >= d` expression. That expression converts both operands to their `common_type`, which is `chrono::duration<float, micro>`. That means we compare `(float)13421771776 >= (13421772.0f * 1000)` which is `true`. But the spec requires an even worse result. All integers in `[13421771265, 13421771776)` are also rounded to that value when converted to `float`. That means `chrono::microseconds(13421771265)` is "the least result representable in `ToDuration` for which `t >= d`".

Meeting the "least result" requirement is impractical, and unhelpful. The straightforward result `13421771776` is already lower than the naively expected result (which is surprising for a "ceil" function). To meet the standard's requirements the implementation would have to do extra work, just to produce an even lower (and even more surprising) result.

It might be impractical to require the naively expected value to be returned (the additional work might have unacceptable performance implications), but the standard should at least permit the straightforward result instead of requiring an even worse one.

The same problem almost certainly exists for `chrono::floor` in reverse.

[2020-11-29; Reflector prioritization]

Set priority to 3 during reflector discussions.

Proposed resolution: