Moved Rational._binary_float_to_ratio() to float.as_integer_ratio() b… · python/cpython@3ea7b41 (original) (raw)
`@@ -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 * 2exponent exactly; fold in 2exponent */
`
``
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},
`