|
20 | 20 |
|
21 | 21 | __all__ = ["s", "imathify", "gmathify", |
22 | 22 | "m", "mg", # old names, pre-0.14.3, will go away in 0.15.0 |
23 | | - "almosteq", |
24 | 23 | "sadd", "ssub", "sabs", "spos", "sneg", "sinvert", "smul", "spow", |
25 | 24 | "struediv", "sfloordiv", "smod", "sdivmod", |
26 | 25 | "sround", "strunc", "sfloor", "sceil", |
|
45 | 44 |
|
46 | 45 | from .it import take, rev, window |
47 | 46 | from .gmemo import imemoize, gmemoize |
| 47 | +from .numutil import almosteq |
48 | 48 |
|
49 | 49 | class _NoSuchType: |
50 | 50 | pass |
51 | 51 |
|
52 | 52 | # stuff to support float, mpf and SymPy expressions transparently |
53 | 53 | # |
54 | | -from sys import float_info |
55 | 54 | from math import log as math_log, copysign, trunc, floor, ceil |
56 | 55 | try: |
57 | 56 | from mpmath import mpf, almosteq as mpf_almosteq |
@@ -98,44 +97,6 @@ def sign(x): |
98 | 97 | sign = _numsign |
99 | 98 | _symExpr = _NoSuchType |
100 | 99 |
|
101 | | -# TODO: Overhaul `almosteq` in v0.15.0, should work like mpf for consistency. |
102 | | -# TODO: Also move it to `unpythonic.misc`, where `ulp` already is. Or make a `numutil`. |
103 | | -def almosteq(a, b, tol=1e-8): |
104 | | - """Almost-equality that supports several formats. |
105 | | -
|
106 | | - The tolerance ``tol`` is used for the builtin ``float`` and ``mpmath.mpf``. |
107 | | -
|
108 | | - For ``mpmath.mpf``, we just delegate to ``mpmath.almosteq``, with the given |
109 | | - ``tol``. For ``float``, we use the strategy suggested in: |
110 | | -
|
111 | | - https://floating-point-gui.de/errors/comparison/ |
112 | | -
|
113 | | - Anything else, for example SymPy expressions, strings, and containers |
114 | | - (regardless of content), is tested for exact equality. |
115 | | -
|
116 | | - **CAUTION**: Although placed in ``unpythonic.mathseq``, this function |
117 | | - **does not** support iterables; rather, it is a low-level tool that is |
118 | | - exposed in the public API in the hope it may be useful elsewhere. |
119 | | - """ |
120 | | - if a == b: # infinities and such, plus any non-float type |
121 | | - return True |
122 | | - |
123 | | - if isinstance(a, mpf) and isinstance(b, mpf): |
124 | | - return mpf_almosteq(a, b, tol) |
125 | | - # compare as native float if only one is an mpf |
126 | | - elif isinstance(a, mpf) and isinstance(b, (float, int)): |
127 | | - a = float(a) |
128 | | - elif isinstance(a, (float, int)) and isinstance(b, mpf): |
129 | | - b = float(b) |
130 | | - |
131 | | - if not all(isinstance(x, (float, int)) for x in (a, b)): |
132 | | - return False # non-float type, already determined that a != b |
133 | | - min_normal = float_info.min |
134 | | - max_float = float_info.max |
135 | | - d = abs(a - b) |
136 | | - if a == 0 or b == 0 or d < min_normal: |
137 | | - return d < tol * min_normal |
138 | | - return d / min(abs(a) + abs(b), max_float) < tol |
139 | 100 |
|
140 | 101 | def s(*spec): |
141 | 102 | """Create a lazy mathematical sequence. |
|
0 commit comments