Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
skirpichev wants to merge2 commits intopython:main
base:main
Choose a base branch
Loading
fromskirpichev:opt-Fraction.from_Decimal/72902

Conversation

skirpichev
Copy link
Member

@skirpichevskirpichev commentedMay 1, 2025
edited by bedevere-appbot
Loading

@skirpichev
Copy link
MemberAuthor

Benchmarkrefpatchpatch2
Fraction.from_decimal(1)15.5 us6.59 us: 2.35x faster10.4 us: 1.49x faster
Fraction.from_decimal(myint)16.3 us11.4 us: 1.43x faster10.8 us: 1.51x faster
Fraction.from_decimal(Decimal('1'))10.9 us7.94 us: 1.37x faster7.88 us: 1.38x faster
Fraction.from_float(1)7.06 us4.25 us: 1.66x faster7.68 us: 1.09x slower
Fraction.from_float(myint)8.87 us9.92 us: 1.12x slower9.36 us: 1.06x slower
Fraction.from_float(1.1)7.37 us4.68 us: 1.57x faster4.68 us: 1.58x faster
Geometric mean(ref)1.49x faster1.27x faster

Here patch2 is the current version. v1 had a hack to checkisinstance(op, (int, Integral)) instead.

# bench.pyimportpyperffromfractionsimportFractionasFfromdecimalimportDecimalasDfromnumbersimportIntegralrunner=pyperf.Runner()s='Fraction.from_decimal'f=F.from_decimalclassmyint:numerator=123denominator=1def__int__(self):return123def__repr__(self):return"myint"Integral.register(myint)forvin [1,myint(),D(1)]:r=s+'('+repr(v)+')'runner.bench_func(r,f,v)s='Fraction.from_float'f=F.from_floatforvin [1,myint(),1.1]:r=s+'('+repr(v)+')'runner.bench_func(r,f,v)
diff --git a/Lib/fractions.py b/Lib/fractions.pyindex 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

@skirpichevskirpichev changed the titlegh-72902: speedup Fraction.from_Decimal/float in typical casesgh-72902: speedup Fraction.from_decimal/float in typical casesMay 1, 2025
@skirpichev
Copy link
MemberAuthor

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.

@neonene
Copy link
Contributor

neonene commentedMay 17, 2025
edited by skirpichev
Loading

Please considerimport decimal; isinstance(dec, decimal.Decimal) as well.

This is slightly slower:

sk@note:~ $ python3.13 -m timeit -s 'import decimal;o1=decimal.Decimal(1);o2=1j' \    'isinstance(o1, decimal.Decimal)'5000000 loops, best of 5: 82.1 nsec per loopsk@note:~ $ python3.13 -m timeit -s 'import decimal;o1=decimal.Decimal(1);o2=1j' \    'isinstance(o2, decimal.Decimal)'2000000 loops, best of 5: 159 nsec per loopsk@note:~ $ python3.13 -m timeit -s 'from decimal import Decimal;o1=Decimal(1);o2=1j' \    'isinstance(o1, Decimal)'5000000 loops, best of 5: 65.5 nsec per loopsk@note:~ $ python3.13 -m timeit -s 'from decimal import Decimal;o1=Decimal(1);o2=1j' \    'isinstance(o2, Decimal)'2000000 loops, best of 5: 139 nsec per loop

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@serhiy-storchakaserhiy-storchakaAwaiting requested review from serhiy-storchaka

Assignees
No one assigned
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

2 participants
@skirpichev@neonene

[8]ページ先頭

©2009-2025 Movatter.jp