Why does the following zero division error occur?
>>> from uncertainties import ufloat
>>> a = ufloat((0,0))
>>> x = ufloat((0.3,0.017))
>>> a**x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/uncertainties/__init__.py", line 601, in f_with_affine_output
if arg.derivatives
File "<string>", line 1, in <lambda>
ZeroDivisionError: 0.0 cannot be raised to a negative power
>>> 0.0**x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/uncertainties/__init__.py", line 601, in f_with_affine_output
if arg.derivatives
File "<string>", line 1, in <lambda>
ValueError: math domain error
Shouldn't these both just return 0.0
?
The situation is quite subtle:
On one hand, you're right, both results should mathematically be 0.
In fact, the behavior should be the same as Python's:
>>> 0.**0.3 0.0
When the exponent has an uncertainty the result should thus be exactly 0 (no uncertainty), since the Python result is always 0.
The case
a = 0±0
is special:a**x
is 0 for positivex
, even ifx
has an uncertainty (the result is undefined for zero or negativex
values). On the other hand, ifa=0±0.1
, the value ofa**x
is undefined because one cannot take the (real) power of a negative number (anda
can be negative, if it has a non-zero uncertainty) (unless one uses complex numbers, which is not the purpose of the uncertainties package).On the other hand, the uncertainties module allows users to change the uncertainties of numbers at any time and still get correct results. This clashes with the "ideal" mathematical results above: if
a = 0±0
, then the result ofa**x
might later be undefined; reciprocally, ifa = 0±0.3
, the result should be undefined, but should somehow become 0 if the uncertainty ofa
is later changed to 0.
Technically, this all boils down to the fact that a**x
with 0 < x < 1 is defined in a = 0 but is not differentiable there: the case of a zero uncertainty should work (the function is defined), but a non-zero uncertainty must yield an error (the derivative is not defined). Both of these cases have to somehow be handled dynamically, since the uncertainties can be changed on-the-fly by the user.
This is an interesting situation, so I will think again about whether the uncertainties module can be modified in some elegant way and accomodate this issue.
PS: Starting with version 2.3.5, the uncertainties package correctly handles the cases of the question, and more generally all cases where a number with uncertainty actually has a zero uncertainty (even if the same number but with a non-zero uncertainty would give an undefined error through linear propagation of error, like in the question).
I think the ZeroDivisionError
is going to happen whenever the exponent is less than 1. The section of code that is choking is trying to take the derivative. My hazy recollection of high-school calculus tells me that the derivative of x ** y
is y * x ** (y - 1)
.
That said, I agree that it would be intuitive for your examples to evaluate to 0. Either our intuition is wrong (as bad as my calculus is, I have no idea about how real mathematicians and scientists want uncertainties to work, and the guy who wrote this package seems to know what he's doing, plus he included a lot of tests), or perhaps we are indeed right and he needs to add handling for the special case of raising zero (with zero uncertainty) to a power.
来源:https://stackoverflow.com/questions/10198753/zero-division-error-in-python-uncertainties-package