Builtin Float Epsilon? (was: Re: Does python suck or I am just stupid? )

Dan Bishop danb_83 at yahoo.com
Sun Feb 23 02:18:55 EST 2003


Stephen Horne <intentionally at blank.co.uk> wrote in message news:<mkpf5v4ekln433ob1b0v464qf4nl0njj44 at 4ax.com>...
> On Sat, 22 Feb 2003 18:33:59 GMT, djw <dwelch91 at no.spam.attbi.com>
> wrote:
> 
> >sys.floatepsilon = 0.000000001 # or maybe some nice default value
> 
> Debatable - most people expect '==' to only return true if the values
> are precisely equal. I suspect an 'approximately equal' operator has
> been suggested in the past, though.
> 
> One problem is - just how close do two values need to be to count as
> equal. There is no single good answer to this - it depends on the
> context. If you are dealing with numbers that range from zero to
> several billion, you might consider 0 and 0.1 to be equal - if your
> numbers range from 0 to 0.00000001 you will probably take quite a
> different view.

Here's a class that solves this particular problem.  Every object of
this type stores its uncertainty, which is used in computations.  x ==
y returns true whenever (x-y).relativeUncertainty >= 1.

Also note that str (but not repr) limits the number of significant
digits according to the uncertainty.

The disadvantage of this approach is that all operations are more
computationally expensive.

------------------------------------------------------------------------

from __future__ import division

import math

_epsilon = 1.
while 1. + _epsilon != 1.:
   _epsilon /= 2

def _machineUncertainty(value):
   mantissa, exponent = math.frexp(value)
   return math.ldexp(_epsilon, exponent)

class Uncertain(object):
   def __init__(self, value, uncertainty=None):
      if uncertainty is None:
         uncertainty = _machineUncertainty(value)
      else:
         uncertainty = max(float(uncertainty),
_machineUncertainty(value))
      self.__v = float(value)
      self.__u = abs(uncertainty)
   value = property(lambda self: self.__v)
   uncertainty = property(lambda self: self.__u)
   relativeUncertainty = property(lambda self: abs(self.__u /
self.__v))
   def __float__(self):
      return self.__v
   def __repr__(self):
      return 'Uncertain(value=%s, uncertainty=%s)' % (`self.__v`,
`self.__u`)
   def __str__(self):
      return '%%.%dg' % self.significantDigits() % self.__v
   def __nonzero__(self):
      return self != 0
   def __pos__(self):
      return self
   def __neg__(self):
      return Uncertain(-self.__v, self.__u)
   def __abs__(self):
      return Uncertain(abs(self.__v), self.__u)
   def __add__(self, other):
      if not isinstance(other, Uncertain):
         other = Uncertain(other)
      return Uncertain(self.__v + other.__v, math.hypot(self.__u,
other.__u))
   __radd__ = __add__
   def __sub__(self, other):
      if not isinstance(other, Uncertain):
         other = Uncertain(other)
      return Uncertain(self.__v - other.__v, math.hypot(self.__u,
other.__u))
   def __rsub__(self, other):
      return Uncertain(other) - self
   def __mul__(self, other):
      if not isinstance(other, Uncertain):
         other = Uncertain(other)
      return Uncertain(self.__v * other.__v,
                       math.hypot(other.__v * self.__u, self.__v *
other.__u))
   __rmul__ = __mul__
   def __truediv__(self, other):
      if not isinstance(other, Uncertain):
         other = Uncertain(other)
      return Uncertain(self.__v / other.__v, math.hypot(self.__u /
other.__v,
                       other.__u * self.__v / other.__v ** 2))
   def __rtruediv__(self, other):
      return Uncertain(other) - self
   __div__ = __truediv__
   __rdiv__ = __rtruediv__
   def __pow__(self, other):
      if not isinstance(other, Uncertain):
         other = Uncertain(other)
      return Uncertain(self.__v ** other.__v, math.hypot(
                       self.__v ** (other.__v - 1) * other.__v *
self.__u,
                       self.__v ** other.__v * math.log(self.__v) *
other.__u))
   def __rpow__(self, other):
      return Uncertain(other) ** self
   def __cmp__(self, other):
      if not isinstance(other, Uncertain):
         other = Uncertain(other)
      diff = self - other
      if diff.__v <= diff.__u:
         return 0
      return cmp(self.__v, other.__v)
   def significantDigits(self, radix=10):
      return max(0, int(math.ceil(-math.log(self.relativeUncertainty)
/
                                            math.log(10))))




More information about the Python-list mailing list