Frequently asked questions#
Why the name Pint?#
Pint is a unit and sounds like Python in the first syllable. Most important, it is a good unit for beer.
How can I avoid magnitude floating point issues?#
By default, UnitRegistry uses float for magnitudes, which is subject
to the usual floating-point rounding behavior:
>>> import pint
>>> ureg = pint.UnitRegistry()
>>> ureg("1 gallon").to("l")
Quantity(3.785411783999999, "liter")
If you need exact arithmetic instead, pass non_int_type when creating
the registry:
>>> import decimal
>>> ureg = pint.UnitRegistry(non_int_type=decimal.Decimal)
>>> ureg("1 gallon").to("l")
Quantity(Decimal('3.785411784000000000000000000'), "liter")
or, for exact fractions:
>>> import fractions
>>> ureg = pint.UnitRegistry(non_int_type=fractions.Fraction)
This avoids floating-point noise entirely (no rounding to begin with), at
the cost of some performance compared to plain float.
How can I avoid exponent floating point issues?#
Combining quantities raised to fractional powers (e.g. multiplying and
dividing several quantities each raised to a different fractional exponent)
can leave a tiny floating-point residual on an exponent that should be an
exact integer or zero, instead of the number of a whole quantity you might
expect, e.g. meter ** 0.9999999999999998 instead of exactly meter ** 1.
Converting the quantity with Quantity.to(), Quantity.to_base_units(),
or Quantity.to_reduced_units() recomputes the units against the
requested target and resolves this: the result has exactly the units you
asked for, with no leftover noise.
Note
Formatters may round the displayed exponent, hiding the issue rather than
fixing it: meter ** 0.9999999999999998 still prints as
meter ** 1, even though the stored exponent is not exactly 1.
Using Fraction or int avoids this noise. Ten multiplications by
meter ** 0.1 don’t quite add up to exactly meter ** 1; ten
multiplications by meter ** Fraction(1, 10) do:
>>> u = ureg.Unit("meter") ** 0.1
>>> for _ in range(9):
... u = u * ureg.Unit("meter") ** 0.1
>>> u == ureg.Unit("meter")
False
>>> import fractions
>>> ureg2 = pint.UnitRegistry(non_int_type=fractions.Fraction)
>>> u3 = ureg2.Unit("meter") ** fractions.Fraction(1, 10)
>>> for _ in range(9):
... u3 = u3 * ureg2.Unit("meter") ** fractions.Fraction(1, 10)
>>> u3 == ureg2.Unit("meter")
True
This comes at a performance cost (roughly 25% slower than plain float
for typical arithmetic), and it only stays exact as long as every exponent
is exact: combining an exact Fraction exponent with an ordinary
float exponent on the same unit produces a float result, the same
noise-prone type this is meant to avoid:
>>> Q_ = ureg2.Quantity
>>> a = Q_(1, ureg2.m ** fractions.Fraction(8, 10))
>>> b = Q_(1, ureg2.m ** 0.5)
>>> c = a * b
>>> c.units._units["meter"]
1.3
>>> type(c.units._units["meter"])
<class 'float'>
You mention other similar Python libraries. Can you point me to those?#
If you’re aware of another one, please contribute a patch to the docs.