diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2019-08-15 10:40:11 -0700 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2019-08-15 10:41:40 -0700 |
commit | af82a6248ce77f1b14f89cfee677250ff024c2c4 (patch) | |
tree | f93ac7f0f37c16ad1cbf1292d3427d7357ac3e52 /test/src | |
parent | f6ae51c71d69b4d1a02fc8f6536f3f8cc0dc1009 (diff) | |
download | emacs-af82a6248ce77f1b14f89cfee677250ff024c2c4.tar.gz |
Fix rounding errors with float timestamps
When converting from float to (TICKS . HZ) form, do the
conversion exactly. When converting from (TICKS . HZ) form to
float, round to even precisely. This way, successfully
converting a float to (TICKS . HZ) and back yields a value
numerically equal to the original.
* src/timefns.c (flt_radix_power_size): New constant.
(flt_radix_power): New static var.
(decode_float_time): Convert the exact numeric value rather
than guessing TIMESPEC_HZ resolution.
(s_ns_to_double): Remove; no longer needed.
(frac_to_double): New function.
(decode_ticks_hz): It is now the caller’s responsibility to
pass a valid TICKS and HZ. All callers changed.
Use frac_to_double to round (TICKS . HZ) precisely.
(decode_time_components): When decoding nil, use
decode_ticks_hz since it rounds precisely.
(syms_of_timefns): Initialize flt_radix_power.
* test/src/timefns-tests.el (float-time-precision): New test.
Diffstat (limited to 'test/src')
-rw-r--r-- | test/src/timefns-tests.el | 18 |
1 files changed, 18 insertions, 0 deletions
diff --git a/test/src/timefns-tests.el b/test/src/timefns-tests.el index feb8fc7905e..1b1032deaa1 100644 --- a/test/src/timefns-tests.el +++ b/test/src/timefns-tests.el @@ -150,3 +150,21 @@ (should (time-equal-p (encode-time '(29 31 17 30 4 2019 2 t 7200 0)) '(23752 27217)))) + +(ert-deftest float-time-precision () + (should (< 0 (float-time '(1 . 10000000000)))) + (should (< (float-time '(-1 . 10000000000)) 0)) + + (let ((x 1.0)) + (while (not (zerop x)) + (dolist (multiplier '(-1.9 -1.5 -1.1 -1 1 1.1 1.5 1.9)) + (let ((xmult (* x multiplier))) + (should (= xmult (float-time (time-convert xmult t)))))) + (setq x (/ x 2)))) + + (let ((x 1.0)) + (while (ignore-errors (time-convert x t)) + (dolist (divisor '(-1.9 -1.5 -1.1 -1 1 1.1 1.5 1.9)) + (let ((xdiv (/ x divisor))) + (should (= xdiv (float-time (time-convert xdiv t)))))) + (setq x (* x 2))))) |