mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 23:21:29 +00:00 
			
		
		
		
	New restriction on pow(x, y, z): If z is not None, x and y must be of
integer types, and y must be >= 0. See discussion at http://sf.net/tracker/index.php?func=detail&aid=457066&group_id=5470&atid=105470
This commit is contained in:
		
							parent
							
								
									5d2b77cf31
								
							
						
					
					
						commit
						32f453eaa4
					
				
					 9 changed files with 79 additions and 49 deletions
				
			
		| 
						 | 
				
			
			@ -519,8 +519,14 @@ the interpreter.
 | 
			
		|||
  case, all arguments are converted to float and a float result is
 | 
			
		||||
  delivered.  For example, \code{10**2} returns \code{100}, but
 | 
			
		||||
  \code{10**-2} returns \code{0.01}.  (This last feature was added in
 | 
			
		||||
  Python 2.2.  In Python 2.1 and before, a negative second argument
 | 
			
		||||
  would raise an exception.)
 | 
			
		||||
  Python 2.2.  In Python 2.1 and before, if both arguments were of integer
 | 
			
		||||
  types and the second argument was negative, an exception was raised.)
 | 
			
		||||
  If the second argument is negative, the third argument must be omitted. 
 | 
			
		||||
  If \var{z} is present, \var{x} and \var{y} must be of integer types,
 | 
			
		||||
  and \var{y} must be non-negative.  (This restriction was added in
 | 
			
		||||
  Python 2.2.  In Python 2.1 and before, floating 3-argument \code{pow()}
 | 
			
		||||
  returned platform-dependent results depending on floating-point
 | 
			
		||||
  rounding accidents.)
 | 
			
		||||
\end{funcdesc}
 | 
			
		||||
 | 
			
		||||
\begin{funcdesc}{range}{\optional{start,} stop\optional{, step}}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,8 +22,4 @@ The number in both columns should match.
 | 
			
		|||
-3L -3L
 | 
			
		||||
-7L -7L
 | 
			
		||||
 | 
			
		||||
3.0 3.0
 | 
			
		||||
-5.0 -5.0
 | 
			
		||||
-1.0 -1.0
 | 
			
		||||
-7.0 -7.0
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -82,15 +82,26 @@
 | 
			
		|||
if fcmp(pow(2.,20), 1024.*1024.): raise TestFailed, 'pow(2.,20)'
 | 
			
		||||
if fcmp(pow(2.,30), 1024.*1024.*1024.): raise TestFailed, 'pow(2.,30)'
 | 
			
		||||
#
 | 
			
		||||
# XXX These don't work -- negative float to the float power...
 | 
			
		||||
#if fcmp(pow(-2.,0), 1.): raise TestFailed, 'pow(-2.,0)'
 | 
			
		||||
#if fcmp(pow(-2.,1), -2.): raise TestFailed, 'pow(-2.,1)'
 | 
			
		||||
#if fcmp(pow(-2.,2), 4.): raise TestFailed, 'pow(-2.,2)'
 | 
			
		||||
#if fcmp(pow(-2.,3), -8.): raise TestFailed, 'pow(-2.,3)'
 | 
			
		||||
#
 | 
			
		||||
if fcmp(pow(-2.,0), 1.): raise TestFailed, 'pow(-2.,0)'
 | 
			
		||||
if fcmp(pow(-2.,1), -2.): raise TestFailed, 'pow(-2.,1)'
 | 
			
		||||
if fcmp(pow(-2.,2), 4.): raise TestFailed, 'pow(-2.,2)'
 | 
			
		||||
if fcmp(pow(-2.,3), -8.): raise TestFailed, 'pow(-2.,3)'
 | 
			
		||||
 | 
			
		||||
from types import FloatType
 | 
			
		||||
