

The perf here won't be hurt and isn't going to involve anything complex. These libraries are very complicated and not particularly fast, I only using them when I absolutely need to.

At least not until I saw a realistic use case which demonstrates the errors of the simple FP64 + rounding approach. However, I don’t think it’s worth the complexity for the time spans. Ideally, look for a well-tested off-the-shelf library which implements either FP128 (like boost) or arbitrary-precision (like GMP but beware of the license) The inexact fractional part is then the only place where rounding considerations exist.
#EXACT MACHINE EPSILON FP64 UPDATE#
The correct fix here is to update the algorithm to correctly break apart the double into an exact integer part and inexact fractional part. And these Add* functions should convert the double argument into ticks (using banker’s rounding which is precisely what these CPU rounding instructions are doing), then do int64 addition on the value. FP64 precision is enough to represent exact ticks up to 28.5 years or something. Even in the case of Days where 1.0 represents 864 billion ticks, we need at most 1.1574 * 10^-12 to represent a single "tick" and so fractional portion will scale correctly into the integer realm.Ĭan you recall or find any of these? Without knowing what specifically was fixed, it’s not really possible to come up with a good solution.īut from general perspective, a simple rounding should be enough. more digits represented which can then have rounding error present and this is small enough that it shouldn't matter. This leaves a fractional portion which, provided the scale amount is less than floor(log10(2^53)) ( 15) digits will result in another "exact" integer representation of the fractional portion and which can be used to adjust the tick value further. The integer and fractional portions can always be split into their own "exact" values. Likewise, the primitive operations (including +, -, *, /, etc) take the input "as given", compute the result "as if to infinite precision and unbounded range", and then round the result "to the nearest representable value". There is some decently complex math that goes into this, but the premise is that the integer part of any double up to 2^53 is exactly representable. For the Add*(double value) functions that are present, this rounding consideration should all be easily mitigated within the confines of the tick range.


There are many scenarios across the entire 64-bit tick range and entire range of inputs for Days, Hours, etc when represented as a double that imprecision will be introduced. doesn’t make any sense.Īgain, this was a simplistic example showing that you cannot and should not rely on (x * y) / y returning x. If the value is seconds, not only it’s well below 1 TimeSpan tick, it’s even well below Planck time i.e. I don’t believe the example is relevant because Math.PI * double.Epsilon is about 1.48E-323.
#EXACT MACHINE EPSILON FP64 FULL#
We have had and have fixed multiple precision bugs in the last few releases, especially where inputs were being unnecessarily truncated and the full tick precision wasn't being respected. Maybe the +0.5/-0.5 rounding should still be applied, but on the ticks before truncating? Remark: maybe the variable should now be renamed into 'ticks' instead of 'millis' here?
