views:

181

answers:

4

So, I'm having some precision issues in Python.

I would like to calculate functions like this:

P(x,y) = exp(-x)/(exp(-x) + exp(-y))

Where x and y might be >1000. Python's math.exp(-1000) (in 2.6 at least!) doesn't have enough floating point precision to handle this.

  1. this form looks like logistic / logit / log-odds, but it's not, right? Is there some algebraic simplification I'm missing here?
  2. I know about Decimal, but am not sure if it applies here
  3. looks like homework, but it's not, I promise!

(Also, I'm open to titles! I couldn't think of a good one for this question!)

+3  A: 

I think you are looking for the bigfloat package for arbitrary precision floating-point reliable arithmetic.

Brian R. Bondy
Good to know, but not part of standard library. Thanks for linking though!
Gregg Lind
+7  A: 

you could divide the top and bottom by exp(-x)

P(x,y) = 1/(1 + exp(x-y))
newacct
or, with less wear and tear on the poor old brain cells, multiply the top and bottom by `exp(x)` :-)
John Machin
While true, this does not solve the problem, because exp(x-y) can still have a value of (x-y) > 1000.
steveha
+1 better to use brain than muscle. @steveha: x and y are likely to be similar in order, and this would then greatly improve the situation.
kaizer.se
Thank you! I knew there was something i was missing here. Jeepers, I feel like a moron! I tried to take the log of all of it, which obviously fails.
Gregg Lind
@steveha: this solves the problem, because even in the cases of `exp(x-y)` being too big or too small it still produces the correct answer. If `x-y` is very negative, `exp(x-y)` will be too small and will evaluate to 0, and the whole expression evaluates to 1, which is correct (to the the degree representible by floats anyway). If `x-y` is very positive, `exp(x-y)` will be too big and will evaluate to infinity, and the whole expression evaluates to 0, which is also correct (to the the degree representible by floats).
newacct
@newacct: "exp(x-y) will be too big and will evaluate to infinity": true in algebra, not necessarily so in a computer language; on Windows Python 2.6. math.exp(1000) gives `OverflowError: math range error` ... you still need to do something like `delta = x - y; result = 0.0 if delta >= TOOBIG else 1/(1+math.exp(delta))` or use try/except.
John Machin
+4  A: 
P(x,y) = exp(-x)/(exp(-x) + exp(-y))

is equivalent to:

P(x,y) = 1 / (1 + exp(x-y))

Perhaps the second one works without the use of more precision.

Mark Byers
I would accept yours as well. I don't know why I just couldn't see it! Thanks!
Gregg Lind
+3  A: 
>>> import decimal
>>> decimal.Decimal(-1000).exp()
Decimal('5.075958897549456765291809480E-435')
>>> decimal.getcontext().prec = 60
>>> decimal.Decimal(-1000).exp()
Decimal('5.07595889754945676529180947957433691930559928289283736183239E-435')
J.F. Sebastian
Thank you for demonstrating how to actually use Decimal here. I didn't realize it had a 'exp' method.
Gregg Lind