static double
frac_to_double (Lisp_Object numerator, Lisp_Object denominator)
{
- intmax_t intmax_numerator;
- if (FASTER_TIMEFNS && EQ (denominator, make_fixnum (1))
- && integer_to_intmax (numerator, &intmax_numerator))
- return intmax_numerator;
+ intmax_t intmax_numerator, intmax_denominator;
+ if (FASTER_TIMEFNS
+ && integer_to_intmax (numerator, &intmax_numerator)
+ && integer_to_intmax (denominator, &intmax_denominator)
+ && ! INT_DIVIDE_OVERFLOW (intmax_numerator, intmax_denominator)
+ && intmax_numerator % intmax_denominator == 0)
+ return intmax_numerator / intmax_denominator;
+ /* Compute number of base-FLT_RADIX digits in numerator and denominator. */
mpz_t const *n = bignum_integer (&mpz[0], numerator);
mpz_t const *d = bignum_integer (&mpz[1], denominator);
- ptrdiff_t nbits = mpz_sizeinbase (*n, 2);
- ptrdiff_t dbits = mpz_sizeinbase (*d, 2);
- eassume (0 < nbits);
- eassume (0 < dbits);
- ptrdiff_t ndig = (nbits + LOG2_FLT_RADIX - 1) / LOG2_FLT_RADIX;
- ptrdiff_t ddig = (dbits + LOG2_FLT_RADIX - 1) / LOG2_FLT_RADIX;
+ ptrdiff_t ndig = mpz_sizeinbase (*n, FLT_RADIX);
+ ptrdiff_t ddig = mpz_sizeinbase (*d, FLT_RADIX);
+
+ if (FASTER_TIMEFNS && ndig <= DBL_MANT_DIG && ddig <= DBL_MANT_DIG)
+ return mpz_get_d (*n) / mpz_get_d (*d);
/* Scale with SCALE when doing integer division. That is, compute
(N * FLT_RADIX**SCALE) / D [or, if SCALE is negative, N / (D *
FLT_RADIX**-SCALE)] as a bignum, convert the bignum to double,
- then divide the double by FLT_RADIX**SCALE. */
+ then divide the double by FLT_RADIX**SCALE. First scale N
+ (or scale D, if SCALE is negative) ... */
- ptrdiff_t scale = ddig - ndig + DBL_MANT_DIG + 1;
+ ptrdiff_t scale = ddig - ndig + DBL_MANT_DIG;
if (scale < 0)
{
mpz_mul_2exp (mpz[1], *d, - (scale * LOG2_FLT_RADIX));