Date
2024-09-15.00:00:00
Message id
14388

Content

[ 2024-09-19; Jonathan adds a note ]

Another problem discovered by STL occurs when the result is floating-point. We can't just add 1. In fact, there is no requirement for whole-numberness.

For example, when converting from `double` to `float`:

chrono::floor<duration<float>>(duration<double>(0.1))
This produces the result duration<float>(-0.9f) with the reference implementation in P0092R1, and the implementations in libstdc++, libc++, and MSVC. This is because 0.1f <= 0.1 is false, so the result is duration<float>(0.1f - 1.0f), which is not the greatest value representable that is not greater than `1.0`. The correct result according to the standard would be duration<float>(nexttoward(0.1f, -HUGE_VAL)), but we can't use `nexttoward` for arbitrary `treat_as_floating_point` types, only for `float`, `double` and `long double`.

STL found cases where ceil<duration<float>>(duration<double>(x)) produces a value that is lower than `x`, e.g. for `x = 13421771263.0` the result is `13421770752.0f`.

A possible resolution for this problem would be to make `ceil` and `floor` behave exactly like `duration_cast` when the result is a floating-point type. This would still permit a `ceil` that is smaller than the input (and a `floor` result that is larger) but that's just a consequence of converting to a floating-point type with less precision. We could also specify that for non-floating-point result types, the effects should be what all known implementations do. That would mean the behaviour is at least predictable and explainable, even if the result is not always the correct mathematical value.