Issue
Certain operations using PyXX unit conversions may result in inaccuracy in calculated values. For instance, $60\ mph$ is exactly $88\ ft/s$; however, PyXX generates error of approximately $1.42*10^{-14}$ in performing this calculation.
>>> import pyxx
>>> unit_converter = pyxx.units.UnitConverterSI()
>>> unit_converter.convert(60, 'mph', 'ft/s') # should return exactly 88.0
87.99999999999999
The cause is that because PyXX performs unit conversion by first converting to base units, this can sometimes lead to repeated multiplication and division operations and division by floating-point numbers that can result in calculation error due to inherent inaccuracy in floating-point calculations.
>>> import numpy as np
>>> np.array([60.0])*1609.344/3600/0.3048 - 88 # how PyXX performs the unit conversion
array([-1.42108547e-14])
>>> np.array([60.0])*5280/3600 - 88 # equivalent calculation mathematically, but better for numerical accuracy
array([0.])
While the current accuracy is acceptable for everyday calculations (e.g., converting 500 miles to kilometers) and it's possible to round answers to the desired precision, there are applications (particularly in scientific analysis) where extremely high-precision guarantees are desirable.
Possible Solutions
Unfortunately, there isn't a simple way to simplify these unit conversion expressions while still maintaining the ability for users to define arbitrary units.
- One option is to restrict unit definitions to only
pyxx.units.UnitLinear units, but this loses flexibility.
- Another alternative is to use Sympy expressions rather than
lambda functions. Symbolic math allows much higher precision, and Sympy provides functionality for evaluating floating-point expressions to very high precision.
- A third option is to leave the implementation as-is, with the understanding that floating-point arithmetic inherently introduces inaccuracy, and placing the responsibility on end users to understand the implications and make appropriate choices in their code.
The second option is arguably preferable, as one of the main priorities of PyXX in general is to be flexible (after all, it's a "utilities" package originally created to put code that was often shared by different scripts/projects in a central place). However, it would be worth investigating the performance, as performing symbolic math computation will likely incur a performance hit.
The third option is valid, but there is an argument to be made that since PyXX takes an "indirect" approach to converting units by first converting to base units, this may not be immediately intuitive to end users. Since this implementation detail is abstracted away from users, it could be argued that dealing with numerical precision should also be handled as much behind-the-scenes as possible.
Task List
Issue
Certain operations using PyXX unit conversions may result in inaccuracy in calculated values. For instance,$60\ mph$ is exactly $88\ ft/s$ ; however, PyXX generates error of approximately $1.42*10^{-14}$ in performing this calculation.
The cause is that because PyXX performs unit conversion by first converting to base units, this can sometimes lead to repeated multiplication and division operations and division by floating-point numbers that can result in calculation error due to inherent inaccuracy in floating-point calculations.
While the current accuracy is acceptable for everyday calculations (e.g., converting 500 miles to kilometers) and it's possible to round answers to the desired precision, there are applications (particularly in scientific analysis) where extremely high-precision guarantees are desirable.
Possible Solutions
Unfortunately, there isn't a simple way to simplify these unit conversion expressions while still maintaining the ability for users to define arbitrary units.
pyxx.units.UnitLinearunits, but this loses flexibility.lambdafunctions. Symbolic math allows much higher precision, and Sympy provides functionality for evaluating floating-point expressions to very high precision.The second option is arguably preferable, as one of the main priorities of PyXX in general is to be flexible (after all, it's a "utilities" package originally created to put code that was often shared by different scripts/projects in a central place). However, it would be worth investigating the performance, as performing symbolic math computation will likely incur a performance hit.
The third option is valid, but there is an argument to be made that since PyXX takes an "indirect" approach to converting units by first converting to base units, this may not be immediately intuitive to end users. Since this implementation detail is abstracted away from users, it could be argued that dealing with numerical precision should also be handled as much behind-the-scenes as possible.
Task List
lambdafunctions currently used to perform unit conversions with Sympy expressions