Package: rounders
RoundersTherounderspackage extends the functionality provided by Python's
built-inroundfunction. It aims to provide a more complete and consistent collection of
decimal rounding functionality than is provided by the Python core and standard
library. Specifically, it provides:Drop-in replacements forroundthat use rounding modes other than
round-ties-to-even (for example, the commonly needed round-ties-to-away).Functionality for rounding to a given number of significant figures,
rather than to a set number of places after (or before) the decimal point.General-purpose rounding functionsThere are four general-purpose rounding functions.Theroundfunction has the same signature as the built-inround, but also allows a
rounding mode to be specified. Likeround, it supports rounding to the nearest
integer in the direction of the given rounding mode, and rounding to a given number of
places while preserving the type of the input.>>>fromroundersimportround,TIES_TO_AWAY,TO_MINUS>>>round(2.5)# The default rounding mode is TIES_TO_EVEN2>>>round(2.5,mode=TIES_TO_AWAY)# round halfway cases away from zero3>>>round(2.97,1,mode=TO_MINUS)# round towards negative infinity (like floor)2.9>>>round(Decimal(-1628),-2,mode=TO_MINUS)# Decimal and Fraction types supportedDecimal('-1.7E+3')Theround_to_figuresfunction rounds to a given number of significant figures,
rather than to a given number of places before or after the decimal point.>>>fromroundersimportround_to_figures,TO_AWAY>>>round_to_figures(1.234567,3)1.23>>>round_to_figures(1234567.,3)1230000.0>>>round_to_figures(0.0001234567,3)0.000123>>>round_to_figures(0.0001234567,3,mode=TO_AWAY)# round away from zero0.000124Theround_to_intandround_to_placesfunctions provide the two pieces of
functionality thatroundcombines:round_to_introunds to a
nearby integer using the given rounding mode, whileround_to_placesalways
expects anndigitsargument and rounds to the given number of places. Theroundfunction is currently a simple wrapper aroundround_to_intandround_to_places.>>>fromroundersimportround_to_int,round_to_places,TO_PLUS>>>round_to_int(3.1415,mode=TO_PLUS)4>>>round_to_places(3.1415,2,mode=TO_PLUS)3.15There are currently thirteen different rounding modes provided, listedbelow.Functions providing alternative rounding modesThere are thirteen functions that act as drop-in replacements forround, but that
use a different rounding mode. For example, if you always want to round ties away
from zero instead of to the nearest even number, you can do this:>>>fromroundersimportround_ties_to_awayasround>>>round(4.5)5>>>round(1.25,1)1.3Or if you want a version ofmath.ceilthat accepts a number of places after the point,
you can do:>>>fromroundersimportceil>>>ceil(1.78)2>>>ceil(1.782,2)1.79>>>ceil(-1.782,2)-1.78The complete list of functions isbelowRounding modes and mode-specific rounding functionsThese are the currently supported rounding modes, along with their corresponding
mode-specific rounding functions. The functionstrunc,floorandceilare
aliases forround_to_zero,round_to_minusandround_to_plus, respectively.To-nearest rounding modesThere are six to-nearest rounding modes: these all round to the closest target value
(e.g., to the closest integer in the case ofround_to_int), and differ only in their
handling of ties.Rounding modeFunctionDescriptionTIES_TO_EVENround_ties_to_evenTies rounded to the nearest even valueTIES_TO_ODDround_ties_to_oddTies rounded to the nearest odd valueTIES_TO_AWAYround_ties_to_awayTies rounded away from zeroTIES_TO_ZEROround_ties_to_zeroTies rounded towards zeroTIES_TO_MINUSround_ties_to_minusTies rounded towards negative infinityTIES_TO_PLUSround_ties_to_plusTies rounded towards positive infinityDirected rounding modesThere are six matching directed rounding modes: for these, all values between any two
representable output values will be rounded in the same direction.Rounding modeFunctionDescriptionTO_EVENround_to_evenRound to the nearest even valueTO_ODDround_to_oddRound to the nearest odd valueTO_AWAYround_to_awayRound away from zeroTO_ZEROround_to_zeroRound towards zeroTO_MINUSround_to_minusRound towards negative infinityTO_PLUSround_to_plusRound towards positive infinityMiscellaneous rounding modesThere's one miscellaneous rounding modeTO_ZERO_05_AWAY, with corresponding functionround_to_zero_05_away.Rounding modeFunctionDescriptionTO_ZERO_05_AWAYround_to_zero_05_awaySee belowThis rounding mode matches the behaviour ofTO_ZERO,exceptin the case where
rounding towards zero would produce a final significant digit of0or5. In that
case, it matches the behaviour ofTO_AWAYinstead. Note that in the case where the
value is already rounded to the required number of digits, neitherTO_ZEROnorTO_AWAYwould change its value, and similarlyTO_ZERO_05_AWAYdoes not change
the value in this case.>>>fromroundersimportround_to_zero_05_away>>>round_to_zero_05_away(1.234,1)# behaves like `TO_ZERO`1.2>>>round_to_zero_05_away(-1.294,1)# also behaves like `TO_ZERO`-1.2>>>round_to_zero_05_away(1.534,1)# `TO_ZERO` would give 1.5, so round away1.6>>>round_to_zero_05_away(-2.088,1)# `TO_ZERO` would give -2.0, so round away-2.1>>>round_to_zero_05_away(3.5,1)# `TO_ZERO` wouldn't change the value; leave as-is3.5Notes on rounding modesSome notes on particular rounding modes:TIES_TO_EVENgoes by avariety of
names, including
"Banker's rounding", "statisticians' rounding", and "Dutch rounding". It matches
Python's default rounding mode and the IEEE 754 default rounding mode,roundTiesToEven. Many other languages also use this rounding mode by default.TIES_TO_AWAYappears to be the rounding mode most commonly taught in schools, and
the mode that users often mistakenly expectroundto use.TIES_TO_PLUSmatches the rounding mode used by JavaScript'sMath.round, and also
appears to be commonly taught. (SeeECMA-262, 13th
edn., §21.3.2.28.)TIES_TO_ZEROis used in IEEE 754's "Augmented arithmetic operations".TO_ZEROmatches the behaviour ofmath.truncTO_PLUSmatches the behaviour ofmath.ceilTO_MINUSmatches the behaviour ofmath.floorTO_ODDis interesting as a form of "round for reround", providing a way to avoid the
phenomenon ofdouble
rounding. Suppose we're
given a real numberxand a number of placesp. Letybe the result of roundingxtop + 2places using theTO_ODDrounding mode. Thenycan act as a proxy
forxwhen rounding topplaces, in the sense thatyandxwill round the
same way under any of the rounding modes defined in this module. (The binary analog
ofTO_ODDis a little more useful here - it works in the same way, but requires
only two extra bits for the intermediate value instead of two extra digits.)TO_ZERO_05_AWAYalso provides a form of "round for reround", but is more efficient
in that it only requires one extra decimal digit instead of two. Given a valuexand a number of placesp, ify = round(x, p + 1, mode=TO_ZERO_05_AWAY), thenround(x, p, mode=mode) == round(y, p, mode=mode)for any of the thirteen rounding
modes defined in this package.>>>fromroundersimport*>>>importrandom>>>x=random.uniform(-1.0,1.0)>>>y=round(x,5,mode=TO_ZERO_05_AWAY)>>>round(x,4,mode=TO_ZERO)==round(y,4,mode=TO_ZERO)True>>>round(x,4,mode=TIES_TO_ODD)==round(y,4,mode=TIES_TO_ODD)True>>>round(x,4,mode=TO_ZERO_05_AWAY)==round(y,4,mode=TO_ZERO_05_AWAY)TrueOn relationships between the rounding modes in this package and rounding modes
elsewhere:IEEE 754 defines five "rounding-direction" attributes:roundTiesToEven,roundTiesToAway,roundTowardPositive,roundTowardNegativeandroundTowardZero.
These matchTIES_TO_EVEN,TIES_TO_AWAY,TO_PLUS,TO_MINUSandTO_ZERO,
respectively. The "Augmented arithmetic operations" section of IEEE 754-2019 also
defines an attributeroundTiesToZero, corresponding toTIES_TO_ZEROin this
module.IEEE 754 rounding directionroundersrounding moderoundTiesToEvenTIES_TO_EVENroundTiesToAwayTIES_TO_AWAYroundTiesToZeroTIES_TO_ZEROroundTowardPositiveTO_PLUSroundTowardNegativeTO_MINUSroundTowardZeroTO_ZEROAs of Python 3.11, Python'sdecimalmodule defines eight
rounding options, corresponding to the rounding modes in this module as follows:decimalrounding optionroundersrounding modeROUND_CEILINGTO_PLUSROUND_DOWNTO_ZEROROUND_FLOORTO_MINUSROUND_HALF_DOWNTIES_TO_ZEROROUND_HALF_EVENTIES_TO_EVENROUND_HALF_UPTIES_TO_AWAYROUND_UPTO_AWAYROUND_05UPTO_ZERO_05_AWAYSupported numeric typesOut of the box,rounderssupports Python's built-in numeric types:int,float,decimal.Decimalandfractions.Fraction. Under the hood, it usesfunctools.singledispatchfor all type-specific operations. This should allow easy extension to new numeric
types in the future. The extension mechanism has not yet stabilised.Future directionsMajor goals for future releases:Add formatting support, including the ability to specify rounding direction in a
format specification.Finalise and document mechanisms for adding support for custom types.Improve performance ofround, especially for thefloattype, with the aid of
a C extension if necessary.Better document the pitfalls ofroundapplied to binary floats (especially for
directed rounding modes, whereroundis not idempotent).