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)
x is not an infinity or nan. */
#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)
{
double iv, iw, ix;
int negate_result = 0;
double iv, iw, res;
int err;
if ((PyObject *)z != Py_None) {
PyErr_SetString(PyExc_TypeError, "pow() 3rd argument not "
......@@ -835,15 +838,32 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
CONVERT_TO_DOUBLE(v, iv);
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() */
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 */
return PyFloat_FromDouble(iv);
*res = iv;
return 0;
}
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)) {
/* 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)
* abs(v) > 1 (including case where v infinite)
*/
iv = fabs(iv);
if (iv == 1.0)
return PyFloat_FromDouble(1.0);
else if ((iw > 0.0) == (iv > 1.0))
return PyFloat_FromDouble(fabs(iw)); /* return inf */
else
return PyFloat_FromDouble(0.0);
if (iv == 1.0) {
*res = 1.0;
return 0;
} else if ((iw > 0.0) == (iv > 1.0)) {
*res = fabs(iw);
return 0;
} else {
*res = 0.0;
return 0;
}
}
if (Py_IS_INFINITY(iv)) {
/* (+-inf)**w is: inf for w positive, 0 for w negative; in
......@@ -866,11 +890,13 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
* an odd integer.
*/
int iw_is_odd = DOUBLE_IS_ODD_INTEGER(iw);
if (iw > 0.0)
return PyFloat_FromDouble(iw_is_odd ? iv : fabs(iv));
else
return PyFloat_FromDouble(iw_is_odd ?
copysign(0.0, iv) : 0.0);
if (iw > 0.0) {
*res = (iw_is_odd ? iv : fabs(iv));
return 0;
} else {
*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
(already dealt with above), and an error
......@@ -880,10 +906,11 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
PyErr_SetString(PyExc_ZeroDivisionError,
"0.0 cannot be raised to a "
"negative power");
return NULL;
return 1;
}
/* 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) {
......@@ -893,7 +920,7 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
if (iw != floor(iw)) {
PyErr_SetString(PyExc_ValueError, "negative number "
"cannot be raised to a fractional power");
return NULL;
return 1;
}
/* iw is an exact integer, albeit perhaps a very large
* one. Replace iv by its absolute value and remember
......@@ -915,7 +942,8 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
* happen to be representable in a *C* integer. That's a
* 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
......@@ -923,7 +951,7 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
* the platform pow to step in and do the rest.
*/
errno = 0;
PyFPE_START_PROTECT("pow", return NULL)
PyFPE_START_PROTECT("pow", return 1)
ix = pow(iv, iw);
PyFPE_END_PROTECT(ix)
Py_ADJUST_ERANGE1(ix);
......@@ -936,9 +964,10 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
*/
PyErr_SetFromErrno(errno == ERANGE ? PyExc_OverflowError :
PyExc_ValueError);
return NULL;
return 1;
}
return PyFloat_FromDouble(ix);
*res = ix;
return 0;
}
#undef DOUBLE_IS_ODD_INTEGER
......
......@@ -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_is_integer(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 {
......@@ -95,10 +97,6 @@ extern "C" double mod_float_float(double lhs, double rhs) {
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) {
raiseDivZeroExcIfZero(rhs);
return lhs / 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) {
// TODO to specialize this, need to account for all the special cases in float_pow
assert(lhs->cls == float_cls);
assert(rhs->cls == float_cls);
if (mod != None)
raiseExcHelper(TypeError, "pow() 3rd argument not allowed unless all arguments are integers");
return boxFloat(pow(lhs->d, rhs->d));
return floatPow(lhs, rhs, mod);
}
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(isSubclass(rhs->cls, int_cls));
if (mod != None)
raiseExcHelper(TypeError, "pow() 3rd argument not allowed unless all arguments are integers");
return boxFloat(pow(lhs->d, rhs->n));
return floatPow(lhs, rhs, mod);
}
extern "C" Box* floatPow(BoxedFloat* lhs, Box* rhs, Box* mod) {
assert(lhs->cls == float_cls);
if (mod != None)
raiseExcHelper(TypeError, "pow() 3rd argument not allowed unless all arguments are integers");
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)));
extern "C" double pow_float_float(double lhs, double rhs) {
double res;
int err = float_pow_unboxed(lhs, rhs, &res);
if (err) {
throwCAPIException();
} else {
return NotImplemented;
return res;
}
}
......
......@@ -31,6 +31,8 @@
#include "runtime/types.h"
#include "runtime/util.h"
extern "C" PyObject* float_pow(PyObject* v, PyObject* w, PyObject* z) noexcept;
namespace pyston {
extern "C" long PyInt_GetMax() noexcept {
......
......@@ -65,3 +65,12 @@ print (0.5).as_integer_ratio()
print (0.5).is_integer()
print (1.0).is_integer()
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