[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
master ff10e95 1/3: Refactor double integer scaling
From: |
Paul Eggert |
Subject: |
master ff10e95 1/3: Refactor double integer scaling |
Date: |
Wed, 13 Nov 2019 16:10:15 -0500 (EST) |
branch: master
commit ff10e9517d98aa606e007d3aa4d5aef1c423ab77
Author: Paul Eggert <address@hidden>
Commit: Paul Eggert <address@hidden>
Refactor double integer scaling
This doesn’t alter behavior, and simplifies a future commit.
* src/floatfns.c (double_integer_scale): New function,
with body adapted from the old timefns.c.
* src/timefns.c (decode_float_time): Use it.
---
src/floatfns.c | 23 +++++++++++++++++++++++
src/lisp.h | 1 +
src/timefns.c | 27 +++++----------------------
3 files changed, 29 insertions(+), 22 deletions(-)
diff --git a/src/floatfns.c b/src/floatfns.c
index 3199d57..7e77dbd 100644
--- a/src/floatfns.c
+++ b/src/floatfns.c
@@ -348,6 +348,29 @@ integer_value (Lisp_Object a)
return true;
}
+/* Return the integer exponent E such that D * FLT_RADIX**E (i.e.,
+ scalbn (D, E)) is an integer that has precision equal to D and is
+ representable as a double.
+
+ Return DBL_MANT_DIG - DBL_MIN_EXP (the maximum possible valid
+ scale) if D is zero or tiny. Return a value greater than
+ DBL_MANT_DIG - DBL_MIN_EXP if there is conversion trouble; on all
+ current platforms this can happen only if D is infinite or a NaN. */
+
+int
+double_integer_scale (double d)
+{
+ int exponent = ilogb (d);
+ return (DBL_MIN_EXP - 1 <= exponent && exponent < INT_MAX
+ ? DBL_MANT_DIG - 1 - exponent
+ : (DBL_MANT_DIG - DBL_MIN_EXP
+ + (exponent == INT_MAX
+ || (exponent == FP_ILOGBNAN
+ && (FP_ILOGBNAN != FP_ILOGB0 || isnan (d)))
+ || (!IEEE_FLOATING_POINT && exponent == INT_MIN
+ && (FP_ILOGB0 != INT_MIN || d != 0)))));
+}
+
/* the rounding functions */
static Lisp_Object
diff --git a/src/lisp.h b/src/lisp.h
index 04fa1d6..38e1891 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -3684,6 +3684,7 @@ extern Lisp_Object string_make_unibyte (Lisp_Object);
extern void syms_of_fns (void);
/* Defined in floatfns.c. */
+int double_integer_scale (double);
#ifndef HAVE_TRUNC
extern double trunc (double);
#endif
diff --git a/src/timefns.c b/src/timefns.c
index fe08efd..cf634a8 100644
--- a/src/timefns.c
+++ b/src/timefns.c
@@ -406,26 +406,9 @@ decode_float_time (double t, struct lisp_time *result)
}
else
{
- int exponent = ilogb (t);
- 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)
+ int scale = double_integer_scale (t);
+
+ if (scale < 0)
{
/* T is finite but so large that HZ would be less than 1 if
T's precision were represented exactly. SCALE must be
@@ -435,8 +418,8 @@ decode_float_time (double t, struct lisp_time *result)
which is typically better than signaling overflow. */
scale = 0;
}
- else
- return FP_ILOGBNAN == INT_MAX && isnan (t) ? EINVAL : EOVERFLOW;
+ else if (flt_radix_power_size <= scale)
+ return isnan (t) ? EDOM : EOVERFLOW;
double scaled = scalbn (t, scale);
eassert (trunc (scaled) == scaled);