diff options
| author | Paul Eggert | 2019-08-15 10:40:11 -0700 |
|---|---|---|
| committer | Paul Eggert | 2019-08-15 10:41:40 -0700 |
| commit | af82a6248ce77f1b14f89cfee677250ff024c2c4 (patch) | |
| tree | f93ac7f0f37c16ad1cbf1292d3427d7357ac3e52 /test/src/timefns-tests.el | |
| parent | f6ae51c71d69b4d1a02fc8f6536f3f8cc0dc1009 (diff) | |
| download | emacs-af82a6248ce77f1b14f89cfee677250ff024c2c4.tar.gz emacs-af82a6248ce77f1b14f89cfee677250ff024c2c4.zip | |
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/timefns-tests.el')
| -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 @@ | |||
| 150 | (should (time-equal-p | 150 | (should (time-equal-p |
| 151 | (encode-time '(29 31 17 30 4 2019 2 t 7200 0)) | 151 | (encode-time '(29 31 17 30 4 2019 2 t 7200 0)) |
| 152 | '(23752 27217)))) | 152 | '(23752 27217)))) |
| 153 | |||
| 154 | (ert-deftest float-time-precision () | ||
| 155 | (should (< 0 (float-time '(1 . 10000000000)))) | ||
| 156 | (should (< (float-time '(-1 . 10000000000)) 0)) | ||
| 157 | |||
| 158 | (let ((x 1.0)) | ||
| 159 | (while (not (zerop x)) | ||
| 160 | (dolist (multiplier '(-1.9 -1.5 -1.1 -1 1 1.1 1.5 1.9)) | ||
| 161 | (let ((xmult (* x multiplier))) | ||
| 162 | (should (= xmult (float-time (time-convert xmult t)))))) | ||
| 163 | (setq x (/ x 2)))) | ||
| 164 | |||
| 165 | (let ((x 1.0)) | ||
| 166 | (while (ignore-errors (time-convert x t)) | ||
| 167 | (dolist (divisor '(-1.9 -1.5 -1.1 -1 1 1.1 1.5 1.9)) | ||
| 168 | (let ((xdiv (/ x divisor))) | ||
| 169 | (should (= xdiv (float-time (time-convert xdiv t)))))) | ||
| 170 | (setq x (* x 2))))) | ||