for x in 2, 2L, 2.0:
 | 
			
		||||
    for y in 10, 10L, 10.0:
 | 
			
		||||
        for z in 1000, 1000L, 1000.0:
 | 
			
		||||
            if isinstance(x, FloatType) or \
 | 
			
		||||
               isinstance(y, FloatType) or \
 | 
			
		||||
               isinstance(z, FloatType):
 | 
			
		||||
                try:
 | 
			
		||||
                    pow(x, y, z)
 | 
			
		||||
                except TypeError:
 | 
			
		||||
                    pass
 | 
			
		||||
                else:
 | 
			
		||||
                    raise TestFailed("3-arg float pow() should have "
 | 
			
		||||
                                     "raised TypeError %r" % (x, y, z))
 | 
			
		||||
            else:
 | 
			
		||||
                if fcmp(pow(x, y, z), 24.0):
 | 
			
		||||
                    raise TestFailed, 'pow(%s, %s, %s)' % (x, y, z)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -315,9 +315,18 @@ def checkit(*args):
 | 
			
		|||
 | 
			
		||||
                for z in special:
 | 
			
		||||
                    if z != 0 :
 | 
			
		||||
                        if y >= 0:
 | 
			
		||||
                            expected = pow(longx, longy, long(z))
 | 
			
		||||
                            got = pow(x, y, z)
 | 
			
		||||
                            checkit('pow', x, y, '%', z)
 | 
			
		||||
                        else:
 | 
			
		||||
                            try:
 | 
			
		||||
                                pow(longx, longy, long(z))
 | 
			
		||||
                            except TypeError:
 | 
			
		||||
                                pass
 | 
			
		||||
                            else:
 | 
			
		||||
                                raise TestFailed("pow%r should have raised "
 | 
			
		||||
                                "TypeError" % ((longx, longy, long(z))))
 | 
			
		||||
 | 
			
		||||
# ---------------------------------------------------------------- do it
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -64,6 +64,15 @@ def powtest(type):
 | 
			
		|||
        for j in range(jl, jh+1):
 | 
			
		||||
            for k in range(kl, kh+1):
 | 
			
		||||
                if k != 0:
 | 
			
		||||
                    if type == float or j < 0:
 | 
			
		||||
                        try:
 | 
			
		||||
                            pow(type(i),j,k)
 | 
			
		||||
                        except TypeError:
 | 
			
		||||
                            pass
 | 
			
		||||
                        else:
 | 
			
		||||
                            raise TestFailed("expected TypeError from "
 | 
			
		||||
                                "pow%r" % ((type(i), j, k)))
 | 
			
		||||
                        continue
 | 
			
		||||
                    if compare(pow(type(i),j,k), pow(type(i),j)% type(k)):
 | 
			
		||||
                        raise ValueError, "pow(" +str(i)+ "," +str(j)+ \
 | 
			
		||||
                             "," +str(k)+ ") != pow(" +str(i)+ "," + \
 | 
			
		||||
| 
						 | 
				
			
			@ -96,10 +105,6 @@ def powtest(type):
 | 
			
		|||
print `pow(5L,2) % -8`, `pow(5L,2,-8)`
 | 
			
		||||
print
 | 
			
		||||
 | 
			
		||||
print pow(3.0,3.0) % 8, pow(3.0,3.0,8)
 | 
			
		||||
print pow(3.0,3.0) % -8, pow(3.0,3.0,-8)
 | 
			
		||||
print pow(3.0,2) % -2, pow(3.0,2,-2)
 | 
			
		||||
print pow(5.0,2) % -8, pow(5.0,2,-8)
 | 
			
		||||
print
 | 
			
		||||
 | 
			
		||||
for i in range(-10, 11):
 | 
			
		||||
| 
						 | 
				
			
			@ -112,8 +117,3 @@ def powtest(type):
 | 
			
		|||
            if j >= 0 and k != 0:
 | 
			
		||||
                o = pow(long(i),j) % k
 | 
			
		||||
                n = pow(long(i),j,k)
 | 
			
		||||
                if o != n: print 'Long mismatch:', i,j,k
 | 
			
		||||
            if i >= 0 and k != 0:
 | 
			
		||||
                o = pow(float(i),j) % k
 | 
			
		||||
                n = pow(float(i),j,k)
 | 
			
		||||
                if o != n: print 'Float mismatch:', i,j,k
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,12 @@ What's New in Python 2.2a3?
 | 
			
		|||
 | 
			
		||||
Core
 | 
			
		||||
 | 
			
		||||
