Commit e6ba3768 authored by Boxiang Sun's avatar Boxiang Sun

some improvements that let test_fractions could pass

parent 48b9a874
......@@ -1528,8 +1528,13 @@ Box* instanceLong(Box* _inst) {
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);
static BoxedString* long_str = internStringImmortal("__long__");
if (PyObject_HasAttr((PyObject*)inst, long_str)) {
Box* long_func = _instanceGetattribute(inst, long_str, true);
return runtimeCall(long_func, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
}
Box* res = instanceInt(inst);
return res;
}
Box* instanceFloat(Box* _inst) {
......
......@@ -541,6 +541,23 @@ Box* complexPow(BoxedComplex* lhs, Box* _rhs, Box* mod) {
return boxComplex(p.real, p.imag);
}
Box* complexRpow(BoxedComplex* _lhs, Box* _rhs) {
if (!PyComplex_Check(_lhs))
raiseExcHelper(TypeError, "descriptor '__rpow__' requires a 'complex' object but received a '%s'",
getTypeName(_lhs));
BoxedComplex* lhs = new BoxedComplex(0.0, 0.0);
if (PyInt_Check(_rhs)) {
lhs->real = (static_cast<BoxedInt*>(_rhs))->n;
} else if (_rhs->cls == float_cls) {
lhs->real = (static_cast<BoxedFloat*>(_rhs))->d;
} else if (_rhs->cls == complex_cls) {
lhs = static_cast<BoxedComplex*>(_rhs);
} else {
return NotImplemented;
}
return complexPow(lhs, _lhs, None);
}
Box* complexHash(BoxedComplex* self) {
if (!PyComplex_Check(self))
raiseExcHelper(TypeError, "descriptor '__hash__' requires a 'complex' object but received a '%s'",
......@@ -1254,6 +1271,8 @@ void setupComplex() {
complex_cls->giveAttr("__rdiv__", new BoxedFunction(FunctionMetadata::create((void*)complexRDiv, UNKNOWN, 2)));
complex_cls->giveAttr(
"__pow__", new BoxedFunction(FunctionMetadata::create((void*)complexPow, UNKNOWN, 3, false, false), { None }));
complex_cls->giveAttr("__rpow__", new BoxedFunction(FunctionMetadata::create((void*)complexRpow, UNKNOWN, 2)));
complex_cls->giveAttr("__mod__", new BoxedFunction(FunctionMetadata::create((void*)complexMod, UNKNOWN, 2)));
complex_cls->giveAttr("__divmod__",
new BoxedFunction(FunctionMetadata::create((void*)complexDivmod, BOXED_TUPLE, 2)));
......
......@@ -54,8 +54,13 @@ extern "C" double PyFloat_AsDouble(PyObject* o) noexcept {
if (o->cls == int_cls || o->cls == bool_cls)
return (double)static_cast<BoxedInt*>(o)->n;
// special case: long
if (o->cls == long_cls)
return mpz_get_d(static_cast<BoxedLong*>(o)->n);
if (o->cls == long_cls) {
double result = PyLong_AsDouble(static_cast<BoxedLong*>(o));
if (result == -1.0 && PyErr_Occurred())
return -1.0;
return result;
}
// implementation from cpython:
PyNumberMethods* nb;
......@@ -125,7 +130,11 @@ extern "C" Box* floatAdd(BoxedFloat* lhs, Box* rhs) {
} else if (rhs->cls == float_cls) {
return floatAddFloat(lhs, static_cast<BoxedFloat*>(rhs));
} else if (rhs->cls == long_cls) {
return boxFloat(lhs->d + PyLong_AsDouble(rhs));
double rhs_f = PyLong_AsDouble(rhs);
if (rhs_f == -1.0 && PyErr_Occurred()) {
throwCAPIException();
}
return boxFloat(lhs->d + rhs_f);
} else {
return NotImplemented;
}
......@@ -152,7 +161,11 @@ extern "C" Box* floatDiv(BoxedFloat* lhs, Box* rhs) {
} else if (rhs->cls == float_cls) {
return floatDivFloat(lhs, static_cast<BoxedFloat*>(rhs));
} else if (rhs->cls == long_cls) {
return boxFloat(lhs->d / PyLong_AsDouble(rhs));
double rhs_f = PyLong_AsDouble(rhs);
if (rhs_f == -1.0 && PyErr_Occurred()) {
throwCAPIException();
}
return boxFloat(lhs->d / rhs_f);
} else {
return NotImplemented;
}
......@@ -165,7 +178,11 @@ extern "C" Box* floatTruediv(BoxedFloat* lhs, Box* rhs) {
} else if (rhs->cls == float_cls) {
return floatDivFloat(lhs, static_cast<BoxedFloat*>(rhs));
} else if (rhs->cls == long_cls) {
return boxFloat(lhs->d / PyLong_AsDouble(rhs));
double rhs_f = PyLong_AsDouble(rhs);
if (rhs_f == -1.0 && PyErr_Occurred()) {
throwCAPIException();
}
return boxFloat(lhs->d / rhs_f);
} else {
return NotImplemented;
}
......@@ -192,7 +209,11 @@ extern "C" Box* floatRDiv(BoxedFloat* lhs, Box* rhs) {
} else if (rhs->cls == float_cls) {
return floatRDivFloat(lhs, static_cast<BoxedFloat*>(rhs));
} else if (rhs->cls == long_cls) {
return boxFloat(PyLong_AsDouble(rhs) / lhs->d);
double rhs_f = PyLong_AsDouble(rhs);
if (rhs_f == -1.0 && PyErr_Occurred()) {
throwCAPIException();
}
return boxFloat(rhs_f / lhs->d);
} else {
return NotImplemented;
}
......@@ -218,6 +239,33 @@ extern "C" Box* floatFloorDiv(BoxedFloat* lhs, Box* rhs) {
return floatFloorDivInt(lhs, static_cast<BoxedInt*>(rhs));
} else if (rhs->cls == float_cls) {
return floatFloorDivFloat(lhs, static_cast<BoxedFloat*>(rhs));
} else if (rhs->cls == long_cls) {
double rhs_f = PyLong_AsDouble(rhs);
if (rhs_f == -1.0 && PyErr_Occurred()) {
throwCAPIException();
}
return floatFloorDivFloat(lhs, new BoxedFloat(rhs_f));
} else {
return NotImplemented;
}
}
extern "C" Box* floatRFloorDiv(BoxedFloat* lhs, Box* _rhs) {
assert(lhs->cls == float_cls);
if (PyInt_Check(_rhs)) {
BoxedInt* rhs = (BoxedInt*)_rhs;
raiseDivZeroExcIfZero(lhs->d);
return boxFloat(floor(rhs->n / lhs->d));
} else if (_rhs->cls == float_cls) {
BoxedFloat* rhs = (BoxedFloat*)_rhs;
raiseDivZeroExcIfZero(lhs->d);
return boxFloat(floor(rhs->d / lhs->d));
} else if (_rhs->cls == long_cls) {
double rhs_f = PyLong_AsDouble(_rhs);
if (rhs_f == -1.0 && PyErr_Occurred()) {
throwCAPIException();
}
return floatFloorDivFloat(new BoxedFloat(rhs_f), lhs);
} else {
return NotImplemented;
}
......@@ -544,7 +592,11 @@ extern "C" Box* floatMod(BoxedFloat* lhs, Box* rhs) {
} else if (rhs->cls == float_cls) {
return floatModFloat(lhs, static_cast<BoxedFloat*>(rhs));
} else if (rhs->cls == long_cls) {
return boxFloat(mod_float_float(lhs->d, PyLong_AsDouble(rhs)));
double rhs_f = PyLong_AsDouble(rhs);
if (rhs_f == -1.0 && PyErr_Occurred()) {
throwCAPIException();
}
return boxFloat(mod_float_float(lhs->d, rhs_f));
} else {
return NotImplemented;
}
......@@ -569,7 +621,11 @@ extern "C" Box* floatRMod(BoxedFloat* lhs, Box* rhs) {
} else if (rhs->cls == float_cls) {
return floatRModFloat(lhs, static_cast<BoxedFloat*>(rhs));
} else if (rhs->cls == long_cls) {
return boxFloat(mod_float_float(PyLong_AsDouble(rhs), lhs->d));
double rhs_f = PyLong_AsDouble(rhs);
if (rhs_f == -1.0 && PyErr_Occurred()) {
throwCAPIException();
}
return boxFloat(mod_float_float(rhs_f, lhs->d));
} else {
return NotImplemented;
}
......@@ -626,7 +682,11 @@ extern "C" Box* floatMul(BoxedFloat* lhs, Box* rhs) {
} else if (rhs->cls == float_cls) {
return floatMulFloat(lhs, static_cast<BoxedFloat*>(rhs));
} else if (rhs->cls == long_cls) {
return boxFloat(lhs->d * PyLong_AsDouble(rhs));
double rhs_f = PyLong_AsDouble(rhs);
if (rhs_f == -1.0 && PyErr_Occurred()) {
throwCAPIException();
}
return boxFloat(lhs->d * rhs_f);
} else {
return NotImplemented;
}
......@@ -651,7 +711,11 @@ extern "C" Box* floatSub(BoxedFloat* lhs, Box* rhs) {
} else if (rhs->cls == float_cls) {
return floatSubFloat(lhs, static_cast<BoxedFloat*>(rhs));
} else if (rhs->cls == long_cls) {
return boxFloat(lhs->d - PyLong_AsDouble(rhs));
double rhs_f = PyLong_AsDouble(rhs);
if (rhs_f == -1.0 && PyErr_Occurred()) {
throwCAPIException();
}
return boxFloat(lhs->d - rhs_f);
} else {
return NotImplemented;
}
......@@ -676,7 +740,11 @@ extern "C" Box* floatRSub(BoxedFloat* lhs, Box* rhs) {
} else if (rhs->cls == float_cls) {
return floatRSubFloat(lhs, static_cast<BoxedFloat*>(rhs));
} else if (rhs->cls == long_cls) {
return boxFloat(PyLong_AsDouble(rhs) - lhs->d);
double rhs_f = PyLong_AsDouble(rhs);
if (rhs_f == -1.0 && PyErr_Occurred()) {
throwCAPIException();
}
return boxFloat(rhs_f - lhs->d);
} else {
return NotImplemented;
}
......@@ -782,6 +850,13 @@ template <ExceptionStyle S> static BoxedFloat* _floatNew(Box* a) noexcept(S == C
return static_cast<BoxedFloat*>(a);
} else if (PyInt_Check(a)) {
return new BoxedFloat(static_cast<BoxedInt*>(a)->n);
} else if (PyLong_Check(a)) {
double a_f = PyLong_AsDouble(a);
if (a_f == -1.0 && PyErr_Occurred()) {
throwCAPIException();
}
return new BoxedFloat(a_f);
} else if (a->cls == str_cls || a->cls == unicode_cls) {
BoxedFloat* res = (BoxedFloat*)PyFloat_FromString(a, NULL);
......@@ -1652,6 +1727,8 @@ void setupFloat() {
_addFunc("__div__", BOXED_FLOAT, (void*)floatDivFloat, (void*)floatDivInt, (void*)floatDiv);
_addFunc("__rdiv__", BOXED_FLOAT, (void*)floatRDivFloat, (void*)floatRDivInt, (void*)floatRDiv);
_addFunc("__floordiv__", BOXED_FLOAT, (void*)floatFloorDivFloat, (void*)floatFloorDivInt, (void*)floatFloorDiv);
float_cls->giveAttr("__rfloordiv__",
new BoxedFunction(FunctionMetadata::create((void*)floatRFloorDiv, BOXED_FLOAT, 2)));
_addFunc("__truediv__", BOXED_FLOAT, (void*)floatDivFloat, (void*)floatDivInt, (void*)floatTruediv);
_addFunc("__mod__", BOXED_FLOAT, (void*)floatModFloat, (void*)floatModInt, (void*)floatMod);
......
......@@ -15,7 +15,9 @@
#include "runtime/long.h"
#include <cmath>
#include <float.h>
#include <gmp.h>
#include <mpfr.h>
#include <sstream>
#include "llvm/Support/raw_ostream.h"
......@@ -212,17 +214,18 @@ extern "C" PyObject* PyLong_FromString(const char* str, char** pend, int base) n
BoxedLong* rtn = new BoxedLong();
int r = 0;
if (str[strlen(str) - 1] == 'L' || str[strlen(str) - 1] == 'l') {
if ((str[strlen(str) - 1] == 'L' || str[strlen(str) - 1] == 'l') && base < 22) {
std::string without_l(str, strlen(str) - 1);
r = mpz_init_set_str(rtn->n, without_l.c_str(), base);
} else {
// if base great than 22, 'l' or 'L' should count as a digit.
r = mpz_init_set_str(rtn->n, str, base);
}
if (pend)
*pend = const_cast<char*>(str) + strlen(str);
if (r != 0) {
PyErr_Format(PyExc_ValueError, "invalid literal for long() with base %d: %s", base, str);
PyErr_Format(PyExc_ValueError, "invalid literal for long() with base %d: '%s'", base, str);
return NULL;
}
......@@ -347,15 +350,17 @@ extern "C" long PyLong_AsLongAndOverflow(Box* vv, int* overflow) noexcept {
extern "C" double PyLong_AsDouble(PyObject* vv) noexcept {
RELEASE_ASSERT(PyLong_Check(vv), "");
BoxedLong* l = static_cast<BoxedLong*>(vv);
mpfr_t result;
mpfr_init(result);
mpfr_init_set_z(result, l->n, MPFR_RNDN);
double result = mpz_get_d(l->n);
if (std::isinf(result)) {
double result_f = mpfr_get_d(result, MPFR_RNDN);
if (isinf(result_f)) {
PyErr_SetString(PyExc_OverflowError, "long int too large to convert to float");
return -1;
}
return result;
return result_f;
}
/* Convert the long to a string object with given base,
......@@ -463,7 +468,10 @@ extern "C" PyObject* PyLong_FromSize_t(size_t ival) noexcept {
#undef IS_LITTLE_ENDIAN
extern "C" double _PyLong_Frexp(PyLongObject* a, Py_ssize_t* e) noexcept {
Py_FatalError("unimplemented");
BoxedLong* v = (BoxedLong*)a;
double result = mpz_get_d_2exp(e, v->n);
static_assert(sizeof(Py_ssize_t) == 8, "need to add overflow checking");
return result;
}
/* Create a new long (or int) object from a C pointer */
......@@ -698,11 +706,11 @@ template <ExceptionStyle S> Box* _longNew(Box* val, Box* _base) noexcept(S == CA
if (s->size() != strlen(s->data())) {
Box* srepr = PyObject_Repr(val);
if (S == CAPI) {
PyErr_Format(PyExc_ValueError, "invalid literal for long() with base %d: %s", base,
PyErr_Format(PyExc_ValueError, "invalid literal for long() with base %d: '%s'", base,
PyString_AS_STRING(srepr));
return NULL;
} else {
raiseExcHelper(ValueError, "invalid literal for long() with base %d: %s", base,
raiseExcHelper(ValueError, "invalid literal for long() with base %d: '%s'", base,
PyString_AS_STRING(srepr));
}
}
......@@ -780,8 +788,8 @@ Box* longFloat(BoxedLong* v) {
double result = PyLong_AsDouble(v);
if (result == -1)
checkAndThrowCAPIException();
if (result == -1.0 && PyErr_Occurred())
throwCAPIException();
return new BoxedFloat(result);
}
......@@ -1241,18 +1249,32 @@ Box* longTrueDiv(BoxedLong* v1, Box* _v2) {
raiseExcHelper(TypeError, "descriptor '__truediv__' requires a 'long' object but received a '%s'",
getTypeName(v1));
// We only support args which fit into an int for now...
int overflow = 0;
long lhs = PyLong_AsLongAndOverflow(v1, &overflow);
if (overflow)
return NotImplemented;
long rhs = PyLong_AsLongAndOverflow(_v2, &overflow);
if (overflow)
BoxedLong* v2;
if (PyInt_Check(_v2) || PyLong_Check(_v2)) {
v2 = (BoxedLong*)PyNumber_Long(_v2);
if (!v2) {
throwCAPIException();
}
} else {
return NotImplemented;
}
if (rhs == 0)
if (mpz_sgn(v2->n) == 0) {
raiseExcHelper(ZeroDivisionError, "division by zero");
return boxFloat(lhs / (double)rhs);
}
mpfr_t lhs_f, rhs_f, result;
mpfr_init(result);
mpfr_init_set_z(lhs_f, v1->n, MPFR_RNDN);
mpfr_init_set_z(rhs_f, v2->n, MPFR_RNDZ);
mpfr_div(result, lhs_f, rhs_f, MPFR_RNDN);
double result_f = mpfr_get_d(result, MPFR_RNDN);
if (isinf(result_f)) {
raiseExcHelper(OverflowError, "integer division result too large for a float");
}
return boxFloat(result_f);
}
Box* longRTrueDiv(BoxedLong* v1, Box* _v2) {
......@@ -1260,18 +1282,27 @@ Box* longRTrueDiv(BoxedLong* v1, Box* _v2) {
raiseExcHelper(TypeError, "descriptor '__rtruediv__' requires a 'long' object but received a '%s'",
getTypeName(v1));
// We only support args which fit into an int for now...
int overflow = 0;
long lhs = PyLong_AsLongAndOverflow(_v2, &overflow);
if (overflow)
return NotImplemented;
long rhs = PyLong_AsLongAndOverflow(v1, &overflow);
if (overflow)
BoxedLong* v2;
if (PyInt_Check(_v2) || PyLong_Check(_v2)) {
v2 = (BoxedLong*)PyNumber_Long(_v2);
} else {
return NotImplemented;
if (rhs == 0)
}
if (mpz_sgn(v2->n) == 0) {
raiseExcHelper(ZeroDivisionError, "division by zero");
return boxFloat(lhs / (double)rhs);
}
mpfr_t lhs_f, rhs_f, result;
mpfr_init(result);
mpfr_init_set_z(lhs_f, v2->n, MPFR_RNDN);
mpfr_init_set_z(rhs_f, v1->n, MPFR_RNDZ);
mpfr_div(result, lhs_f, rhs_f, MPFR_RNDN);
double result_f = mpfr_get_d(result, MPFR_RNDZ);
if (isinf(result_f)) {
raiseExcHelper(OverflowError, "integer division result too large for a float");
}
return boxFloat(result_f);
}
static void _addFuncPow(const char* name, ConcreteCompilerType* rtn_type, void* float_func, void* long_func) {
......@@ -1393,14 +1424,17 @@ Box* longHash(BoxedLong* self) {
if (mpz_fits_slong_p(self->n))
return boxInt(mpz_get_si(self->n));
// Not sure if this is a good hash function or not;
// simple, but only includes top bits:
union {
uint64_t n;
double d;
};
d = mpz_get_d(self->n);
return boxInt(n);
// CPython use the absolute value of self mod ULONG_MAX.
unsigned long remainder = mpz_tdiv_ui(self->n, ULONG_MAX);
if (remainder == 0)
remainder = -1; // CPython compatibility -- ULONG_MAX mod ULONG_MAX is ULONG_MAX to them.
remainder *= mpz_sgn(self->n);
if (remainder == -1)
remainder = -2;
return boxInt(remainder);
}
extern "C" Box* longTrunc(BoxedLong* self) {
......
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