4

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?

John Y
  • 14,123
  • 2
  • 48
  • 72
user545424
  • 15,713
  • 11
  • 56
  • 70
  • 3
    I would say you are right. Also happens on 2.6. Maybe you should report the problem to Eric Lebigot (EOL), the author of uncertainties, directly. He will welcome your feedback – joaquin Apr 17 '12 at 20:54
  • This case is correctly handled in version 2.3.5 of the [uncertainties package](https://pypi.python.org/pypi/uncertainties/)! – Eric O. Lebigot Apr 28 '13 at 09:49

2 Answers2

3

The situation is quite subtle:

  1. 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 positive x, even if x has an uncertainty (the result is undefined for zero or negative x values). On the other hand, if a=0±0.1, the value of a**x is undefined because one cannot take the (real) power of a negative number (and a can be negative, if it has a non-zero uncertainty) (unless one uses complex numbers, which is not the purpose of the uncertainties package).

  2. 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 of a**x might later be undefined; reciprocally, if a = 0±0.3, the result should be undefined, but should somehow become 0 if the uncertainty of a 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).

Eric O. Lebigot
  • 91,433
  • 48
  • 218
  • 260
0

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.

John Y
  • 14,123
  • 2
  • 48
  • 72
  • 1
    You're right about the form of the derivative, but there is nothing wrong with that when y is less than 1. You run into problems when x is negative, but I don't think it should be a problem for x >= 0. – user545424 Apr 17 '12 at 23:22
  • No, when the exponent *before taking the derivative* is less than 1, it is a problem. Because *the derivative* will then have a negative exponent, and a negative exponent is equivalent to division, so the derivative will have division by zero. – John Y Apr 18 '12 at 00:16
  • Ah, I see. He does need to evaluate the derivative df(a=0)/da, in which case this pops up. – user545424 Apr 18 '12 at 00:27
  • And, for df/dx, which will involve a log(0). Doh! All makes sense now. – user545424 Apr 18 '12 at 00:31