-
Notifications
You must be signed in to change notification settings - Fork 171
Description
https://tc39.es/proposal-temporal/#sec-isvalidduration
- Let normalizedSeconds be days × 86,400 + hours × 3600 + minutes × 60 + seconds + ℝ(𝔽(milliseconds)) × 10**-3 + ℝ(𝔽(microseconds)) × 10**-6 + ℝ(𝔽(nanoseconds)) × 10**-9.
- NOTE: The above step cannot be implemented directly using floating-point arithmetic. Multiplying by 10**-3, 10**-6, and 10**-9 respectively may be imprecise when milliseconds, microseconds, or nanoseconds is an unsafe integer. This multiplication can be implemented in C++ with an implementation of std::remquo() with sufficient bits in the quotient. String manipulation will also give an exact result, since the multiplication is by a power of 10.
I think this whole thing is somewhat unclear, and comes off as self-contradictory without careful inspection.
It comes off as self contradictory since it explicitly uses floating point intermediates and then tells you not to do floating point arithmetic. It's not actually self-contradictory since it's talking specifically about the arithmetic, but it's certainly confusing.
The mention of remquo is also not very useful: Not everyone is using C++, and it's not immediately clear how remquo would be used.
Ultimately, @nekevss and I are still not sure if what we have implemented in temporal_rs is correct.
What we've done is, after converting to a float and back to an integer to handle the ℝ(𝔽(..)) bits, is done the computation in the space of nanoseconds instead of seconds.
I can see why the spec chose not to write it this way: the max safe nanosecond value is 10⁹×2⁵³, which is greater than the largest integer size in standard C++.
Rust has i128, though, so we don't have that problem. It would be nice to know if this implementation is also acceptable. Perhaps the spec text can be improved around this to mention this as an option.