summaryrefslogtreecommitdiff
path: root/test/src
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2019-08-15 10:40:11 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2019-08-15 10:41:40 -0700
commitaf82a6248ce77f1b14f89cfee677250ff024c2c4 (patch)
treef93ac7f0f37c16ad1cbf1292d3427d7357ac3e52 /test/src
parentf6ae51c71d69b4d1a02fc8f6536f3f8cc0dc1009 (diff)
downloademacs-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.el18
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)))))