Commit ccdbbaa7 authored by Marius Wachtler's avatar Marius Wachtler

float.cpp: now that we have float.c use some of the functions directly

this also workarounds the problem we were having on ubuntu 16.04 where we have to use std::isinf instead of isinf()
parent 5ae5bf2c
......@@ -409,9 +409,7 @@ float_str(PyFloatObject *v)
* coercion to double. So this part is painful too.
*/
// Pyston change: don't need this for now
#if 0
static PyObject*
PyObject*
float_richcompare(PyObject *v, PyObject *w, int op)
{
double i, j;
......@@ -624,7 +622,6 @@ float_richcompare(PyObject *v, PyObject *w, int op)
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
#endif
static long
float_hash(PyFloatObject *v)
......@@ -1887,7 +1884,7 @@ float_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return newobj;
}
static PyObject *
PyObject *
float_getnewargs(PyFloatObject *v)
{
return Py_BuildValue("(d)", v->ob_fval);
......@@ -1902,7 +1899,7 @@ typedef enum {
static float_format_type double_format, float_format;
static float_format_type detected_double_format, detected_float_format;
static PyObject *
PyObject *
float_getformat(PyTypeObject *v, PyObject* arg)
{
char* s;
......@@ -2200,6 +2197,8 @@ PyTypeObject PyFloat_Type = {
0, /* tp_alloc */
float_new, /* tp_new */
};
// pyston change:
#endif
void
_PyFloat_Init(void)
......@@ -2255,6 +2254,8 @@ _PyFloat_Init(void)
PyStructSequence_InitType(&FloatInfoType, &floatinfo_desc);
}
// pyston change: don't need this
#if 0
int
PyFloat_ClearFreeList(void)
{
......@@ -2351,8 +2352,6 @@ PyFloat_Fini(void)
}
#endif
// pyston change: comment this out
#if 0
/*----------------------------------------------------------------------------
* _PyFloat_{Pack,Unpack}{4,8}. See floatobject.h.
*/
......@@ -2762,4 +2761,3 @@ _PyFloat_Unpack8(const unsigned char *p, int le)
return x;
}
}
#endif
......@@ -509,8 +509,10 @@ extern "C" long _Py_HashDouble(double v) noexcept {
* of mapping keys will turn out weird.
*/
// pyston change: was if (!Py_IS_FINITE(v)) {
if (!std::isfinite(v)) {
if (Py_IS_INFINITY(v))
// pyston change: was if (Py_IS_INFINITY(v)) {
if (std::isinf(v))
return v < 0 ? -271828 : 314159;
else
return 0;
......
......@@ -27,17 +27,20 @@
#include "runtime/types.h"
#include "runtime/util.h"
extern "C" PyObject* float_divmod(PyObject* v, PyObject* w) noexcept;
extern "C" int float_coerce(PyObject** v, PyObject** w) noexcept;
extern "C" PyObject* float_hex(PyObject* v) noexcept;
extern "C" PyObject* float_fromhex(PyObject* cls, PyObject* arg) noexcept;
extern "C" int float_pow_unboxed(double iv, double iw, double* res) 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_divmod(PyObject* v, PyObject* w) noexcept;
extern "C" PyObject* float__format__(PyObject* v) noexcept;
extern "C" PyObject* float_setformat(PyTypeObject* v, PyObject* args) noexcept;
extern "C" PyObject* float_fromhex(PyObject* cls, PyObject* arg) noexcept;
extern "C" PyObject* float_getformat(PyTypeObject* v, PyObject* arg) noexcept;
extern "C" PyObject* float_getnewargs(PyFloatObject* v) noexcept;
extern "C" PyObject* float_hex(PyObject* v) noexcept;
extern "C" PyObject* float_is_integer(PyObject* v) noexcept;
extern "C" PyObject* float_pow(PyObject* v, PyObject* w, PyObject* z) noexcept;
extern "C" PyObject* float_richcompare(PyObject* v, PyObject* w, int op) noexcept;
extern "C" PyObject* float_setformat(PyTypeObject* v, PyObject* args) noexcept;
extern "C" PyObject* float_str(PyObject* v) noexcept;
extern "C" int float_pow_unboxed(double iv, double iw, double* res) noexcept;
namespace pyston {
......@@ -379,230 +382,6 @@ extern "C" Box* floatRFloorDiv(BoxedFloat* lhs, Box* _rhs) {
}
}
/* Comparison is pretty much a nightmare. When comparing float to float,
* we do it as straightforwardly (and long-windedly) as conceivable, so
* that, e.g., Python x == y delivers the same result as the platform
* C x == y when x and/or y is a NaN.
* When mixing float with an integer type, there's no good *uniform* approach.
* Converting the double to an integer obviously doesn't work, since we
* may lose info from fractional bits. Converting the integer to a double
* also has two failure modes: (1) a long int may trigger overflow (too
* large to fit in the dynamic range of a C double); (2) even a C long may have
* more bits than fit in a C double (e.g., on a a 64-bit box long may have
* 63 bits of precision, but a C double probably has only 53), and then
* we can falsely claim equality when low-order integer bits are lost by
* coercion to double. So this part is painful too.
*/
static PyObject* float_richcompare(PyObject* v, PyObject* w, int op) noexcept {
double i, j;
int r = 0;
assert(PyFloat_Check(v));
i = PyFloat_AS_DOUBLE(v);
/* Switch on the type of w. Set i and j to doubles to be compared,
* and op to the richcomp to use.
*/
if (PyFloat_Check(w))
j = PyFloat_AS_DOUBLE(w);
else if (!std::isfinite(i)) {
if (PyInt_Check(w) || PyLong_Check(w))
/* If i is an infinity, its magnitude exceeds any
* finite integer, so it doesn't matter which int we
* compare i with. If i is a NaN, similarly.
*/
j = 0.0;
else
goto Unimplemented;
}
else if (PyInt_Check(w)) {
long jj = PyInt_AS_LONG(w);
/* In the worst realistic case I can imagine, C double is a
* Cray single with 48 bits of precision, and long has 64
* bits.
*/
#if SIZEOF_LONG > 6
unsigned long abs = (unsigned long)(jj < 0 ? -jj : jj);
if (abs >> 48) {
/* Needs more than 48 bits. Make it take the
* PyLong path.
*/
PyObject* result;
PyObject* ww = PyLong_FromLong(jj);
if (ww == NULL)
return NULL;
result = float_richcompare(v, ww, op);
Py_DECREF(ww);
return result;
}
#endif
j = (double)jj;
assert((long)j == jj);
}
else if (PyLong_Check(w)) {
int vsign = i == 0.0 ? 0 : i < 0.0 ? -1 : 1;
int wsign = _PyLong_Sign(w);
size_t nbits;
int exponent;
if (vsign != wsign) {
/* Magnitudes are irrelevant -- the signs alone
* determine the outcome.
*/
i = (double)vsign;
j = (double)wsign;
goto Compare;
}
/* The signs are the same. */
/* Convert w to a double if it fits. In particular, 0 fits. */
nbits = mpz_sizeinbase(static_cast<BoxedLong*>(w)->n, 2);
if (nbits == (size_t)-1 && PyErr_Occurred()) {
/* This long is so large that size_t isn't big enough
* to hold the # of bits. Replace with little doubles
* that give the same outcome -- w is so large that
* its magnitude must exceed the magnitude of any
* finite float.
*/
PyErr_Clear();
i = (double)vsign;
assert(wsign != 0);
j = wsign * 2.0;
goto Compare;
}
if (nbits <= 48) {
j = PyLong_AsDouble(w);
/* It's impossible that <= 48 bits overflowed. */
assert(j != -1.0 || !PyErr_Occurred());
goto Compare;
}
assert(wsign != 0); /* else nbits was 0 */
assert(vsign != 0); /* if vsign were 0, then since wsign is
* not 0, we would have taken the
* vsign != wsign branch at the start */
/* We want to work with non-negative numbers. */
if (vsign < 0) {
/* "Multiply both sides" by -1; this also swaps the
* comparator.
*/
i = -i;
op = _Py_SwappedOp[op];
}
assert(i > 0.0);
(void)frexp(i, &exponent);
/* exponent is the # of bits in v before the radix point;
* we know that nbits (the # of bits in w) > 48 at this point
*/
if (exponent < 0 || (size_t)exponent < nbits) {
i = 1.0;
j = 2.0;
goto Compare;
}
if ((size_t)exponent > nbits) {
i = 2.0;
j = 1.0;
goto Compare;
}
/* v and w have the same number of bits before the radix
* point. Construct two longs that have the same comparison
* outcome.
*/
{
double fracpart;
double intpart;
PyObject* result = NULL;
PyObject* one = NULL;
PyObject* vv = NULL;
PyObject* ww = w;
if (wsign < 0) {
ww = PyNumber_Negative(w);
if (ww == NULL)
goto Error;
} else
Py_INCREF(ww);
fracpart = modf(i, &intpart);
vv = PyLong_FromDouble(intpart);
if (vv == NULL)
goto Error;
if (fracpart != 0.0) {
/* Shift left, and or a 1 bit into vv
* to represent the lost fraction.
*/
PyObject* temp;
one = PyInt_FromLong(1);
if (one == NULL)
goto Error;
temp = PyNumber_Lshift(ww, one);
if (temp == NULL)
goto Error;
Py_DECREF(ww);
ww = temp;
temp = PyNumber_Lshift(vv, one);
if (temp == NULL)
goto Error;
Py_DECREF(vv);
vv = temp;
temp = PyNumber_Or(vv, one);
if (temp == NULL)
goto Error;
Py_DECREF(vv);
vv = temp;
}
r = PyObject_RichCompareBool(vv, ww, op);
if (r < 0)
goto Error;
result = PyBool_FromLong(r);
Error:
Py_XDECREF(vv);
Py_XDECREF(ww);
Py_XDECREF(one);
return result;
}
} /* else if (PyLong_Check(w)) */
else /* w isn't float, int, or long */
goto Unimplemented;
Compare:
PyFPE_START_PROTECT("richcompare", return NULL) switch (op) {
case Py_EQ:
r = i == j;
break;
case Py_NE:
r = i != j;
break;
case Py_LE:
r = i <= j;
break;
case Py_GE:
r = i >= j;
break;
case Py_LT:
r = i < j;
break;
case Py_GT:
r = i > j;
break;
}
PyFPE_END_PROTECT(r) return PyBool_FromLong(r);
Unimplemented:
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
extern "C" Box* floatEq(BoxedFloat* lhs, Box* rhs) {
if (!PyFloat_Check(lhs)) {
raiseExcHelper(TypeError, "descriptor '__eq__' requires a 'float' object but received a '%s'",
......@@ -1134,525 +913,14 @@ static Box* float0(Box*, void*) noexcept {
return boxFloat(0.0);
}
// __getformat__
// ported pretty directly from cpython Objects/floatobject.c
typedef enum { unknown_format, ieee_big_endian_format, ieee_little_endian_format } float_format_type;
static float_format_type double_format, float_format;
static float_format_type detected_double_format, detected_float_format;
static void floatFormatInit() {
/* We attempt to determine if this machine is using IEEE
floating point formats by peering at the bits of some
carefully chosen values. If it looks like we are on an
IEEE platform, the float packing/unpacking routines can
just copy bits, if not they resort to arithmetic & shifts
and masks. The shifts & masks approach works on all finite
values, but what happens to infinities, NaNs and signed
zeroes on packing is an accident, and attempting to unpack
a NaN or an infinity will raise an exception.
Note that if we're on some whacked-out platform which uses
IEEE formats but isn't strictly little-endian or big-
endian, we will fall back to the portable shifts & masks
method. */
if (sizeof(double) == 8) {
double x = 9006104071832581.0;
if (memcmp(&x, "\x43\x3f\xff\x01\x02\x03\x04\x05", 8) == 0)
detected_double_format = ieee_big_endian_format;
else if (memcmp(&x, "\x05\x04\x03\x02\x01\xff\x3f\x43", 8) == 0)
detected_double_format = ieee_little_endian_format;
else
detected_double_format = unknown_format;
} else {
detected_double_format = unknown_format;
}
if (sizeof(float) == 4) {
float y = 16711938.0;
if (memcmp(&y, "\x4b\x7f\x01\x02", 4) == 0)
detected_float_format = ieee_big_endian_format;
else if (memcmp(&y, "\x02\x01\x7f\x4b", 4) == 0)
detected_float_format = ieee_little_endian_format;
else
detected_float_format = unknown_format;
} else {
detected_float_format = unknown_format;
}
double_format = detected_double_format;
float_format = detected_float_format;
}
// ported pretty directly from cpython
Box* floatGetFormat(Box* arg) {
char* s;
float_format_type r;
if (!PyString_Check(arg)) {
raiseExcHelper(TypeError, "__getformat__() argument must be string, not %s", arg->cls->tp_name);
}
s = PyString_AS_STRING(arg);
if (strcmp(s, "double") == 0) {
r = double_format;
} else if (strcmp(s, "float") == 0) {
r = float_format;
} else {
raiseExcHelper(ValueError, "__getformat__() argument 1 must be "
"'double' or 'float'");
}
switch (r) {
case unknown_format:
return boxString("unknown");
case ieee_little_endian_format:
return boxString("IEEE, little-endian");
case ieee_big_endian_format:
return boxString("IEEE, big-endian");
default:
RELEASE_ASSERT(false, "insane float_format or double_format");
return NULL;
}
}
const char* floatGetFormatDoc = "float.__getformat__(typestr) -> string\n"
"\n"
"You probably don't want to use this function. It exists mainly to be\n"
"used in Python's test suite.\n"
"\n"
"typestr must be 'double' or 'float'. This function returns whichever of\n"
"'unknown', 'IEEE, big-endian' or 'IEEE, little-endian' best describes the\n"
"format of floating point numbers used by the C type named by typestr.";
static PyObject* float_setformat(PyTypeObject* v, PyObject* args) noexcept {
char* typestr;
char* format;
float_format_type f;
float_format_type detected;
float_format_type* p;
if (!PyArg_ParseTuple(args, "ss:__setformat__", &typestr, &format))
return NULL;
if (strcmp(typestr, "double") == 0) {
p = &double_format;
detected = detected_double_format;
} else if (strcmp(typestr, "float") == 0) {
p = &float_format;
detected = detected_float_format;
} else {
PyErr_SetString(PyExc_ValueError, "__setformat__() argument 1 must "
"be 'double' or 'float'");
return NULL;
}
if (strcmp(format, "unknown") == 0) {
f = unknown_format;
} else if (strcmp(format, "IEEE, little-endian") == 0) {
f = ieee_little_endian_format;
} else if (strcmp(format, "IEEE, big-endian") == 0) {
f = ieee_big_endian_format;
} else {
PyErr_SetString(PyExc_ValueError, "__setformat__() argument 2 must be "
"'unknown', 'IEEE, little-endian' or "
"'IEEE, big-endian'");
return NULL;
}
if (f != unknown_format && f != detected) {
PyErr_Format(PyExc_ValueError, "can only set %s format to 'unknown' or the "
"detected platform value",
typestr);
return NULL;
}
*p = f;
Py_RETURN_NONE;
}
/*----------------------------------------------------------------------------
* _PyFloat_{Pack,Unpack}{4,8}. See floatobject.h.
*/
extern "C" int _PyFloat_Pack4(double x, unsigned char* p, int le) noexcept {
if (float_format == unknown_format) {
unsigned char sign;
int e;
double f;
unsigned int fbits;
int incr = 1;
if (le) {
p += 3;
incr = -1;
}
if (x < 0) {
sign = 1;
x = -x;
} else
sign = 0;
f = frexp(x, &e);
/* Normalize f to be in the range [1.0, 2.0) */
if (0.5 <= f && f < 1.0) {
f *= 2.0;
e--;
} else if (f == 0.0)
e = 0;
else {
PyErr_SetString(PyExc_SystemError, "frexp() result out of range");
return -1;
}
if (e >= 128)
goto Overflow;
else if (e < -126) {
/* Gradual underflow */
f = ldexp(f, 126 + e);
e = 0;
} else if (!(e == 0 && f == 0.0)) {
e += 127;
f -= 1.0; /* Get rid of leading 1 */
}
f *= 8388608.0; /* 2**23 */
fbits = (unsigned int)(f + 0.5); /* Round */
assert(fbits <= 8388608);
if (fbits >> 23) {
/* The carry propagated out of a string of 23 1 bits. */
fbits = 0;
++e;
if (e >= 255)
goto Overflow;
}
/* First byte */
*p = (sign << 7) | (e >> 1);
p += incr;
/* Second byte */
*p = (char)(((e & 1) << 7) | (fbits >> 16));
p += incr;
/* Third byte */
*p = (fbits >> 8) & 0xFF;
p += incr;
/* Fourth byte */
*p = fbits & 0xFF;
/* Done */
return 0;
} else {
float y = (float)x;
const char* s = (char*)&y;
int i, incr = 1;
if (Py_IS_INFINITY(y) && !Py_IS_INFINITY(x))
goto Overflow;
if ((float_format == ieee_little_endian_format && !le) || (float_format == ieee_big_endian_format && le)) {
p += 3;
incr = -1;
}
for (i = 0; i < 4; i++) {
*p = *s++;
p += incr;
}
return 0;
}
Overflow:
PyErr_SetString(PyExc_OverflowError, "float too large to pack with f format");
return -1;
}
extern "C" int _PyFloat_Pack8(double x, unsigned char* p, int le) noexcept {
if (double_format == unknown_format) {
unsigned char sign;
int e;
double f;
unsigned int fhi, flo;
int incr = 1;
if (le) {
p += 7;
incr = -1;
}
if (x < 0) {
sign = 1;
x = -x;
} else
sign = 0;
f = frexp(x, &e);
/* Normalize f to be in the range [1.0, 2.0) */
if (0.5 <= f && f < 1.0) {
f *= 2.0;
e--;
} else if (f == 0.0)
e = 0;
else {
PyErr_SetString(PyExc_SystemError, "frexp() result out of range");
return -1;
}
if (e >= 1024)
goto Overflow;
else if (e < -1022) {
/* Gradual underflow */
f = ldexp(f, 1022 + e);
e = 0;
} else if (!(e == 0 && f == 0.0)) {
e += 1023;
f -= 1.0; /* Get rid of leading 1 */
}
/* fhi receives the high 28 bits; flo the low 24 bits (== 52 bits) */
f *= 268435456.0; /* 2**28 */
fhi = (unsigned int)f; /* Truncate */
assert(fhi < 268435456);
f -= (double)fhi;
f *= 16777216.0; /* 2**24 */
flo = (unsigned int)(f + 0.5); /* Round */
assert(flo <= 16777216);
if (flo >> 24) {
/* The carry propagated out of a string of 24 1 bits. */
flo = 0;
++fhi;
if (fhi >> 28) {
/* And it also progagated out of the next 28 bits. */
fhi = 0;
++e;
if (e >= 2047)
goto Overflow;
}
}
/* First byte */
*p = (sign << 7) | (e >> 4);
p += incr;
/* Second byte */
*p = (unsigned char)(((e & 0xF) << 4) | (fhi >> 24));
p += incr;
/* Third byte */
*p = (fhi >> 16) & 0xFF;
p += incr;
/* Fourth byte */
*p = (fhi >> 8) & 0xFF;
p += incr;
/* Fifth byte */
*p = fhi & 0xFF;
p += incr;
/* Sixth byte */
*p = (flo >> 16) & 0xFF;
p += incr;
/* Seventh byte */
*p = (flo >> 8) & 0xFF;
p += incr;
/* Eighth byte */
*p = flo & 0xFF;
/* p += incr; Unneeded (for now) */
/* Done */
return 0;
Overflow:
PyErr_SetString(PyExc_OverflowError, "float too large to pack with d format");
return -1;
} else {
const char* s = (char*)&x;
int i, incr = 1;
if ((double_format == ieee_little_endian_format && !le) || (double_format == ieee_big_endian_format && le)) {
p += 7;
incr = -1;
}
for (i = 0; i < 8; i++) {
*p = *s++;
p += incr;
}
return 0;
}
}
extern "C" double _PyFloat_Unpack4(const unsigned char* p, int le) noexcept {
if (float_format == unknown_format) {
unsigned char sign;
int e;
unsigned int f;
double x;
int incr = 1;
if (le) {
p += 3;
incr = -1;
}
/* First byte */
sign = (*p >> 7) & 1;
e = (*p & 0x7F) << 1;
p += incr;
/* Second byte */
e |= (*p >> 7) & 1;
f = (*p & 0x7F) << 16;
p += incr;
if (e == 255) {
PyErr_SetString(PyExc_ValueError, "can't unpack IEEE 754 special value "
"on non-IEEE platform");
return -1;
}
/* Third byte */
f |= *p << 8;
p += incr;
/* Fourth byte */
f |= *p;
x = (double)f / 8388608.0;
/* XXX This sadly ignores Inf/NaN issues */
if (e == 0)
e = -126;
else {
x += 1.0;
e -= 127;
}
x = ldexp(x, e);
if (sign)
x = -x;
return x;
} else {
float x;
if ((float_format == ieee_little_endian_format && !le) || (float_format == ieee_big_endian_format && le)) {
char buf[4];
char* d = &buf[3];
int i;
for (i = 0; i < 4; i++) {
*d-- = *p++;
}
memcpy(&x, buf, 4);
} else {
memcpy(&x, p, 4);
}
return x;
}
}
extern "C" double _PyFloat_Unpack8(const unsigned char* p, int le) noexcept {
if (double_format == unknown_format) {
unsigned char sign;
int e;
unsigned int fhi, flo;
double x;
int incr = 1;
if (le) {
p += 7;
incr = -1;
}
/* First byte */
sign = (*p >> 7) & 1;
e = (*p & 0x7F) << 4;
p += incr;
/* Second byte */
e |= (*p >> 4) & 0xF;
fhi = (*p & 0xF) << 24;
p += incr;
if (e == 2047) {
PyErr_SetString(PyExc_ValueError, "can't unpack IEEE 754 special value "
"on non-IEEE platform");
return -1.0;
}
/* Third byte */
fhi |= *p << 16;
p += incr;
/* Fourth byte */
fhi |= *p << 8;
p += incr;
/* Fifth byte */
fhi |= *p;
p += incr;
/* Sixth byte */
flo = *p << 16;
p += incr;
/* Seventh byte */
flo |= *p << 8;
p += incr;
/* Eighth byte */
flo |= *p;
x = (double)fhi + (double)flo / 16777216.0; /* 2**24 */
x /= 268435456.0; /* 2**28 */
if (e == 0)
e = -1022;
else {
x += 1.0;
e -= 1023;
}
x = ldexp(x, e);
if (sign)
x = -x;
return x;
} else {
double x;
if ((double_format == ieee_little_endian_format && !le) || (double_format == ieee_big_endian_format && le)) {
char buf[8];
char* d = &buf[7];
int i;
for (i = 0; i < 8; i++) {
*d-- = *p++;
}
memcpy(&x, buf, 8);
} else {
memcpy(&x, p, 8);
}
return x;
}
}
static PyObject* float_getnewargs(PyFloatObject* v) noexcept {
return Py_BuildValue("(d)", v->ob_fval);
}
PyDoc_STRVAR(float_getformat_doc, "float.__getformat__(typestr) -> string\n"
"\n"
"You probably don't want to use this function. It exists mainly to be\n"
"used in Python's test suite.\n"
"\n"
"typestr must be 'double' or 'float'. This function returns whichever of\n"
"'unknown', 'IEEE, big-endian' or 'IEEE, little-endian' best describes the\n"
"format of floating point numbers used by the C type named by typestr.");
PyDoc_STRVAR(float_setformat_doc, "float.__setformat__(typestr, fmt) -> None\n"
"\n"
......@@ -1670,6 +938,7 @@ static PyMethodDef float_methods[]
= { { "hex", (PyCFunction)float_hex, METH_NOARGS, NULL },
{ "fromhex", (PyCFunction)float_fromhex, METH_O | METH_CLASS, NULL },
{ "as_integer_ratio", (PyCFunction)float_as_integer_ratio, METH_NOARGS, NULL },
{ "__getformat__", (PyCFunction)float_getformat, METH_O | METH_CLASS, float_getformat_doc },
{ "__setformat__", (PyCFunction)float_setformat, METH_VARARGS | METH_CLASS, float_setformat_doc },
{ "is_integer", (PyCFunction)float_is_integer, METH_NOARGS, NULL },
{ "__format__", (PyCFunction)float__format__, METH_VARARGS, NULL },
......@@ -1743,16 +1012,13 @@ void setupFloat() {
float_cls->giveAttr("__doc__", boxString("float(x) -> floating point number\n"
"\n"
"Convert a string or number to a floating point number, if possible."));
float_cls->giveAttr("__getformat__",
new BoxedBuiltinFunctionOrMethod(FunctionMetadata::create((void*)floatGetFormat, STR, 1),
"__getformat__", floatGetFormatDoc));
add_methods(float_cls, float_methods);
add_operators(float_cls);
float_cls->freeze();
floatFormatInit();
_PyFloat_Init();
float_cls->tp_str = float_str;
float_cls->tp_as_number->nb_power = float_pow;
......
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