Introduce new private API function _PyLong_AsScaledDouble. Not used yet,
authorTim Peters <tim.peters@gmail.com>
Tue, 4 Sep 2001 02:50:49 +0000 (02:50 +0000)
committerTim Peters <tim.peters@gmail.com>
Tue, 4 Sep 2001 02:50:49 +0000 (02:50 +0000)
but will be the foundation for Good Things:
+ Speed PyLong_AsDouble.
+ Give PyLong_AsDouble the ability to detect overflow.
+ Make true division of long/long nearly as accurate as possible (no
  spurious infinities or NaNs).
+ Return non-insane results from math.log and math.log10 when passing a
  long that can't be approximated by a double better than HUGE_VAL.

Include/longobject.h
Objects/longobject.c

index 5d1ea0a51742c8660d951239a75b1c5dd538d729..e592891687a6ff649f9fdc3d50781b2444583de6 100644 (file)
@@ -18,6 +18,15 @@ extern DL_IMPORT(PyObject *) PyLong_FromUnsignedLong(unsigned long);
 extern DL_IMPORT(PyObject *) PyLong_FromDouble(double);
 extern DL_IMPORT(long) PyLong_AsLong(PyObject *);
 extern DL_IMPORT(unsigned long) PyLong_AsUnsignedLong(PyObject *);
+
+/* _PyLong_AsScaledDouble returns a double x and an exponent e such that
+   the true value is approximately equal to x * 2**(SHIFT*e).  e is >= 0.
+   x is 0.0 if and only if the input is 0 (in which case, e and x are both
+   zeroes).  Overflow is impossible.  Note that the exponent returned must
+   be multiplied by SHIFT!  There may not be enough room in an int to store
+   e*SHIFT directly. */
+extern DL_IMPORT(double) _PyLong_AsScaledDouble(PyObject *vv, int *e);
+
 extern DL_IMPORT(double) PyLong_AsDouble(PyObject *);
 extern DL_IMPORT(PyObject *) PyLong_FromVoidPtr(void *);
 extern DL_IMPORT(void *) PyLong_AsVoidPtr(PyObject *);
index 4d4a9599bcfe0b136055bb3f34cf9b9794463e58..b511928dbd4ba570a1e80fef3ecadf0d88ec7245 100644 (file)
@@ -474,6 +474,58 @@ Overflow:
        
 }
 
+double
+_PyLong_AsScaledDouble(PyObject *vv, int *exponent)
+{
+/* NBITS_WANTED should be > the number of bits in a double's precision,
+   but small enough so that 2**NBITS_WANTED is within the normal double
+   range.  nbitsneeded is set to 1 less than that because the most-significant
+   Python digit contains at least 1 significant bit, but we don't want to
+   bother counting them (catering to the worst case cheaply).
+
+   57 is one more than VAX-D double precision; I (Tim) don't know of a double
+   format with more precision than that; it's 1 larger so that we add in at
+   least one round bit to stand in for the ignored least-significant bits.
+*/
+#define NBITS_WANTED 57
+       PyLongObject *v;
+       double x;
+       const double multiplier = (double)(1L << SHIFT);
+       int i, sign;
+       int nbitsneeded;
+
+       if (vv == NULL || !PyLong_Check(vv)) {
+               PyErr_BadInternalCall();
+               return -1;
+       }
+       v = (PyLongObject *)vv;
+       i = v->ob_size;
+       sign = 1;
+       if (i < 0) {
+               sign = -1;
+               i = -(i);
+       }
+       else if (i == 0) {
+               *exponent = 0;
+               return 0.0;
+       }
+       --i;
+       x = (double)v->ob_digit[i];
+       nbitsneeded = NBITS_WANTED - 1;
+       /* Invariant:  i Python digits remain unaccounted for. */
+       while (i > 0 && nbitsneeded > 0) {
+               --i;
+               x = x * multiplier + (double)v->ob_digit[i];
+               nbitsneeded -= SHIFT;
+       }
+       /* There are i digits we didn't shift in.  Pretending they're all
+          zeroes, the true value is x * 2**(i*SHIFT). */
+       *exponent = i;
+       assert(x > 0.0);
+       return x * sign;
+#undef NBITS_WANTED
+}
+
 /* Get a C double from a long int object. */
 
 double