Commit 32f453ea authored by Tim Peters's avatar Tim Peters

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
parent 5d2b77cf
......@@ -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.,10), 1024.): raise TestFailed, 'pow(2.,10)'
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)
......
......@@ -314,10 +314,19 @@ def test_auto_overflow():
checkit(x, '**', y)
for z in special:
if z != 0:
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 @@ print `pow(-3L,3L) % -8`, `pow(-3L,3L,-8)`
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 @@ for i in range(-10, 11):
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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment