Created
April 8, 2014 18:03
-
-
Save speezepearson/10164343 to your computer and use it in GitHub Desktop.
Stores floating-point numbers in log-space (intended for probability calculations).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| from math import log, exp | |
| from functools import total_ordering | |
| @total_ordering | |
| class LogFloat(object): | |
| """Represents a positive real number in log-space to avoid underflow.""" | |
| def __init__(self, normal=None, log_space=None): | |
| if not ((normal is not None) ^ (log_space is not None)): | |
| raise ValueError("must specify normal-space XOR log-space value") | |
| self.logval = log(normal) if normal is not None else log_space | |
| def __repr__(self): | |
| return "LogFloat(log_space={!r})".format(self.logval) | |
| def __str__(self): | |
| return repr(self) | |
| def __float__(self): | |
| return float(exp(self.logval)) | |
| def __int__(self): | |
| return int(float(self)) | |
| def __div__(self, other): | |
| if isinstance(other, LogFloat): | |
| return LogFloat(log_space=self.logval - other.logval) | |
| result = float(self) / other | |
| return LogFloat(result) if result>0 else result | |
| def __rdiv__(self, other): | |
| return LogFloat(other / float(self)) | |
| def __mul__(self, other): | |
| if isinstance(other, LogFloat): | |
| return LogFloat(log_space=self.logval + other.logval) | |
| result = float(self) * other | |
| return LogFloat(result) if result>0 else result | |
| def __rmul__(self, other): | |
| return self.__mul__(other) | |
| def __pow__(self, power): | |
| return LogFloat(log_space=self.logval * power) | |
| def __rpow__(self, base): | |
| return base ** exp(self.logval) | |
| def __add__(self, other): | |
| result = float(self) + other | |
| return LogFloat(result) if result>0 else result | |
| def __radd__(self, other): | |
| result = other + float(self) | |
| return LogFloat(result) if result>0 else result | |
| def __sub__(self, other): | |
| result = float(self) - other | |
| return LogFloat(result) if result>0 else result | |
| def __rsub__(self, other): | |
| result = other - float(self) | |
| return LogFloat(result) if result>0 else result | |
| def __lt__(self, other): | |
| if isinstance(other, LogFloat): | |
| return self.logval < other.logval | |
| return exp(self.logval) < other | |
| def __eq__(self, other): | |
| if isinstance(other, LogFloat): | |
| return self.logval == other.logval | |
| return exp(self.logval) == other | |
| def __abs__(self): | |
| return self |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment