Commit 2be06383 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #549 from tjhance/float_pow

Float pow
parents 1eb99619 b569aed6
...@@ -820,11 +820,14 @@ float_floor_div(PyObject *v, PyObject *w) ...@@ -820,11 +820,14 @@ float_floor_div(PyObject *v, PyObject *w)
x is not an infinity or nan. */ x is not an infinity or nan. */
#define DOUBLE_IS_ODD_INTEGER(x) (fmod(fabs(x), 2.0) == 1.0) #define DOUBLE_IS_ODD_INTEGER(x) (fmod(fabs(x), 2.0) == 1.0)
static PyObject * inline int float_pow_unboxed(double iv, double iw, double* res);
// pyston change: split this up into float_pow and and float_pow_unboxed
PyObject *
float_pow(PyObject *v, PyObject *w, PyObject *z) float_pow(PyObject *v, PyObject *w, PyObject *z)
{ {
double iv, iw, ix; double iv, iw, res;
int negate_result = 0; int err;
if ((PyObject *)z != Py_None) { if ((PyObject *)z != Py_None) {
PyErr_SetString(PyExc_TypeError, "pow() 3rd argument not " PyErr_SetString(PyExc_TypeError, "pow() 3rd argument not "
...@@ -835,15 +838,32 @@ float_pow(PyObject *v, PyObject *w, PyObject *z) ...@@ -835,15 +838,32 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
CONVERT_TO_DOUBLE(v, iv); CONVERT_TO_DOUBLE(v, iv);
CONVERT_TO_DOUBLE(w, iw); CONVERT_TO_DOUBLE(w, iw);
err = float_pow_unboxed(iv, iw, &res);
if (err) {
return NULL;
} else {
return PyFloat_FromDouble(res);
}
}
int
float_pow_unboxed(double iv, double iw, double* res)
{
double ix;
int negate_result = 0;
/* Sort out special cases here instead of relying on pow() */ /* Sort out special cases here instead of relying on pow() */
if (iw == 0) { /* v**0 is 1, even 0**0 */ if (iw == 0) { /* v**0 is 1, even 0**0 */
return PyFloat_FromDouble(1.0); *res = 1.0;
return 0;
} }
if (Py_IS_NAN(iv)) { /* nan**w = nan, unless w == 0 */ if (Py_IS_NAN(iv)) { /* nan**w = nan, unless w == 0 */
return PyFloat_FromDouble(iv); *res = iv;
return 0;
} }
if (Py_IS_NAN(iw)) { /* v**nan = nan, unless v == 1; 1**nan = 1 */ if (Py_IS_NAN(iw)) { /* v**nan = nan, unless v == 1; 1**nan = 1 */
return PyFloat_FromDouble(iv == 1.0 ? 1.0 : iw); *res = (iv == 1.0 ? 1.0 : iw);
return 0;
} }
if (Py_IS_INFINITY(iw)) { if (Py_IS_INFINITY(iw)) {
/* v**inf is: 0.0 if abs(v) < 1; 1.0 if abs(v) == 1; inf if /* v**inf is: 0.0 if abs(v) < 1; 1.0 if abs(v) == 1; inf if
...@@ -853,12 +873,16 @@ float_pow(PyObject *v, PyObject *w, PyObject *z) ...@@ -853,12 +873,16 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
* abs(v) > 1 (including case where v infinite) * abs(v) > 1 (including case where v infinite)
*/ */
iv = fabs(iv); iv = fabs(iv);
if (iv == 1.0) if (iv == 1.0) {
return PyFloat_FromDouble(1.0); *res = 1.0;
else if ((iw > 0.0) == (iv > 1.0)) return 0;
return PyFloat_FromDouble(fabs(iw)); /* return inf */ } else if ((iw > 0.0) == (iv > 1.0)) {
else *res = fabs(iw);
return PyFloat_FromDouble(0.0); return 0;
} else {
*res = 0.0;
return 0;
}
} }
if (Py_IS_INFINITY(iv)) { if (Py_IS_INFINITY(iv)) {
/* (+-inf)**w is: inf for w positive, 0 for w negative; in /* (+-inf)**w is: inf for w positive, 0 for w negative; in
...@@ -866,11 +890,13 @@ float_pow(PyObject *v, PyObject *w, PyObject *z) ...@@ -866,11 +890,13 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
* an odd integer. * an odd integer.
*/ */
int iw_is_odd = DOUBLE_IS_ODD_INTEGER(iw); int iw_is_odd = DOUBLE_IS_ODD_INTEGER(iw);
if (iw > 0.0) if (iw > 0.0) {
return PyFloat_FromDouble(iw_is_odd ? iv : fabs(iv)); *res = (iw_is_odd ? iv : fabs(iv));
else return 0;
return PyFloat_FromDouble(iw_is_odd ? } else {
copysign(0.0, iv) : 0.0); *res = (iw_is_odd ? copysign(0.0, iv) : 0.0);
return 0;
}
} }
if (iv == 0.0) { /* 0**w is: 0 for w positive, 1 for w zero if (iv == 0.0) { /* 0**w is: 0 for w positive, 1 for w zero
(already dealt with above), and an error (already dealt with above), and an error
...@@ -880,10 +906,11 @@ float_pow(PyObject *v, PyObject *w, PyObject *z) ...@@ -880,10 +906,11 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
PyErr_SetString(PyExc_ZeroDivisionError, PyErr_SetString(PyExc_ZeroDivisionError,
"0.0 cannot be raised to a " "0.0 cannot be raised to a "
"negative power"); "negative power");
return NULL; return 1;
} }
/* use correct sign if iw is odd */ /* use correct sign if iw is odd */
return PyFloat_FromDouble(iw_is_odd ? iv : 0.0); *res = (iw_is_odd ? iv : 0.0);
return 0;
} }
if (iv < 0.0) { if (iv < 0.0) {
...@@ -893,7 +920,7 @@ float_pow(PyObject *v, PyObject *w, PyObject *z) ...@@ -893,7 +920,7 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
if (iw != floor(iw)) { if (iw != floor(iw)) {
PyErr_SetString(PyExc_ValueError, "negative number " PyErr_SetString(PyExc_ValueError, "negative number "
"cannot be raised to a fractional power"); "cannot be raised to a fractional power");
return NULL; return 1;
} }
/* iw is an exact integer, albeit perhaps a very large /* iw is an exact integer, albeit perhaps a very large
* one. Replace iv by its absolute value and remember * one. Replace iv by its absolute value and remember
...@@ -915,7 +942,8 @@ float_pow(PyObject *v, PyObject *w, PyObject *z) ...@@ -915,7 +942,8 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
* happen to be representable in a *C* integer. That's a * happen to be representable in a *C* integer. That's a
* bug. * bug.
*/ */
return PyFloat_FromDouble(negate_result ? -1.0 : 1.0); *res = (negate_result ? -1.0 : 1.0);
return 0;
} }
/* Now iv and iw are finite, iw is nonzero, and iv is /* Now iv and iw are finite, iw is nonzero, and iv is
...@@ -923,7 +951,7 @@ float_pow(PyObject *v, PyObject *w, PyObject *z) ...@@ -923,7 +951,7 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
* the platform pow to step in and do the rest. * the platform pow to step in and do the rest.
*/ */
errno = 0; errno = 0;
PyFPE_START_PROTECT("pow", return NULL) PyFPE_START_PROTECT("pow", return 1)
ix = pow(iv, iw); ix = pow(iv, iw);
PyFPE_END_PROTECT(ix) PyFPE_END_PROTECT(ix)
Py_ADJUST_ERANGE1(ix); Py_ADJUST_ERANGE1(ix);
...@@ -936,9 +964,10 @@ float_pow(PyObject *v, PyObject *w, PyObject *z) ...@@ -936,9 +964,10 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
*/ */
PyErr_SetFromErrno(errno == ERANGE ? PyExc_OverflowError : PyErr_SetFromErrno(errno == ERANGE ? PyExc_OverflowError :
PyExc_ValueError); PyExc_ValueError);
return NULL; return 1;
} }
return PyFloat_FromDouble(ix); *res = ix;
return 0;
} }
#undef DOUBLE_IS_ODD_INTEGER #undef DOUBLE_IS_ODD_INTEGER
......
...@@ -30,6 +30,8 @@ extern "C" PyObject* float_fromhex(PyObject* cls, PyObject* arg) noexcept; ...@@ -30,6 +30,8 @@ extern "C" PyObject* float_fromhex(PyObject* cls, PyObject* arg) noexcept;
extern "C" PyObject* float_as_integer_ratio(PyObject* v, PyObject* unused) noexcept; extern "C" PyObject* float_as_integer_ratio(PyObject* v, PyObject* unused) noexcept;
extern "C" PyObject* float_is_integer(PyObject* v) noexcept; extern "C" PyObject* float_is_integer(PyObject* v) noexcept;
extern "C" PyObject* float__format__(PyObject* v) noexcept; extern "C" PyObject* float__format__(PyObject* v) noexcept;
extern "C" PyObject* float_pow(PyObject* v, PyObject* w, PyObject* z) noexcept;
extern "C" int float_pow_unboxed(double iv, double iw, double* res) noexcept;
namespace pyston { namespace pyston {
...@@ -95,10 +97,6 @@ extern "C" double mod_float_float(double lhs, double rhs) { ...@@ -95,10 +97,6 @@ extern "C" double mod_float_float(double lhs, double rhs) {
return r; return r;
} }
extern "C" double pow_float_float(double lhs, double rhs) {
return pow(lhs, rhs);
}
extern "C" double div_float_float(double lhs, double rhs) { extern "C" double div_float_float(double lhs, double rhs) {
raiseDivZeroExcIfZero(rhs); raiseDivZeroExcIfZero(rhs);
return lhs / rhs; return lhs / rhs;
...@@ -426,35 +424,35 @@ extern "C" Box* floatRMod(BoxedFloat* lhs, Box* rhs) { ...@@ -426,35 +424,35 @@ extern "C" Box* floatRMod(BoxedFloat* lhs, Box* rhs) {
} }
} }
extern "C" Box* floatPow(BoxedFloat* lhs, Box* rhs, Box* mod) {
Box* res = float_pow(lhs, rhs, mod);
if (!res) {
throwCAPIException();
}
return res;
}
extern "C" Box* floatPowFloat(BoxedFloat* lhs, BoxedFloat* rhs, Box* mod = None) { extern "C" Box* floatPowFloat(BoxedFloat* lhs, BoxedFloat* rhs, Box* mod = None) {
// TODO to specialize this, need to account for all the special cases in float_pow
assert(lhs->cls == float_cls); assert(lhs->cls == float_cls);
assert(rhs->cls == float_cls); assert(rhs->cls == float_cls);
if (mod != None) return floatPow(lhs, rhs, mod);
raiseExcHelper(TypeError, "pow() 3rd argument not allowed unless all arguments are integers");
return boxFloat(pow(lhs->d, rhs->d));
} }
extern "C" Box* floatPowInt(BoxedFloat* lhs, BoxedInt* rhs, Box* mod = None) { extern "C" Box* floatPowInt(BoxedFloat* lhs, BoxedInt* rhs, Box* mod = None) {
// TODO to specialize this, need to account for all the special cases in float_pow
assert(lhs->cls == float_cls); assert(lhs->cls == float_cls);
assert(isSubclass(rhs->cls, int_cls)); assert(isSubclass(rhs->cls, int_cls));
if (mod != None) return floatPow(lhs, rhs, mod);
raiseExcHelper(TypeError, "pow() 3rd argument not allowed unless all arguments are integers");
return boxFloat(pow(lhs->d, rhs->n));
} }
extern "C" Box* floatPow(BoxedFloat* lhs, Box* rhs, Box* mod) { extern "C" double pow_float_float(double lhs, double rhs) {
assert(lhs->cls == float_cls); double res;
if (mod != None) int err = float_pow_unboxed(lhs, rhs, &res);
raiseExcHelper(TypeError, "pow() 3rd argument not allowed unless all arguments are integers"); if (err) {
throwCAPIException();
if (isSubclass(rhs->cls, int_cls)) {
return floatPowInt(lhs, static_cast<BoxedInt*>(rhs));
} else if (rhs->cls == float_cls) {
return floatPowFloat(lhs, static_cast<BoxedFloat*>(rhs));
} else if (rhs->cls == long_cls) {
return boxFloat(pow(lhs->d, PyLong_AsDouble(rhs)));
} else { } else {
return NotImplemented; return res;
} }
} }
......
...@@ -31,6 +31,8 @@ ...@@ -31,6 +31,8 @@
#include "runtime/types.h" #include "runtime/types.h"
#include "runtime/util.h" #include "runtime/util.h"
extern "C" PyObject* float_pow(PyObject* v, PyObject* w, PyObject* z) noexcept;
namespace pyston { namespace pyston {
extern "C" long PyInt_GetMax() noexcept { extern "C" long PyInt_GetMax() noexcept {
......
...@@ -65,3 +65,12 @@ print (0.5).as_integer_ratio() ...@@ -65,3 +65,12 @@ print (0.5).as_integer_ratio()
print (0.5).is_integer() print (0.5).is_integer()
print (1.0).is_integer() print (1.0).is_integer()
print 1.0.__hash__(), 1.1.__hash__(), -1.1.__hash__() print 1.0.__hash__(), 1.1.__hash__(), -1.1.__hash__()
print 1.0 ** (10 ** 100)
print (-1.0) ** (10 ** 100)
print (-1.0) ** (10 ** 100 + 1)
print 0.0 ** 0.0
try:
0.0 ** (-1.0)
except ZeroDivisionError as e:
print e.message
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