[New-bugs-announce] [issue31978] make it simpler to round fractions

Wolfgang Maier report at bugs.python.org
Wed Nov 8 05:13:02 EST 2017


New submission from Wolfgang Maier <wolfgang.maier at biologie.uni-freiburg.de>:

Hi,

because of floating point inaccuracies it is suboptimal to use round(int1/int2) for rounding of a fraction.
fractions.Fraction, OTOH, offers exact rounding through its implementation of __round__, but using it requires users to create a fractions.Fraction instance from two ints first.
The algorithm used by Fraction.__round__ is, essentially, the same as the one used in the pure-Python version of the datetime._divide_and_round module (which, in turn, is taken from a comment by Mark Dickinson in Objects/longobject.c).

My suggestion is to promote this algorithm to an exposed function in the fractions module (actually, it may make sense to have it in the math module instead - compare the case of the gcd function, which started out in fractions, but is now in transition to math) so that it can be used by Fraction.__round__, but also any other code.

Attached is a patch demonstrating the idea. In addition, to the above benefit, it turns out to actually speed up Fraction.__round__ substantially, when ndigits is not None because it then avoids the generation of temporary Fraction instances, and, in my hands at least, it even makes the general (ndigits=None) case slightly faster (apparently the copied datetime._divide_and_round code is more efficient than the original in Fraction.__round__).

There is one slight additional tweak in the patch: in the case of ndigits < 0, it returns an int, not a Fraction (see test_fractions modification to make it pass).
I think this is actually a mistake in the current Fraction.__round__, which already promotes the result to int in the general case. This change speeds up round to the next ndigits power of ten by ~ a factor of 5 in my hands because no new Fraction needs to be instantiated anymore.

A full PR could include having pure-Python datetime import the function from fractions instead of rolling its own, but I'd first like to hear whether you think this should go into math instead.

----------
components: Library (Lib)
files: fractions_divround.patch
keywords: patch
messages: 305817
nosy: mark.dickinson, wolma
priority: normal
severity: normal
status: open
title: make it simpler to round fractions
type: enhancement
versions: Python 3.7, Python 3.8
Added file: https://bugs.python.org/file47254/fractions_divround.patch

_______________________________________
Python tracker <report at bugs.python.org>
<https://bugs.python.org/issue31978>
_______________________________________


More information about the New-bugs-announce mailing list