-
-
Notifications
You must be signed in to change notification settings - Fork 32k
gh-72902: speedup Fraction.from_decimal/float in typical cases #133251
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
gh-72902: speedup Fraction.from_decimal/float in typical cases #133251
Conversation
Here patch2 is the current version. v1 had a hack to check # bench.py
import pyperf
from fractions import Fraction as F
from decimal import Decimal as D
from numbers import Integral
runner = pyperf.Runner()
s = 'Fraction.from_decimal'
f = F.from_decimal
class myint:
numerator = 123
denominator = 1
def __int__(self):
return 123
def __repr__(self):
return "myint"
Integral.register(myint)
for v in [1, myint(), D(1)]:
r = s + '(' + repr(v) + ')'
runner.bench_func(r, f, v)
s = 'Fraction.from_float'
f = F.from_float
for v in [1, myint(), 1.1]:
r = s + '(' + repr(v) + ')'
runner.bench_func(r, f, v) diff --git a/Lib/fractions.py b/Lib/fractions.py
index fa722589fb..d7887af9f8 100644
--- a/Lib/fractions.py
+++ b/Lib/fractions.py
@@ -335,23 +335,23 @@ def from_float(cls, f):
Beware that Fraction.from_float(0.3) != Fraction(3, 10).
"""
- if isinstance(f, numbers.Integral):
+ if not isinstance(f, float):
+ if not isinstance(f, (int, numbers.Integral)):
+ raise TypeError("%s.from_float() only takes floats, not %r (%s)" %
+ (cls.__name__, f, type(f).__name__))
return cls(f)
- elif not isinstance(f, float):
- raise TypeError("%s.from_float() only takes floats, not %r (%s)" %
- (cls.__name__, f, type(f).__name__))
return cls._from_coprime_ints(*f.as_integer_ratio())
@classmethod
def from_decimal(cls, dec):
"""Converts a finite Decimal instance to a rational number, exactly."""
from decimal import Decimal
- if isinstance(dec, numbers.Integral):
- dec = Decimal(int(dec))
- elif not isinstance(dec, Decimal):
- raise TypeError(
- "%s.from_decimal() only takes Decimals, not %r (%s)" %
- (cls.__name__, dec, type(dec).__name__))
+ if not isinstance(dec, Decimal):
+ if not isinstance(dec, (int, numbers.Integral)):
+ raise TypeError(
+ "%s.from_decimal() only takes Decimals, not %r (%s)" %
+ (cls.__name__, dec, type(dec).__name__))
+ dec = int(dec)
return cls._from_coprime_ints(*dec.as_integer_ratio())
@classmethod |
This is a second part of improvements, cherry-picked from the issue thread. I think this is less controversial, as speedup affects main use-cases (i.e. Decimal's or float's, respectively). With v2 version we haven't speed regressions for integer case. Though, I'm not sure about using that hack. |
This is slightly slower:
|
Uh oh!
There was an error while loading. Please reload this page.