aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert2019-08-20 14:02:30 -0700
committerPaul Eggert2019-08-20 15:45:59 -0700
commit5a9552128296478ec74594b45d0728d87450197e (patch)
treef83d7409a2d62813ed4bb1d8b10215efefca29a3
parenta13c64204c8ead966789abf8efe176e4f2d4f599 (diff)
downloademacs-5a9552128296478ec74594b45d0728d87450197e.tar.gz
emacs-5a9552128296478ec74594b45d0728d87450197e.zip
Support larger TIMEs in (time-convert TIME t)
Also, improve the doc to match current behavior. * doc/lispref/os.texi (Time Conversion): Document that time-convert signals an error for infinite or NaN args, and that (time-convert TIME t) is exact otherwise. Mention float-time as an alternative to time-convert. (Time Calculations): Document that time-add and time-subtract are exact and do not decrease HZ below the minimum of their args. * src/timefns.c (decode_float_time): Don’t signal an error for floating-point arguments whose base-FLT_RADIX exponent is not less than DBL_MANT_DIG. Instead, convert them to (TICKS . 1) values. Use two (instead of three) integer exponent comparisons in the typical case. * test/src/timefns-tests.el (time-arith-tests): Add more floating-point tests, including some tests that the old code fails.
-rw-r--r--doc/lispref/os.texi31
-rw-r--r--src/timefns.c40
-rw-r--r--test/src/timefns-tests.el6
3 files changed, 57 insertions, 20 deletions
diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi
index 49c07380c5f..dd80b04ad83 100644
--- a/doc/lispref/os.texi
+++ b/doc/lispref/os.texi
@@ -1346,6 +1346,8 @@ given, specifies a time to convert instead of the current time.
1346 1346
1347@emph{Warning}: Since the result is floating point, it may not be 1347@emph{Warning}: Since the result is floating point, it may not be
1348exact. Do not use this function if precise time stamps are required. 1348exact. Do not use this function if precise time stamps are required.
1349For example, on typical systems @code{(float-time '(1 . 10))} displays
1350as @samp{0.1} but is slightly greater than 1/10.
1349 1351
1350@code{time-to-seconds} is an alias for this function. 1352@code{time-to-seconds} is an alias for this function.
1351@end defun 1353@end defun
@@ -1432,8 +1434,6 @@ as traditional Gregorian years do; for example, the year number
1432 1434
1433@defun time-convert time &optional form 1435@defun time-convert time &optional form
1434This function converts a time value into a Lisp timestamp. 1436This function converts a time value into a Lisp timestamp.
1435If the time cannot be represented exactly, it is truncated
1436toward minus infinity.
1437 1437
1438The optional @var{form} argument specifies the timestamp form to be 1438The optional @var{form} argument specifies the timestamp form to be
1439returned. If @var{form} is the symbol @code{integer}, this function 1439returned. If @var{form} is the symbol @code{integer}, this function
@@ -1452,8 +1452,17 @@ Although an omitted or @code{nil} @var{form} currently acts like
1452@code{list}, this is planned to change in a future Emacs version, so 1452@code{list}, this is planned to change in a future Emacs version, so
1453callers requiring list timestamps should pass @code{list} explicitly. 1453callers requiring list timestamps should pass @code{list} explicitly.
1454 1454
1455If @var{time} already has the proper form, this function might yield 1455If @var{time} is infinite or a NaN, this function signals an error.
1456@var{time} rather than a copy. 1456Otherwise, if @var{time} cannot be represented exactly, conversion
1457truncates it toward minus infinity. When @var{form} is @code{t},
1458conversion is always exact so no truncation occurs, and the returned
1459clock resolution is no less than that of @var{time}. By way of
1460contrast, @code{float-time} can convert any Lisp time value without
1461signaling an error, although the result might not be exact.
1462@xref{Time of Day}.
1463
1464For efficiency this function might return a value that is @code{eq} to
1465@var{time}, or that otherwise shares structure with @var{time}.
1457 1466
1458Although @code{(time-convert nil nil)} is equivalent to 1467Although @code{(time-convert nil nil)} is equivalent to
1459@code{(current-time)}, the latter may be a bit faster. 1468@code{(current-time)}, the latter may be a bit faster.
@@ -1950,16 +1959,18 @@ The result is @code{nil} if either argument is a NaN.
1950 1959
1951@defun time-subtract t1 t2 1960@defun time-subtract t1 t2
1952This returns the time difference @var{t1} @minus{} @var{t2} between 1961This returns the time difference @var{t1} @minus{} @var{t2} between
1953two time values, as a time value. However, the result is a float 1962two time values, normally as a Lisp timestamp but as a float
1954if either argument is a float infinity or NaN@. 1963if either argument is infinite or a NaN@.
1964When the result is a timestamp, it is exact and its clock
1965resolution is no worse than the worse of its two arguments' resolutions.
1955If you need the difference in units 1966If you need the difference in units
1956of elapsed seconds, use @code{float-time} (@pxref{Time of Day, 1967of elapsed seconds, you can convert it with @code{time-convert} or
1957float-time}) to convert the result into seconds. 1968@code{float-time}. @xref{Time Conversion}.
1958@end defun 1969@end defun
1959 1970
1960@defun time-add t1 t2 1971@defun time-add t1 t2
1961This returns the sum of two time values, as a time value. 1972This returns the sum of two time values,
1962However, the result is a float if either argument is a float infinity or NaN@. 1973using the same conversion rules as @code{time-subtract}.
1963One argument should represent a time difference rather than a point in time, 1974One argument should represent a time difference rather than a point in time,
1964as a time value that is often just a single number of elapsed seconds. 1975as a time value that is often just a single number of elapsed seconds.
1965Here is how to add a number of seconds to a time value: 1976Here is how to add a number of seconds to a time value:
diff --git a/src/timefns.c b/src/timefns.c
index 2d545a4f905..3b686eb2265 100644
--- a/src/timefns.c
+++ b/src/timefns.c
@@ -391,16 +391,36 @@ decode_float_time (double t, struct lisp_time *result)
391 else 391 else
392 { 392 {
393 int exponent = ilogb (t); 393 int exponent = ilogb (t);
394 if (exponent == FP_ILOGBNAN) 394 int scale;
395 return EINVAL; 395 if (exponent < DBL_MANT_DIG)
396 396 {
397 /* An enormous or infinite T would make SCALE < 0 which would make 397 if (exponent < DBL_MIN_EXP - 1)
398 HZ < 1, which the (TICKS . HZ) representation does not allow. */ 398 {
399 if (DBL_MANT_DIG - 1 < exponent) 399 if (exponent == FP_ILOGBNAN
400 return EOVERFLOW; 400 && (FP_ILOGBNAN != FP_ILOGB0 || isnan (t)))
401 401 return EINVAL;
402 /* min so we don't scale tiny numbers as if they were normalized. */ 402 /* T is tiny. SCALE must be less than FLT_RADIX_POWER_SIZE,
403 int scale = min (DBL_MANT_DIG - 1 - exponent, flt_radix_power_size - 1); 403 as otherwise T would be scaled as if it were normalized. */
404 scale = flt_radix_power_size - 1;
405 }
406 else
407 {
408 /* The typical case. */
409 scale = DBL_MANT_DIG - 1 - exponent;
410 }
411 }
412 else if (exponent < INT_MAX)
413 {
414 /* T is finite but so large that HZ would be less than 1 if
415 T's precision were represented exactly. SCALE must be
416 nonnegative, as the (TICKS . HZ) representation requires
417 HZ to be at least 1. So use SCALE = 0, which converts T to
418 (T . 1), which is the exact numeric value with too-large HZ,
419 which is typically better than signaling overflow. */
420 scale = 0;
421 }
422 else
423 return FP_ILOGBNAN == INT_MAX && isnan (t) ? EINVAL : EOVERFLOW;
404 424
405 double scaled = scalbn (t, scale); 425 double scaled = scalbn (t, scale);
406 eassert (trunc (scaled) == scaled); 426 eassert (trunc (scaled) == scaled);
diff --git a/test/src/timefns-tests.el b/test/src/timefns-tests.el
index a30b2de3a5b..48d964d129c 100644
--- a/test/src/timefns-tests.el
+++ b/test/src/timefns-tests.el
@@ -129,6 +129,12 @@
129 most-negative-fixnum most-positive-fixnum 129 most-negative-fixnum most-positive-fixnum
130 (1- most-negative-fixnum) 130 (1- most-negative-fixnum)
131 (1+ most-positive-fixnum) 131 (1+ most-positive-fixnum)
132 1e1 -1e1 1e-1 -1e-1
133 1e8 -1e8 1e-8 -1e-8
134 1e9 -1e9 1e-9 -1e-9
135 1e10 -1e10 1e-10 -1e-10
136 1e16 -1e16 1e-16 -1e-16
137 1e37 -1e37 1e-37 -1e-37
132 1e+INF -1e+INF 1e+NaN -1e+NaN 138 1e+INF -1e+INF 1e+NaN -1e+NaN
133 '(0 0 0 1) '(0 0 1 0) '(0 1 0 0) '(1 0 0 0) 139 '(0 0 0 1) '(0 0 1 0) '(0 1 0 0) '(1 0 0 0)
134 '(-1 0 0 0) '(1 2 3 4) '(-1 2 3 4) 140 '(-1 0 0 0) '(1 2 3 4) '(-1 2 3 4)