diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2019-08-20 14:02:30 -0700 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2019-08-20 15:45:59 -0700 |
commit | 5a9552128296478ec74594b45d0728d87450197e (patch) | |
tree | f83d7409a2d62813ed4bb1d8b10215efefca29a3 /src/timefns.c | |
parent | a13c64204c8ead966789abf8efe176e4f2d4f599 (diff) | |
download | emacs-5a9552128296478ec74594b45d0728d87450197e.tar.gz emacs-5a9552128296478ec74594b45d0728d87450197e.tar.bz2 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.
Diffstat (limited to 'src/timefns.c')
-rw-r--r-- | src/timefns.c | 40 |
1 files changed, 30 insertions, 10 deletions
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) else { int exponent = ilogb (t); - if (exponent == FP_ILOGBNAN) - return EINVAL; - - /* An enormous or infinite T would make SCALE < 0 which would make - HZ < 1, which the (TICKS . HZ) representation does not allow. */ - if (DBL_MANT_DIG - 1 < exponent) - return EOVERFLOW; - - /* min so we don't scale tiny numbers as if they were normalized. */ - int scale = min (DBL_MANT_DIG - 1 - exponent, flt_radix_power_size - 1); + int scale; + if (exponent < DBL_MANT_DIG) + { + if (exponent < DBL_MIN_EXP - 1) + { + if (exponent == FP_ILOGBNAN + && (FP_ILOGBNAN != FP_ILOGB0 || isnan (t))) + return EINVAL; + /* T is tiny. SCALE must be less than FLT_RADIX_POWER_SIZE, + as otherwise T would be scaled as if it were normalized. */ + scale = flt_radix_power_size - 1; + } + else + { + /* The typical case. */ + scale = DBL_MANT_DIG - 1 - exponent; + } + } + else if (exponent < INT_MAX) + { + /* T is finite but so large that HZ would be less than 1 if + T's precision were represented exactly. SCALE must be + nonnegative, as the (TICKS . HZ) representation requires + HZ to be at least 1. So use SCALE = 0, which converts T to + (T . 1), which is the exact numeric value with too-large HZ, + which is typically better than signaling overflow. */ + scale = 0; + } + else + return FP_ILOGBNAN == INT_MAX && isnan (t) ? EINVAL : EOVERFLOW; double scaled = scalbn (t, scale); eassert (trunc (scaled) == scaled); |