This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Minor floatobject.c bug
Type: Stage:
Components: Interpreter Core Versions: Python 2.2
process
Status: closed Resolution: out of date
Dependencies: Superseder:
Assigned To: Nosy List: nmm1, nnorwitz
Priority: normal Keywords:

Created on 2003-08-15 10:39 by nmm1, last changed 2022-04-10 16:10 by admin. This issue is now closed.

Messages (4)
msg17778 - (view) Author: Nick Maclaren (nmm1) Date: 2003-08-15 10:39
The following is a previously reported bug that got
only half fixed.
The bug was closed before I could respond that the fix
was incomplete;
here is a complete fix.

The failure is when overflow checking is enabled on
integers, as is
good programming practice and permitted by the C
standard.  It could
also cause wrong answers if overflow is mishandled (as
is also permitted
and can happen).

*** ./Objects/floatobject.c.org Tue Jan 28 19:40:35
2003
--- ./Objects/floatobject.c     Tue Jun  3 13:02:48
2003
***************
*** 659,667 ****
           to long may yield gibberish in either case. 
What really matters
           is whether converting back to double again
reproduces what we
           started with. */
!       aslong = (long)wholepart;
!       if ((double)aslong == wholepart)
!               return PyInt_FromLong(aslong);
        PyErr_SetString(PyExc_OverflowError, "float too
large to convert");
        return NULL;
  }
--- 659,669 ----
           to long may yield gibberish in either case. 
What really matters
           is whether converting back to double again
reproduces what we
           started with. */
!         if (wholepart > LONG_MIN-1.0 && wholepart <
LONG_MAX+1.0) {
!               aslong = (long)wholepart;
!               if ((double)aslong == wholepart)
!                       return PyInt_FromLong(aslong);
!         }
        PyErr_SetString(PyExc_OverflowError, "float too
large to convert");
        return NULL;
  }

        
Regards,
Nick Maclaren,
University of Cambridge Computing Service,
New Museums Site, Pembroke Street, Cambridge CB2 3QH,
England.
Email:  nmm1@cam.ac.uk
Tel.:  +44 1223 334761    Fax:  +44 1223 334679

msg17779 - (view) Author: Neal Norwitz (nnorwitz) * (Python committer) Date: 2003-08-15 12:44
Logged In: YES 
user_id=33168

Nick, if we do close a bug, you can still make comments and
we'll see it.  Thanks.
msg17780 - (view) Author: Nick Maclaren (nmm1) Date: 2003-08-15 15:08
Logged In: YES 
user_id=652073

Thanks for the remark about closing.  I tried to append,
but Sourceforge wouldn't let me.  It is all a while ago
now, though.


Heck.  I remember the discussion.  That has problems when
rounding gets in the way.  The following is an improved
fix and SHOULD work on all machines, past, present and
future that support standard C and used a power of two
base floating-point (or base 10, actually):

*** floatobject.c.org   Tue Jan 28 19:40:35 2003
--- floatobject.c       Fri Aug 15 15:22:48 2003
***************
*** 645,667 ****
  {
        double x = PyFloat_AsDouble(v);
        double wholepart;       /* integral portion of x,
rounded toward 0 */
!       long aslong;            /* (long)wholepart */
  
        (void)modf(x, &wholepart);
- #ifdef RISCOS
-       /* conversion from floating to integral type would
raise exception */
-       if (wholepart>LONG_MAX || wholepart<LONG_MIN) {
-               PyErr_SetString(PyExc_OverflowError, "float
too large to convert");
-               return NULL;
-       }
- #endif
        /* doubles may have more bits than longs, or vice
versa; and casting
           to long may yield gibberish in either case.  What
really matters
           is whether converting back to double again
reproduces what we
!          started with. */
!       aslong = (long)wholepart;
!       if ((double)aslong == wholepart)
!               return PyInt_FromLong(aslong);
        PyErr_SetString(PyExc_OverflowError, "float too
large to convert");
        return NULL;
  }
--- 645,675 ----
  {
        double x = PyFloat_AsDouble(v);
        double wholepart;       /* integral portion of x,
rounded toward 0 */
!       long aslong, z;         /* (long)wholepart */
!       int i, j, k;
  
        (void)modf(x, &wholepart);
        /* doubles may have more bits than longs, or vice
versa; and casting
           to long may yield gibberish in either case.  What
really matters
           is whether converting back to double again
reproduces what we
!          started with.  And remember that exceptions can
always occur. */
!       if (wholepart > LONG_MIN/2 && wholepart <
LONG_MAX/2)
!               x = 0.0;
!       else {
!               k = (x >= 0.0);
!               x = wholepart;
!               for (i = (sizeof(long)*CHAR_BIT-1)/16; i >=
0; --i) {
!                       z = LONG_MAX;
!                       for (j = 0; j < i; ++j) z >>= 16;
!                       x -= (k ? 1.0 :
-1.0)*ldexp(z&0xffff,16*i);
!               }
!               if (! k) x = (LONG_MAX+LONG_MIN)-x;
!       }
!         if (x <= 0.0) {
!               aslong = (long)wholepart;
!               if ((double)aslong == wholepart)
!                       return PyInt_FromLong(aslong);
!         }
        PyErr_SetString(PyExc_OverflowError, "float too
large to convert");
        return NULL;
  }

I have tested it, but don't know the internals well enough
to test it exhaustively.

msg17781 - (view) Author: Neal Norwitz (nnorwitz) * (Python committer) Date: 2006-10-07 22:54
Logged In: YES 
user_id=33168

The code is out of date.  It looks like the problem has been
addressed.  Please provide an updated patch in a new report
if this is not the case.
History
Date User Action Args
2022-04-10 16:10:39adminsetgithub: 39068
2003-08-15 10:39:13nmm1create