@@ -1161,6 +1161,163 @@ float_float(PyObject *v)
1161
1161
return v;
1162
1162
}
1163
1163
1164
+
static PyObject *
1165
+
float_as_integer_ratio(PyObject *v)
1166
+
{
1167
+
double self;
1168
+
double float_part;
1169
+
int exponent;
1170
+
int is_negative;
1171
+
const int chunk_size = 28;
1172
+
PyObject *prev;
1173
+
PyObject *py_chunk = NULL;
1174
+
PyObject *py_exponent = NULL;
1175
+
PyObject *numerator = NULL;
1176
+
PyObject *denominator = NULL;
1177
+
PyObject *result_pair = NULL;
1178
+
PyNumberMethods *long_methods;
1179
+
1180
+
#define INPLACE_UPDATE(obj, call) \
1181
+
prev = obj; \
1182
+
obj = call; \
1183
+
Py_DECREF(prev); \
1184
+
1185
+
CONVERT_TO_DOUBLE(v, self);
1186
+
1187
+
if (Py_IS_INFINITY(self)) {
1188
+
PyErr_SetString(PyExc_OverflowError,
1189
+
"Cannot pass infinity to float.as_integer_ratio.");
1190
+
return NULL;
1191
+
}
1192
+
#ifdef Py_NAN
1193
+
if (Py_IS_NAN(self)) {
1194
+
PyErr_SetString(PyExc_ValueError,
1195
+
"Cannot pass nan to float.as_integer_ratio.");
1196
+
return NULL;
1197
+
}
1198
+
#endif
1199
+
1200
+
if (self == 0) {
1201
+
numerator = PyInt_FromLong(0);
1202
+
if (numerator == NULL) goto error;
1203
+
denominator = PyInt_FromLong(1);
1204
+
if (denominator == NULL) goto error;
1205
+
result_pair = PyTuple_Pack(2, numerator, denominator);
1206
+
/* Hand ownership over to the tuple. If the tuple
1207
+
wasn't created successfully, we want to delete the
1208
+
ints anyway. */
1209
+
Py_DECREF(numerator);
1210
+
Py_DECREF(denominator);
1211
+
return result_pair;
1212
+
}
1213
+
1214
+
/* XXX: Could perhaps handle FLT_RADIX!=2 by using ilogb and
1215
+
scalbn, but those may not be in C89. */
1216
+
PyFPE_START_PROTECT("as_integer_ratio", goto error);
1217
+
float_part = frexp(self, &exponent);
1218
+
is_negative = 0;
1219
+
if (float_part < 0) {
1220
+
float_part = -float_part;
1221
+
is_negative = 1;
1222
+
/* 0.5 <= float_part < 1.0 */
1223
+
}
1224
+
PyFPE_END_PROTECT(float_part);
1225
+
/* abs(self) == float_part * 2**exponent exactly */
1226
+
1227
+
/* Suck up chunk_size bits at a time; 28 is enough so that we
1228
+
suck up all bits in 2 iterations for all known binary
1229
+
double-precision formats, and small enough to fit in a
1230
+
long. */
1231
+
numerator = PyLong_FromLong(0);
1232
+
if (numerator == NULL) goto error;
1233
+
1234
+
long_methods = PyLong_Type.tp_as_number;
1235
+
1236
+
py_chunk = PyLong_FromLong(chunk_size);
1237
+
if (py_chunk == NULL) goto error;
1238
+
1239
+
while (float_part != 0) {
1240
+
/* invariant: abs(self) ==
1241
+
(numerator + float_part) * 2**exponent exactly */
1242
+
long digit;
1243
+
PyObject *py_digit;
1244
+
1245
+
PyFPE_START_PROTECT("as_integer_ratio", goto error);
1246
+
/* Pull chunk_size bits out of float_part, into digits. */
1247
+
float_part = ldexp(float_part, chunk_size);
1248
+
digit = (long)float_part;
1249
+
float_part -= digit;
1250
+
/* 0 <= float_part < 1 */
1251
+
exponent -= chunk_size;
1252
+
PyFPE_END_PROTECT(float_part);
1253
+
1254
+
/* Shift digits into numerator. */
1255
+
// numerator <<= chunk_size
1256
+
INPLACE_UPDATE(numerator,
1257
+
long_methods->nb_lshift(numerator, py_chunk));
1258
+
if (numerator == NULL) goto error;
1259
+
1260
+
// numerator |= digit
1261
+
py_digit = PyLong_FromLong(digit);
1262
+
if (py_digit == NULL) goto error;
1263
+
INPLACE_UPDATE(numerator,
1264
+
long_methods->nb_or(numerator, py_digit));
1265
+
Py_DECREF(py_digit);
1266
+
if (numerator == NULL) goto error;
1267
+
}
1268
+
1269
+
/* Add in the sign bit. */
1270
+
if (is_negative) {
1271
+
INPLACE_UPDATE(numerator,
1272
+
long_methods->nb_negative(numerator));
1273
+
if (numerator == NULL) goto error;
1274
+
}
1275
+
1276
+
/* now self = numerator * 2**exponent exactly; fold in 2**exponent */
1277
+
denominator = PyLong_FromLong(1);
1278
+
py_exponent = PyLong_FromLong(labs(exponent));
1279
+
if (py_exponent == NULL) goto error;
1280
+
INPLACE_UPDATE(py_exponent,
1281
+
long_methods->nb_lshift(denominator, py_exponent));
1282
+
if (py_exponent == NULL) goto error;
1283
+
if (exponent > 0) {
1284
+
INPLACE_UPDATE(numerator,
1285
+
long_methods->nb_multiply(numerator,
1286
+
py_exponent));
1287
+
if (numerator == NULL) goto error;
1288
+
}
1289
+
else {
1290
+
Py_DECREF(denominator);
1291
+
denominator = py_exponent;
1292
+
py_exponent = NULL;
1293
+
}
1294
+
1295
+
result_pair = PyTuple_Pack(2, numerator, denominator);
1296
+
1297
+
#undef INPLACE_UPDATE
1298
+
error:
1299
+
Py_XDECREF(py_exponent);
1300
+
Py_XDECREF(py_chunk);
1301
+
Py_XDECREF(denominator);
1302
+
Py_XDECREF(numerator);
1303
+
return result_pair;
1304
+
}
1305
+
1306
+
PyDoc_STRVAR(float_as_integer_ratio_doc,
1307
+
"float.as_integer_ratio() -> (int, int)\n"
1308
+
"\n"
1309
+
"Returns a pair of integers, not necessarily in lowest terms, whose\n"
1310
+
"ratio is exactly equal to the original float. This method raises an\n"
1311
+
"OverflowError on infinities and a ValueError on nans. The resulting\n"
1312
+
"denominator will be positive.\n"
1313
+
"\n"
1314
+
">>> (10.0).as_integer_ratio()\n"
1315
+
"(167772160L, 16777216L)\n"
1316
+
">>> (0.0).as_integer_ratio()\n"
1317
+
"(0, 1)\n"
1318
+
">>> (-.25).as_integer_ratio()\n"
1319
+
"(-134217728L, 536870912L)");
1320
+
1164
1321
1165
1322
static PyObject *
1166
1323
float_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
@@ -1349,6 +1506,8 @@ static PyMethodDef float_methods[] = {
1349
1506
"Returns self, the complex conjugate of any float."},
1350
1507
{"__trunc__", (PyCFunction)float_trunc, METH_NOARGS,
1351
1508
"Returns the Integral closest to x between 0 and x."},
1509
+
{"as_integer_ratio", (PyCFunction)float_as_integer_ratio, METH_NOARGS,
1510
+
float_as_integer_ratio_doc},
1352
1511
{"__getnewargs__", (PyCFunction)float_getnewargs, METH_NOARGS},
1353
1512
{"__getformat__", (PyCFunction)float_getformat,
1354
1513
METH_O|METH_CLASS, float_getformat_doc},
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4