1 / 13

Floating point numbers in Python

Floating point numbers in Python. Floats in Python are platform dependent, but usually equivalent to an IEEE754 64-bit C “double” . (-1) sign · (1. b -1 · b -2 · b -3 ... b -52 )·2 (ex-1023). As a practical matter, the smallest float is usually on the order of ~ 2.225 x 10 -308.

lamont
Télécharger la présentation

Floating point numbers in Python

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Floating point numbers in Python Floats in Python are platform dependent, but usually equivalent to an IEEE754 64-bit C “double” (-1)sign ·(1.b-1·b-2·b-3...b-52)·2(ex-1023) As a practical matter, the smallest float is usually on the order of ~ 2.225 x 10-308 However, because the significand is also finite, we start having issues with precision significantly earlier….

  2. A numerically stable numeric class Developing the log_float numeric class The idea is to define a class, log_floatthat we can use as if its objects were regular python floats, even though stored values are represented internally in log space, and all of the arithmetic operations that we will need (multiplication, division and addition) are also defined in such a way that they also take place in log space. We should be able to write: or… A = log_float(2) B = log_float(3) C = 2.1 * (A + B) print C #result is 10.2 A = log_float(2) C = A * 2 print C # result is 4 We should be able to freely mix log_floats, floats, and ints

  3. Special Method Attributes Handling zero values in log space is a nuisance We’ll adopt the convention of internally representing values as “extended logarithms” where zero valued reals are handled as a special case. if value: ## for positive reals self.value = math.log(value) else: ## for value was zero self.value = LOGZERO We’ll use the built-in None object to represent LOGZERO

  4. Special Method Attributes These are methods used internally by python that are usually not directly invoked. They are called automatically when needed def __init__(self): pass The class constructor method __init__ is an example of a special method attribute you are already familiar with def __str__(self): return “This is how my object should print” The class method __str__ allows you to specify how an instance should print itself when the print funciton is invoked We will use SMAs to simulate a numeric class

  5. Special Method Attributes These are the special methods we will minimally need to define for our numerically stable log_float class: __init__(self, value, mode = None): __str__(self): __mul__(self,other): __rmul__(self,other): __add__(self,other): __div__(self,other): __rdiv__(self,other): Some hints as to how each must behave…

  6. “log_float” Special Method Attributes __init__(self, value, mode = None) Unless mode = True, this function should accept as its first argument a floating point real-space number provided by the user. This number will be then log transformed and stored in an instance variable self.value. In the special case where value is zero, self.valueshould be set to LOGZERO (or None) The only time that the mode flag will be set is when the constructor has been called not by the user, but instead by an arithmetic operation involving another log_floatobject. If this is the case, the value being passed in is already in log space, so the self.value variable should just be set to value. We should also make sure that user-specified reals are positive

  7. “log_float” Special Method Attributes __str__(self): This might print a message indicating something about both the internal state of the object and the way that the value would be publically viewed.. So for instance ifself.value is None,it might return“Public value is 0, internal value is None” If self.value is defined, it should return a message indicating that self.value itself is the internal value, and the exponent to e of self.value as the public value. Natural log values can converted back to reals with math.exp()

  8. “log_float” Special Method Attributes __mul__(self,other): self and other refer to the operands on the left hand and right hand side of the multiplication operator. These can in principle be of any type Multiplication is easy if both self and other are log_float objects. Since self.value and other.value should both be in log space, you can just return the sum of these values. But you’ll also need to handle the special cases where one or the other object (or both) has a value variable set to None!!! In all cases you should return an object of type log_floatso that the result of the operation is, itself, a log_float. And the values you are returning are already in log space, so you should make sure to set the mode flag of the initializer. i.e. return log_float(self.value + other.value, True)

  9. “log_float” Special Method Attributes __mul__(self,other): What about the special case where the other object isn’t a log_float? This is easiest to handle with a try/except block. If you try to refer to or evaluate the other.value attribute and it turns out not to exist it will throw an AttributeError: try: if self.value is None or other.value is None: ## do some stuff except AttributeError: # do something to handle the fact that “other“ # isn’t a log_float. Just assume it’s a float or # int, then log transform it and carry on

  10. “log_float” Special Method Attributes __add__(self,other): Log-space addition is a minor PITA. We adopt the procedure suggested by Tobias Mann ln(x+y) = ln(x) + ln(X+Y) – ln (x) = ln(x) + ln(x+y) = ln(x) + ln(1+y) x x = ln(x) + ln(1 + eln(y/x)) = ln(x) + ln(1 + eln(y)-ln(x)) x and y have now been forced into a form compatible with our prior log transform. (order matters, as stability demands we keep the exponential term small)

  11. “log_float” Special Method Attributes __add__(self,other): Log-space addition is a minor PITA. We adopt the procedure suggested by Tobias Mann • Again, we need to consider several “edge cases”: • self.value or other.valueisLOGZERO • other is a float or int type so evaluating other.value throws an attribute error • A combination of the above scenarios Be careful when making comparisons to None. For instance, try evaluating: -999 < None Testing for None should be “if X is None”, never “if X == None”

  12. “log_float” Special Method Attributes __div__(self,other): Division has similar edge cases as most of the other operations, but in addition we need to handle attempts to divide by zero. For instance, this would occur if other.value = LOGZERO. We can raise our own exception to handle this: if other.value is LOGZERO: raise ZeroDivisionError You should also define a __truediv__ method that simply returns a call to your __div__ method. __truediv__ is invoked instead of __div__ if you have used from __future__import division

  13. “log_float” Special Method Attributes __cmp__(self,other): __cmp__ is invoked by the comparison operators >, >=, ==, <=, < , or implicitly during operations like sorts. Generally, it should return -1 if object self is “less” than object other, 0 if object self is “equal” to object other, and 1 if object self is greater than object other. Another (preferred actually, but more work) option is to individually define each of the separate “rich comparison operator” methods, such as __lt__, __eq__, __gt__etc. It is critical here to remember that LOGZERO is an identity with None, and will NOT evaluate as less than a negative number. You will need to be especially careful here with all the edge cases.

More Related