[pypy-commit] pypy default: (timfel, cfbolz) move float_as_integer_ratio into rlib and add test, because Ruby needs it, too
timfel
noreply at buildbot.pypy.org
Wed Feb 20 13:06:34 CET 2013
Author: Tim Felgentreff <timfelgentreff at gmail.com>
Branch:
Changeset: r61493:67e7e4a54f22
Date: 2013-02-20 12:56 +0100
http://bitbucket.org/pypy/pypy/changeset/67e7e4a54f22/
Log: (timfel, cfbolz) move float_as_integer_ratio into rlib and add test,
because Ruby needs it, too
diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py
--- a/pypy/objspace/std/floatobject.py
+++ b/pypy/objspace/std/floatobject.py
@@ -10,7 +10,7 @@
from rpython.rlib.rarithmetic import ovfcheck_float_to_int, intmask, LONG_BIT
from rpython.rlib.rfloat import (
isinf, isnan, isfinite, INFINITY, NAN, copysign, formatd,
- DTSF_ADD_DOT_0, DTSF_STR_PRECISION)
+ DTSF_ADD_DOT_0, DTSF_STR_PRECISION, float_as_rbigint_ratio)
from rpython.rlib.rbigint import rbigint
from rpython.rlib import rfloat
from rpython.tool.sourcetools import func_with_new_name
@@ -553,27 +553,18 @@
def float_as_integer_ratio__Float(space, w_float):
value = w_float.floatval
- if isinf(value):
+ try:
+ num, den = float_as_rbigint_ratio(value)
+ except OverflowError:
w_msg = space.wrap("cannot pass infinity to as_integer_ratio()")
raise OperationError(space.w_OverflowError, w_msg)
- elif isnan(value):
+ except ValueError:
w_msg = space.wrap("cannot pass nan to as_integer_ratio()")
raise OperationError(space.w_ValueError, w_msg)
- float_part, exp = math.frexp(value)
- for i in range(300):
- if float_part == math.floor(float_part):
- break
- float_part *= 2.0
- exp -= 1
- w_num = W_LongObject.fromfloat(space, float_part)
- w_den = space.newlong(1)
- w_exp = space.newlong(abs(exp))
- w_exp = space.lshift(w_den, w_exp)
- if exp > 0:
- w_num = space.mul(w_num, w_exp)
- else:
- w_den = w_exp
- # Try to return int.
+
+ w_num = space.newlong_from_rbigint(num)
+ w_den = space.newlong_from_rbigint(den)
+ # Try to return int
return space.newtuple([space.int(w_num), space.int(w_den)])
def float_is_integer__Float(space, w_float):
diff --git a/rpython/rlib/rfloat.py b/rpython/rlib/rfloat.py
--- a/rpython/rlib/rfloat.py
+++ b/rpython/rlib/rfloat.py
@@ -419,3 +419,25 @@
def isfinite(x):
"NOT_RPYTHON"
return not isinf(x) and not isnan(x)
+
+def float_as_rbigint_ratio(value):
+ from rpython.rlib.rbigint import rbigint
+
+ if isinf(value):
+ raise OverflowError("cannot pass infinity to as_integer_ratio()")
+ elif isnan(value):
+ raise ValueError("cannot pass nan to as_integer_ratio()")
+ float_part, exp_int = math.frexp(value)
+ for i in range(300):
+ if float_part == math.floor(float_part):
+ break
+ float_part *= 2.0
+ exp_int -= 1
+ num = rbigint.fromfloat(float_part)
+ den = rbigint.fromint(1)
+ exp = den.lshift(abs(exp_int))
+ if exp_int > 0:
+ num = num.mul(exp)
+ else:
+ den = exp
+ return num, den
diff --git a/rpython/rlib/test/test_rfloat.py b/rpython/rlib/test/test_rfloat.py
new file mode 100644
--- /dev/null
+++ b/rpython/rlib/test/test_rfloat.py
@@ -0,0 +1,23 @@
+import sys, py
+
+from rpython.rlib.rfloat import float_as_rbigint_ratio
+from rpython.rlib.rbigint import rbigint
+
+
+def test_float_as_rbigint_ratio():
+ for f, ratio in [
+ (0.875, (7, 8)),
+ (-0.875, (-7, 8)),
+ (0.0, (0, 1)),
+ (11.5, (23, 2)),
+ ]:
+ num, den = float_as_rbigint_ratio(f)
+ assert num.eq(rbigint.fromint(ratio[0]))
+ assert den.eq(rbigint.fromint(ratio[1]))
+
+ with py.test.raises(OverflowError):
+ float_as_rbigint_ratio(float('inf'))
+ with py.test.raises(OverflowError):
+ float_as_rbigint_ratio(float('-inf'))
+ with py.test.raises(ValueError):
+ float_as_rbigint_ratio(float('nan'))
More information about the pypy-commit
mailing list