- The 3-argument builtin pow() no longer allows a third non-None argument
 | 
			
		||||
  if either of the first two arguments is a float, or if both are of
 | 
			
		||||
  integer types and the second argument is negative (in which latter case
 | 
			
		||||
  the arguments are converted to float, so this is really the same
 | 
			
		||||
  restriction).
 | 
			
		||||
 | 
			
		||||
- The builtin dir() now returns more information, and sometimes much
 | 
			
		||||
  more, generally naming all attributes of an object, and all attributes
 | 
			
		||||
  reachable from the object via its class, and from its class's base
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -492,11 +492,13 @@ static PyObject *
 | 
			
		|||
float_pow(PyObject *v, PyObject *w, PyObject *z)
 | 
			
		||||
{
 | 
			
		||||
	double iv, iw, ix;
 | 
			
		||||
 /* XXX Doesn't handle overflows if z!=None yet; it may never do so :(
 | 
			
		||||
  * The z parameter is really only going to be useful for integers and
 | 
			
		||||
  * long integers.  Maybe something clever with logarithms could be done.
 | 
			
		||||
  * [AMK]
 | 
			
		||||
  */
 | 
			
		||||
 | 
			
		||||
	if ((PyObject *)z != Py_None) {
 | 
			
		||||
		PyErr_SetString(PyExc_TypeError,
 | 
			
		||||
			"3rd argument to floating pow() must be None");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	CONVERT_TO_DOUBLE(v, iv);
 | 
			
		||||
	CONVERT_TO_DOUBLE(w, iw);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -538,16 +540,6 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
 | 
			
		|||
		PyErr_SetFromErrno(PyExc_OverflowError);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	if ((PyObject *)z != Py_None) {
 | 
			
		||||
		double iz;
 | 
			
		||||
		CONVERT_TO_DOUBLE(z, iz);
 | 
			
		||||
		PyFPE_START_PROTECT("pow", return 0)
 | 
			
		||||
	 	ix = fmod(ix, iz);	/* XXX To Be Rewritten */
 | 
			
		||||
	 	if (ix != 0 && ((iv < 0 && iz > 0) || (iv > 0 && iz < 0) )) {
 | 
			
		||||
		     ix += iz;
 | 
			
		||||
		}
 | 
			
		||||
  		PyFPE_END_PROTECT(ix)
 | 
			
		||||
	}
 | 
			
		||||
	return PyFloat_FromDouble(ix);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -575,6 +575,11 @@ int_pow(PyIntObject *v, PyIntObject *w, PyIntObject *z)
 | 
			
		|||
	CONVERT_TO_LONG(v, iv);
 | 
			
		||||
	CONVERT_TO_LONG(w, iw);
 | 
			
		||||
	if (iw < 0) {
 | 
			
		||||
		if ((PyObject *)z != Py_None) {
 | 
			
		||||
			PyErr_SetString(PyExc_TypeError, "integer pow() arg "
 | 
			
		||||
			     "3 must not be specified when arg 2 is < 0");
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
		/* Return a float.  This works because we know that
 | 
			
		||||
		   this calls float_pow() which converts its
 | 
			
		||||
		   arguments to double. */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1598,12 +1598,17 @@ long_pow(PyObject *v, PyObject *w, PyObject *x)
 | 
			
		|||
	
 | 
			
		||||
	size_b = b->ob_size;
 | 
			
		||||
	if (size_b < 0) {
 | 
			
		||||
		/* Return a float.  This works because we know that
 | 
			
		||||
		   this calls float_pow() which converts its
 | 
			
		||||
		   arguments to double. */
 | 
			
		||||
		Py_DECREF(a);
 | 
			
		||||
		Py_DECREF(b);
 | 
			
		||||
		Py_DECREF(c);
 | 
			
		||||
		if (x != Py_None) {
 | 
			
		||||
			PyErr_SetString(PyExc_TypeError, "integer pow() arg "
 | 
			
		||||
			     "3 must not be specified when arg 2 is < 0");
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
		/* Return a float.  This works because we know that
 | 
			
		||||
		   this calls float_pow() which converts its
 | 
			
		||||
		   arguments to double. */
 | 
			
		||||
		return PyFloat_Type.tp_as_number->nb_power(v, w, x);
 | 
			
		||||
	}
 | 
			
		||||
	z = (PyLongObject *)PyLong_FromLong(1L);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue