Ugh, a bunch of things. @overrides. --lmodule. Chromecasts. etc...
[python_utils.git] / math_utils.py
index 2e126990fba0d7b9138f4a4b6238440aae89bb82..e0e3f6c10732b9a3ab20a251a225a0e963c362e9 100644 (file)
@@ -1,11 +1,26 @@
 #!/usr/bin/env python3
 
+import functools
 import math
 from typing import List
 from heapq import heappush, heappop
 
 
-class RunningMedian:
+class RunningMedian(object):
+    """A running median computer.
+
+    >>> median = RunningMedian()
+    >>> median.add_number(1)
+    >>> median.add_number(10)
+    >>> median.add_number(3)
+    >>> median.get_median()
+    3
+    >>> median.add_number(7)
+    >>> median.add_number(5)
+    >>> median.get_median()
+    5
+    """
+
     def __init__(self):
         self.lowers, self.highers = [], []
 
@@ -54,14 +69,69 @@ def gcd_float_sequence(lst: List[float]) -> float:
 
 
 def truncate_float(n: float, decimals: int = 2):
-    """Truncate a float to a particular number of decimals."""
+    """
+    Truncate a float to a particular number of decimals.
+
+    >>> truncate_float(3.1415927, 3)
+    3.141
+
+    """
     assert decimals > 0 and decimals < 10
     multiplier = 10 ** decimals
     return int(n * multiplier) / multiplier
 
 
+def percentage_to_multiplier(percent: float) -> float:
+    """Given a percentage (e.g. 155%), return a factor needed to scale a
+    number by that percentage.
+
+    >>> percentage_to_multiplier(155)
+    2.55
+    >>> percentage_to_multiplier(45)
+    1.45
+    >>> percentage_to_multiplier(-25)
+    0.75
+
+    """
+    multiplier = percent / 100
+    multiplier += 1.0
+    return multiplier
+
+
+def multiplier_to_percent(multiplier: float) -> float:
+    """Convert a multiplicative factor into a percent change.
+
+    >>> multiplier_to_percent(0.75)
+    -25.0
+    >>> multiplier_to_percent(1.0)
+    0.0
+    >>> multiplier_to_percent(1.99)
+    99.0
+
+    """
+    percent = multiplier
+    if percent > 0.0:
+        percent -= 1.0
+    else:
+        percent = 1.0 - percent
+    percent *= 100.0
+    return percent
+
+
[email protected]_cache(maxsize=1024, typed=True)
 def is_prime(n: int) -> bool:
-    """Returns True if n is prime and False otherwise"""
+    """
+    Returns True if n is prime and False otherwise.  Obviously(?) very slow for
+    very large input numbers.
+
+    >>> is_prime(13)
+    True
+    >>> is_prime(22)
+    False
+    >>> is_prime(51602981)
+    True
+
+    """
     if not isinstance(n, int):
         raise TypeError("argument passed to is_prime is not of 'int' type")
 
@@ -82,3 +152,8 @@ def is_prime(n: int) -> bool:
             return False
         i = i + 6
     return True
+
+
+if __name__ == '__main__':
+    import doctest
+    doctest.testmod()