hgrecco / pint

Operate and manipulate physical quantities in Python
http://pint.readthedocs.org/
Other
2.37k stars 466 forks source link

Lack of Unit Pluralization and Decimalization of Significand (i.e.. 9.99999 instead of 10), despite Unit Conversion by Powers of 10 #1520

Closed OzborneOrteza closed 1 year ago

OzborneOrteza commented 2 years ago

When converting between units, such as:

Often, the result is the conversion of "1" to "1.0000000000000001" or "9.999999999999999". This is undesirable, as it can cause error accumulation by floating point error. These do indeed accumulate, incrementing by the smallest place (ex: 1.0000000000000001 becomes 1.0000000000000002 when converting meters to Queccameters to Ronnameters).

I am just converting units that are powers of ten- the exponent should change, not the significand. Multiplying the measurement by a number, without changing the unit, does not cause this. Smaller magnitude (so units closer to unity) seem to return to scientific notation, but the error reappears when converting back to large units.

Additionally, units do not pluralize on output or print. However, units are converted into singular form on input.

Code is attached here: default_en.txt Unit Test Issues.txt

dalito commented 2 years ago

The imprecision is a consequence of using floats and how they are represented. Pint does not do anything special. You may use decimal numbers instead. In general, avoid unnecessary back-and-forth conversion. Just convert one time (or max. twice: input & output).

Because pint supports multiple languages, babel must be installed to generate output in plural-format, see

OzborneOrteza commented 2 years ago

Forgive me for my ignorance, but it would appear neither decimals nor fractions prevent the floating-point error. I've attached my code below, this time without any custom prefixes.

Yes, I will no longer needlessly convert. But if I may- why might repeated conversion cause floating point error?

Ah, the Babel module makes sense! My bad!

OrangeChannel commented 2 years ago

Ah, full compatibility with Fraction and Decimals can be achieved by initializing the unit registry with non_int_type=decimal.Decimal etc... Change line 4 in the text you sent to ureg = UnitRegistry(non_int_type=Decimal) and that's it. You don't need to create quantities explicity with Decimal objects either once you do this, strings work too. So like ureg.Quantity('4.555 km') is sufficient enough to get a quantity who's magnitude is a Decimal('4.555').

hgrecco commented 1 year ago

As @OrangeChannel said. Feel free to reopen.