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},

`