pygeodesy 24.9.9__py2.py3-none-any.whl → 24.9.29__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {PyGeodesy-24.9.9.dist-info → PyGeodesy-24.9.29.dist-info}/METADATA +7 -7
- {PyGeodesy-24.9.9.dist-info → PyGeodesy-24.9.29.dist-info}/RECORD +24 -24
- pygeodesy/__init__.py +7 -5
- pygeodesy/basics.py +11 -12
- pygeodesy/booleans.py +6 -7
- pygeodesy/clipy.py +7 -7
- pygeodesy/constants.py +21 -7
- pygeodesy/deprecated/__init__.py +1 -1
- pygeodesy/deprecated/functions.py +9 -1
- pygeodesy/ellipsoidalBaseDI.py +4 -4
- pygeodesy/errors.py +40 -5
- pygeodesy/fmath.py +43 -21
- pygeodesy/formy.py +2 -1
- pygeodesy/fstats.py +10 -14
- pygeodesy/fsums.py +819 -511
- pygeodesy/karney.py +1 -5
- pygeodesy/lazily.py +6 -6
- pygeodesy/points.py +3 -3
- pygeodesy/resections.py +2 -2
- pygeodesy/sphericalNvector.py +4 -4
- pygeodesy/sphericalTrigonometry.py +2 -2
- pygeodesy/streprs.py +14 -7
- {PyGeodesy-24.9.9.dist-info → PyGeodesy-24.9.29.dist-info}/WHEEL +0 -0
- {PyGeodesy-24.9.9.dist-info → PyGeodesy-24.9.29.dist-info}/top_level.txt +0 -0
pygeodesy/fsums.py
CHANGED
|
@@ -1,29 +1,40 @@
|
|
|
1
1
|
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
3
|
|
|
4
|
-
u'''Class L{Fsum} for precision floating point summation
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
C{
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
C{
|
|
21
|
-
|
|
22
|
-
Set env variable C{PYGEODESY_FSUM_RESIDUAL} to a C{float} string greater than
|
|
23
|
-
C{"0.0"} as the threshold to throw a L{ResidualError} for a division, power or
|
|
24
|
-
root operation of an L{Fsum} instance with a C{residual} I{ratio} exceeding
|
|
4
|
+
u'''Class L{Fsum} for precision floating point summation similar to
|
|
5
|
+
Python's C{math.fsum} enhanced with I{running} summation and as an
|
|
6
|
+
option, accurate I{TwoProduct} multiplication.
|
|
7
|
+
|
|
8
|
+
Accurate multiplication is based on the C{math.fma} function for
|
|
9
|
+
Python 3.13 and newer or one of two equivalent C{fma} implementations
|
|
10
|
+
for Python 3.12 and older. To enable accurate multiplication, set
|
|
11
|
+
env variable C{PYGEODESY_FSUM_F2PRODUCT} to C{"std"} or any non-empty
|
|
12
|
+
string or invoke function C{pygeodesy.f2product(True)} or set. With
|
|
13
|
+
C{"std"} the C{fma} implemention follows the C{math.fma} function,
|
|
14
|
+
otherwise the C{PyGeodesy 24.09.09} release.
|
|
15
|
+
|
|
16
|
+
Generally, an L{Fsum} instance is considered a C{float} plus a small or
|
|
17
|
+
zero C{residue} aka C{residual} value, see property L{Fsum.residual}.
|
|
18
|
+
|
|
19
|
+
Set env variable C{PYGEODESY_FSUM_RESIDUAL} to a C{float} string greater
|
|
20
|
+
than C{"0.0"} as the threshold to throw a L{ResidualError} for a division,
|
|
21
|
+
power or root operation of an L{Fsum} with a C{residual} I{ratio} exceeding
|
|
25
22
|
the threshold. See methods L{Fsum.RESIDUAL}, L{Fsum.pow}, L{Fsum.__ipow__}
|
|
26
23
|
and L{Fsum.__itruediv__}.
|
|
24
|
+
|
|
25
|
+
There are several C{integer} L{Fsum} cases, for example the result from
|
|
26
|
+
functions C{ceil}, C{floor}, C{Fsum.__floordiv__} and methods L{Fsum.fint},
|
|
27
|
+
L{Fsum.fint2} and L{Fsum.is_integer}. Also, L{Fsum} methods L{Fsum.pow},
|
|
28
|
+
L{Fsum.__ipow__}, L{Fsum.__pow__} and L{Fsum.__rpow__} return a (very long)
|
|
29
|
+
C{int} if invoked with optional argument C{mod} set to C{None}. The
|
|
30
|
+
C{residual} of an C{integer} L{Fsum} is between C{-1.0} and C{+1.0} and
|
|
31
|
+
will be C{INT0} if that is considered to be I{exact}.
|
|
32
|
+
|
|
33
|
+
Set env variable C{PYGEODESY_FSUM_NONFINITES} to C{"std"} or use function
|
|
34
|
+
C{pygeodesy.nonfiniterrors(False)} to allow I{non-finite} C{float}s like
|
|
35
|
+
C{inf}, C{INF}, C{NINF}, C{nan} and C{NAN} and to ignore C{OverflowError}
|
|
36
|
+
respectively C{ValueError} exceptions. However, in that case I{non-finite}
|
|
37
|
+
results may differ from Python's C{math.fsum} results.
|
|
27
38
|
'''
|
|
28
39
|
# make sure int/int division yields float quotient, see .basics
|
|
29
40
|
from __future__ import division as _; del _ # PYCHOK semicolon
|
|
@@ -31,197 +42,233 @@ from __future__ import division as _; del _ # PYCHOK semicolon
|
|
|
31
42
|
from pygeodesy.basics import isbool, iscomplex, isint, isscalar, \
|
|
32
43
|
_signOf, itemsorted, signOf, _xiterable, \
|
|
33
44
|
_xiterablen
|
|
34
|
-
from pygeodesy.constants import
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
45
|
+
from pygeodesy.constants import INF, INT0, MANT_DIG, NEG0, NINF, _0_0, \
|
|
46
|
+
_1_0, _N_1_0, _isfinite, _pos_self, \
|
|
47
|
+
Float, Int
|
|
48
|
+
from pygeodesy.errors import _AssertionError, _OverflowError, _TypeError, \
|
|
49
|
+
_ValueError, _xError, _xError2, _xkwds_get, \
|
|
50
|
+
_xkwds, _xkwds_get1, _xkwds_not, _xkwds_pop, \
|
|
51
|
+
_xsError
|
|
39
52
|
from pygeodesy.internals import _enquote, _passarg
|
|
40
|
-
from pygeodesy.interns import NN, _arg_, _COMMASPACE_,
|
|
41
|
-
|
|
42
|
-
_not_finite_, _PERCENT_, _PLUS_, \
|
|
43
|
-
_RANGLE_, _SLASH_, _SPACE_, _STAR_, _UNDER_
|
|
53
|
+
from pygeodesy.interns import NN, _arg_, _COMMASPACE_, _DOT_, _from_, \
|
|
54
|
+
_not_finite_, _SPACE_, _std_, _UNDER_
|
|
44
55
|
from pygeodesy.lazily import _ALL_LAZY, _getenv, _sys_version_info2
|
|
45
56
|
from pygeodesy.named import _name__, _name2__, _Named, _NamedTuple, \
|
|
46
57
|
_NotImplemented
|
|
47
|
-
from pygeodesy.props import _allPropertiesOf_n,
|
|
48
|
-
|
|
58
|
+
from pygeodesy.props import _allPropertiesOf_n, deprecated_method, \
|
|
59
|
+
deprecated_property_RO, Property, \
|
|
60
|
+
Property_RO, property_RO
|
|
49
61
|
from pygeodesy.streprs import Fmt, fstr, unstr
|
|
50
62
|
# from pygeodesy.units import Float, Int # from .constants
|
|
51
63
|
|
|
52
|
-
from math import
|
|
64
|
+
from math import fabs, isinf, isnan, \
|
|
65
|
+
ceil as _ceil, floor as _floor # PYCHOK used! .ltp
|
|
53
66
|
|
|
54
67
|
__all__ = _ALL_LAZY.fsums
|
|
55
|
-
__version__ = '24.09.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
68
|
+
__version__ = '24.09.29'
|
|
69
|
+
|
|
70
|
+
from pygeodesy.interns import (
|
|
71
|
+
_PLUS_ as _add_op_, # in .auxilats.auxAngle
|
|
72
|
+
_EQUAL_ as _fset_op_,
|
|
73
|
+
_RANGLE_ as _gt_op_,
|
|
74
|
+
_LANGLE_ as _lt_op_,
|
|
75
|
+
_PERCENT_ as _mod_op_,
|
|
76
|
+
_STAR_ as _mul_op_,
|
|
77
|
+
_NOTEQUAL_ as _ne_op_,
|
|
78
|
+
_DASH_ as _sub_op_, # in .auxilats.auxAngle
|
|
79
|
+
_SLASH_ as _truediv_op_
|
|
80
|
+
)
|
|
81
|
+
_eq_op_ = _fset_op_ * 2 # _DEQUAL_
|
|
82
|
+
_floordiv_op_ = _truediv_op_ * 2 # _DSLASH_
|
|
83
|
+
_divmod_op_ = _floordiv_op_ + _mod_op_
|
|
84
|
+
_F2PRODUCT = _getenv('PYGEODESY_FSUM_F2PRODUCT', NN)
|
|
85
|
+
_ge_op_ = _gt_op_ + _fset_op_
|
|
86
|
+
_iadd_op_ = _add_op_ + _fset_op_ # in .auxilats.auxAngle, .fstats
|
|
65
87
|
_integer_ = 'integer'
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
_mul_op_ = _STAR_
|
|
71
|
-
_ne_op_ = _NOTEQUAL_
|
|
88
|
+
_isub_op_ = _sub_op_ + _fset_op_ # in .auxilats.auxAngle
|
|
89
|
+
_le_op_ = _lt_op_ + _fset_op_
|
|
90
|
+
_NONFINITEr = _0_0
|
|
91
|
+
_NONFINITES = _getenv('PYGEODESY_FSUM_NONFINITES', NN)
|
|
72
92
|
_non_zero_ = 'non-zero'
|
|
73
|
-
_pow_op_ =
|
|
93
|
+
_pow_op_ = _mul_op_ * 2 # _DSTAR_
|
|
94
|
+
_RESIDUAL_0_0 = _getenv('PYGEODESY_FSUM_RESIDUAL', _0_0)
|
|
74
95
|
_significant_ = 'significant'
|
|
75
|
-
_sub_op_ = _DASH_ # in .auxilats.auxAngle
|
|
76
96
|
_threshold_ = 'threshold'
|
|
77
|
-
_truediv_op_ = _SLASH_
|
|
78
|
-
_divmod_op_ = _floordiv_op_ + _mod_op_
|
|
79
|
-
_isub_op_ = _sub_op_ + _fset_op_ # in .auxilats.auxAngle
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def _2delta(*ab):
|
|
83
|
-
'''(INTERNAL) Helper for C{Fsum._fsum2}.
|
|
84
|
-
'''
|
|
85
|
-
try:
|
|
86
|
-
a, b = _2sum(*ab)
|
|
87
|
-
except _OverflowError:
|
|
88
|
-
a, b = ab
|
|
89
|
-
return float(a if fabs(a) > fabs(b) else b)
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
def _2error(unused): # in .fstats
|
|
93
|
-
'''(INTERNAL) Throw a C{not-finite} exception.
|
|
94
|
-
'''
|
|
95
|
-
raise ValueError(_not_finite_)
|
|
96
97
|
|
|
97
98
|
|
|
98
|
-
def _2finite(x):
|
|
99
|
+
def _2finite(x): # in .fstats
|
|
99
100
|
'''(INTERNAL) return C{float(x)} if finite.
|
|
100
101
|
'''
|
|
101
|
-
x
|
|
102
|
-
|
|
102
|
+
return (float(x) if _isfinite(x) # and isscalar(x)
|
|
103
|
+
else _nfError(x))
|
|
103
104
|
|
|
104
105
|
|
|
105
|
-
def _2float(index=None, **
|
|
106
|
-
'''(INTERNAL) Raise C{TypeError} or C{ValueError} if not
|
|
106
|
+
def _2float(index=None, _isfine=_isfinite, **name_x): # in .fmath, .fstats
|
|
107
|
+
'''(INTERNAL) Raise C{TypeError} or C{Overflow-/ValueError} if not finite.
|
|
107
108
|
'''
|
|
108
|
-
n,
|
|
109
|
+
n, x = name_x.popitem() # _xkwds_item2(name_x)
|
|
109
110
|
try:
|
|
110
|
-
|
|
111
|
+
f = float(x)
|
|
112
|
+
return f if _isfine(f) else _nfError(x)
|
|
111
113
|
except Exception as X:
|
|
112
|
-
raise _xError(X, Fmt.INDEX(n, index),
|
|
114
|
+
raise _xError(X, Fmt.INDEX(n, index), x)
|
|
113
115
|
|
|
114
116
|
|
|
115
117
|
def _X_ps(X): # for _2floats only
|
|
116
118
|
return X._ps
|
|
117
119
|
|
|
118
120
|
|
|
119
|
-
def _2floats(xs, origin=0, _X=_X_ps, _x=float):
|
|
121
|
+
def _2floats(xs, origin=0, _X=_X_ps, _x=float, _isfine=_isfinite):
|
|
120
122
|
'''(INTERNAL) Yield each B{C{xs}} as a C{float}.
|
|
121
123
|
'''
|
|
122
124
|
try:
|
|
123
|
-
i, x = origin,
|
|
124
|
-
|
|
125
|
-
_FsT = _Fsum_Fsum2Tuple_types
|
|
126
|
-
_isa = isinstance
|
|
125
|
+
i, x = origin, xs
|
|
126
|
+
_FsT = _Fsum_2Tuple_types
|
|
127
127
|
for x in _xiterable(xs):
|
|
128
|
-
if
|
|
128
|
+
if isinstance(x, _FsT):
|
|
129
129
|
for p in _X(x._Fsum):
|
|
130
130
|
yield p
|
|
131
131
|
else:
|
|
132
132
|
f = _x(x)
|
|
133
|
-
yield f if
|
|
133
|
+
yield f if _isfine(f) else _nfError(f)
|
|
134
134
|
i += 1
|
|
135
135
|
except Exception as X:
|
|
136
|
-
raise
|
|
137
|
-
_xError(X, Fmt.INDEX(xs=i), x)
|
|
136
|
+
raise _xsError(X, xs, i, x)
|
|
138
137
|
|
|
139
138
|
|
|
140
|
-
try: # MCCABE
|
|
139
|
+
try: # MCCABE 26
|
|
141
140
|
from math import fma as _fma
|
|
142
141
|
|
|
143
|
-
def _2products(x, ys,
|
|
142
|
+
def _2products(x, ys, *zs):
|
|
143
|
+
# yield(x * y for y in ys) + yield(z in zs)
|
|
144
144
|
# TwoProductFMA U{Algorithm 3.5
|
|
145
145
|
# <https://www.TUHH.De/ti3/paper/rump/OgRuOi05.pdf>}
|
|
146
146
|
for y in ys:
|
|
147
147
|
f = x * y
|
|
148
148
|
yield f
|
|
149
149
|
yield _fma(x, y, -f)
|
|
150
|
+
for z in zs:
|
|
151
|
+
yield z
|
|
150
152
|
|
|
151
|
-
|
|
153
|
+
# _2split3 = \
|
|
154
|
+
_2split3s = _passarg # in Fsum.is_math_fma
|
|
152
155
|
|
|
153
|
-
except
|
|
156
|
+
except ImportError: # PYCHOK DSPACE! Python 3.12-
|
|
154
157
|
|
|
155
|
-
|
|
156
|
-
#
|
|
157
|
-
# <https://MomentsInGraphics.De/FMA.html>
|
|
158
|
-
# >>> a = 1.00000011920929
|
|
159
|
-
# >>> b = 53400708
|
|
160
|
-
# >>> c = -b
|
|
161
|
-
# >>> _fma(a, b, c)
|
|
162
|
-
# 6.365860485903399
|
|
163
|
-
# >>> (a * b) + c
|
|
164
|
-
# 6.3658604845404625
|
|
158
|
+
if _F2PRODUCT and _F2PRODUCT != _std_:
|
|
159
|
+
# back to PyGeodesy 24.09.09, with _fmaX
|
|
165
160
|
|
|
166
|
-
def
|
|
161
|
+
def _fma(*a_b_c): # PYCHOK no cover
|
|
162
|
+
# mimick C{math.fma} from Python 3.13+,
|
|
163
|
+
# the same accuracy, but ~14x slower
|
|
164
|
+
(na, da), (nb, db), (nc, dc) = map(_2n_d, a_b_c)
|
|
165
|
+
n = na * nb * dc
|
|
166
|
+
n += da * db * nc
|
|
167
|
+
d = da * db * dc
|
|
167
168
|
try:
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
169
|
+
r = float(n / d)
|
|
170
|
+
except OverflowError: # "integer division result too large ..."
|
|
171
|
+
r = NINF if (_signOf(n, 0) * _signOf(d, 0)) < 0 else INF
|
|
172
|
+
return r if _isfinite(r) else _fmaX(r, *a_b_c) # "overflow in fma"
|
|
173
|
+
|
|
174
|
+
def _2n_d(x):
|
|
175
|
+
try: # int.as_integer_ratio in 3.8+
|
|
176
|
+
return x.as_integer_ratio()
|
|
171
177
|
except (AttributeError, OverflowError, TypeError, ValueError):
|
|
172
|
-
|
|
173
|
-
|
|
178
|
+
return (x if isint(x) else float(x)), 1
|
|
179
|
+
else:
|
|
174
180
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
181
|
+
def _fma(a, b, c): # PYCHOK redef
|
|
182
|
+
# mimick C{math.fma} from Python 3.13+,
|
|
183
|
+
# the same accuracy, but ~13x slower
|
|
184
|
+
b3s = _2split3(b), # 1-tuple of 3-tuple
|
|
185
|
+
r = _fsum(_2products(a, b3s, c))
|
|
186
|
+
return r if _isfinite(r) else _fmaX(r, a, b, c)
|
|
187
|
+
|
|
188
|
+
_2n_d = None # redef
|
|
189
|
+
|
|
190
|
+
def _fmaX(r, *a_b_c): # like Python 3.13+ I{Modules/mathmodule.c}:
|
|
191
|
+
# raise a ValueError for a NAN result from non-NAN C{a_b_c}s or
|
|
192
|
+
# OverflowError for a non-NAN result from all finite C{a_b_c}s.
|
|
193
|
+
if isnan(r):
|
|
194
|
+
def _x(x):
|
|
195
|
+
return not isnan(x)
|
|
196
|
+
else:
|
|
197
|
+
_x = _isfinite
|
|
198
|
+
if all(map(_x, a_b_c)):
|
|
199
|
+
raise _nfError(r, unstr(_fma, *a_b_c))
|
|
200
|
+
return r
|
|
179
201
|
|
|
180
|
-
def _2products(x, y3s,
|
|
202
|
+
def _2products(x, y3s, *zs): # PYCHOK in Fsum._f2mul
|
|
203
|
+
# yield(x * y3 for y3 in y3s) + yield(z in zs)
|
|
181
204
|
# TwoProduct U{Algorithm 3.3
|
|
182
205
|
# <https://www.TUHH.De/ti3/paper/rump/OgRuOi05.pdf>}
|
|
206
|
+
# also in Python 3.13+ C{Modules/mathmodule.c} under
|
|
207
|
+
# #ifndef UNRELIABLE_FMA ... #else ... #endif
|
|
183
208
|
_, a, b = _2split3(x)
|
|
184
209
|
for y, c, d in y3s:
|
|
185
210
|
y *= x
|
|
186
211
|
yield y
|
|
187
|
-
if
|
|
212
|
+
if False: # no cover
|
|
188
213
|
yield b * d - (((y - a * c) - b * c) - a * d)
|
|
189
|
-
#
|
|
190
|
-
#
|
|
191
|
-
#
|
|
192
|
-
|
|
214
|
+
# = b * d + (a * d - ((y - a * c) - b * c))
|
|
215
|
+
# = b * d + (a * d + (b * c - (y - a * c)))
|
|
216
|
+
# = b * d + (a * d + (b * c + (a * c - y)))
|
|
217
|
+
elif a:
|
|
193
218
|
yield a * c - y
|
|
194
219
|
yield b * c
|
|
195
220
|
if d:
|
|
196
221
|
yield a * d
|
|
197
222
|
yield b * d
|
|
223
|
+
else:
|
|
224
|
+
yield b * c - y
|
|
225
|
+
yield b * d
|
|
226
|
+
for z in zs:
|
|
227
|
+
yield z
|
|
198
228
|
|
|
199
|
-
_2FACTOR = pow(2, (MANT_DIG + 1) // 2) +
|
|
229
|
+
_2FACTOR = pow(2, (MANT_DIG + 1) // 2) + _1_0 # 134217729 if MANT_DIG == 53
|
|
200
230
|
|
|
201
231
|
def _2split3(x):
|
|
202
232
|
# Split U{Algorithm 3.2
|
|
203
|
-
# <
|
|
233
|
+
# <https://www.TUHH.De/ti3/paper/rump/OgRuOi05.pdf>}
|
|
204
234
|
a = c = x * _2FACTOR
|
|
205
235
|
a -= c - x
|
|
206
236
|
b = x - a
|
|
207
237
|
return x, a, b
|
|
208
238
|
|
|
209
|
-
def _2split3s(xs): #
|
|
239
|
+
def _2split3s(xs): # in Fsum.is_math_fma
|
|
210
240
|
return map(_2split3, xs)
|
|
211
241
|
|
|
212
|
-
del MANT_DIG
|
|
213
242
|
|
|
243
|
+
def f2product(*two):
|
|
244
|
+
'''Turn accurate I{TwoProduct} multiplication on or off.
|
|
245
|
+
|
|
246
|
+
@arg two: If C{True}, turn I{TwoProduct} on, if C{False} off or
|
|
247
|
+
if C{None} or omitted, keep the current setting.
|
|
214
248
|
|
|
215
|
-
|
|
216
|
-
|
|
249
|
+
@return: The previous setting (C{bool}).
|
|
250
|
+
|
|
251
|
+
@see: I{TwoProduct} multiplication is based on the I{TwoProductFMA}
|
|
252
|
+
U{Algorithm 3.5 <https://www.TUHH.De/ti3/paper/rump/OgRuOi05.pdf>}
|
|
253
|
+
using function C{math.fma} from Python 3.13 and later or an
|
|
254
|
+
equivalent, slower implementation when not available.
|
|
217
255
|
'''
|
|
218
|
-
|
|
256
|
+
t = Fsum._f2product
|
|
257
|
+
if two and two[0] is not None:
|
|
258
|
+
Fsum._f2product = bool(two[0])
|
|
259
|
+
return t
|
|
219
260
|
|
|
220
261
|
|
|
221
|
-
def
|
|
222
|
-
'''(INTERNAL) An C{Fsum}
|
|
262
|
+
def _Fsumf_(*xs): # in .auxLat, .ltp, ...
|
|
263
|
+
'''(INTERNAL) An C{Fsum(xs)}, all C{scalar}, an L{Fsum} or L{Fsum2Tuple}.
|
|
223
264
|
'''
|
|
224
|
-
return Fsum().
|
|
265
|
+
return Fsum()._facc_scalarf(xs, up=False)
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def _Fsum1f_(*xs): # in .albers
|
|
269
|
+
'''(INTERNAL) An C{Fsum(xs)}, all C{scalar}, an L{Fsum} or L{Fsum2Tuple}, 1-primed.
|
|
270
|
+
'''
|
|
271
|
+
return Fsum()._facc_scalarf(_1primed(xs), up=False)
|
|
225
272
|
|
|
226
273
|
|
|
227
274
|
def _2halfeven(s, r, p):
|
|
@@ -242,16 +289,69 @@ def _isFsum(x): # in .fmath
|
|
|
242
289
|
return isinstance(x, Fsum)
|
|
243
290
|
|
|
244
291
|
|
|
245
|
-
def
|
|
292
|
+
def _isFsum_2Tuple(x): # in .basics, .constants, .fmath, .fstats
|
|
246
293
|
'''(INTERNAL) Is C{x} an C{Fsum} or C{Fsum2Tuple} instance?
|
|
247
294
|
'''
|
|
248
|
-
return isinstance(x,
|
|
295
|
+
return isinstance(x, _Fsum_2Tuple_types)
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def _isOK(unused):
|
|
299
|
+
'''(INTERNAL) Helper for C{Fsum._fsum2} and C{Fsum.nonfinites}.
|
|
300
|
+
'''
|
|
301
|
+
return True
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def _isOK_or_finite(x, _isfine=_isfinite):
|
|
305
|
+
'''(INTERNAL) Is C{x} finite or is I{non-finite} OK?.
|
|
306
|
+
'''
|
|
307
|
+
# assert _isfine in (_isOK, _isfinite)
|
|
308
|
+
return _isfine(x)
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def _ixError(X, xs, i, x, origin=0, which=None):
|
|
312
|
+
'''(INTERNAL) Error for C{xs} or C{x}, item C{xs[i]}.
|
|
313
|
+
'''
|
|
314
|
+
t = _xsError(X, xs, i + origin, x)
|
|
315
|
+
if which:
|
|
316
|
+
t = _COMMASPACE_(unstr(which, _Cdot=Fsum), t)
|
|
317
|
+
return _xError(X, t, txt=None)
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def _nfError(x, *args):
|
|
321
|
+
'''(INTERNAL) Throw a C{not-finite} exception.
|
|
322
|
+
'''
|
|
323
|
+
E = _NonfiniteError(x)
|
|
324
|
+
t = Fmt.PARENSPACED(_not_finite_, x)
|
|
325
|
+
if args: # in _fmaX, _2sum
|
|
326
|
+
return E(txt=t, *args)
|
|
327
|
+
raise E(t, txt=None)
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def nonfiniterrors(*raiser):
|
|
331
|
+
'''Throw C{OverflowError} and C{ValueError} exceptions for or
|
|
332
|
+
handle I{non-finite} C{float}s as C{inf}, C{INF}, C{NINF},
|
|
333
|
+
C{nan} and C{NAN} in summations and multiplications.
|
|
334
|
+
|
|
335
|
+
@arg raiser: If C{True}, throw exceptions, if C{False} handle
|
|
336
|
+
I{non-finites} or if C{None} or omitted, leave
|
|
337
|
+
the setting unchanged.
|
|
338
|
+
|
|
339
|
+
@return: Previous setting (C{bool}).
|
|
340
|
+
|
|
341
|
+
@note: C{inf}, C{INF} and C{NINF} throw an C{OverflowError},
|
|
342
|
+
C{nan} and C{NAN} a C{ValueError}.
|
|
343
|
+
'''
|
|
344
|
+
d = Fsum._isfine
|
|
345
|
+
if raiser and raiser[0] is not None:
|
|
346
|
+
Fsum._isfine = {} if bool(raiser[0]) else Fsum._nonfinites_isfine_kwds[True]
|
|
347
|
+
return _xkwds_get1(d, _isfine=_isfinite) is _isfinite
|
|
249
348
|
|
|
250
349
|
|
|
251
|
-
def
|
|
252
|
-
'''(INTERNAL) Return
|
|
350
|
+
def _NonfiniteError(x):
|
|
351
|
+
'''(INTERNAL) Return the Error class for C{x}, I{non-finite}.
|
|
253
352
|
'''
|
|
254
|
-
return
|
|
353
|
+
return _OverflowError if isinf(x) else (
|
|
354
|
+
_ValueError if isnan(x) else _AssertionError)
|
|
255
355
|
|
|
256
356
|
|
|
257
357
|
def _1primed(xs): # in .fmath
|
|
@@ -264,16 +364,15 @@ def _1primed(xs): # in .fmath
|
|
|
264
364
|
yield _N_1_0
|
|
265
365
|
|
|
266
366
|
|
|
267
|
-
def _psum(ps): # PYCHOK used!
|
|
367
|
+
def _psum(ps, **_isfine): # PYCHOK used!
|
|
268
368
|
'''(INTERNAL) Partials summation, updating C{ps}.
|
|
269
369
|
'''
|
|
270
370
|
# assert isinstance(ps, list)
|
|
271
|
-
i
|
|
272
|
-
s
|
|
273
|
-
_2s = _2sum
|
|
371
|
+
i = len(ps) - 1
|
|
372
|
+
s = _0_0 if i < 0 else ps[i]
|
|
274
373
|
while i > 0:
|
|
275
374
|
i -= 1
|
|
276
|
-
s, r =
|
|
375
|
+
s, r = _2sum(s, ps[i], **_isfine)
|
|
277
376
|
if r: # sum(ps) became inexact
|
|
278
377
|
if s:
|
|
279
378
|
ps[i:] = r, s
|
|
@@ -281,31 +380,35 @@ def _psum(ps): # PYCHOK used!
|
|
|
281
380
|
s = _2halfeven(s, r, ps[i-1])
|
|
282
381
|
break # return s
|
|
283
382
|
s = r # PYCHOK no cover
|
|
383
|
+
elif not _isfinite(s): # non-finite OK
|
|
384
|
+
i = 0 # collapse ps
|
|
385
|
+
if ps:
|
|
386
|
+
s += sum(ps)
|
|
284
387
|
ps[i:] = s,
|
|
285
388
|
return s
|
|
286
389
|
|
|
287
390
|
|
|
288
|
-
def _Psum(ps, **
|
|
391
|
+
def _Psum(ps, **name_f2product_nonfinites_RESIDUAL):
|
|
289
392
|
'''(INTERNAL) Return an C{Fsum} from I{ordered} partials C{ps}.
|
|
290
393
|
'''
|
|
291
|
-
|
|
394
|
+
F = Fsum(**name_f2product_nonfinites_RESIDUAL)
|
|
292
395
|
if ps:
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
return
|
|
396
|
+
F._ps[:] = ps
|
|
397
|
+
F._n = len(F._ps)
|
|
398
|
+
return F
|
|
296
399
|
|
|
297
400
|
|
|
298
|
-
def _Psum_(*ps, **
|
|
299
|
-
'''(INTERNAL) Return an C{Fsum} from
|
|
401
|
+
def _Psum_(*ps, **name_f2product_nonfinites_RESIDUAL): # in .fmath
|
|
402
|
+
'''(INTERNAL) Return an C{Fsum} from I{known scalar} C{ps}.
|
|
300
403
|
'''
|
|
301
|
-
return _Psum(ps, **
|
|
404
|
+
return _Psum(ps, **name_f2product_nonfinites_RESIDUAL)
|
|
302
405
|
|
|
303
406
|
|
|
304
407
|
def _2scalar2(other):
|
|
305
408
|
'''(INTERNAL) Return 2-tuple C{(other, r)} with C{other} as C{int},
|
|
306
409
|
C{float} or C{as-is} and C{r} the residual of C{as-is}.
|
|
307
410
|
'''
|
|
308
|
-
if
|
|
411
|
+
if _isFsum_2Tuple(other):
|
|
309
412
|
s, r = other._fint2
|
|
310
413
|
if r:
|
|
311
414
|
s, r = other._fprs2
|
|
@@ -322,7 +425,7 @@ def _2scalar2(other):
|
|
|
322
425
|
def _s_r(s, r):
|
|
323
426
|
'''(INTERNAL) Return C{(s, r)}, I{ordered}.
|
|
324
427
|
'''
|
|
325
|
-
if r:
|
|
428
|
+
if r and _isfinite(s):
|
|
326
429
|
if fabs(s) < fabs(r):
|
|
327
430
|
s, r = r, (s or INT0)
|
|
328
431
|
else:
|
|
@@ -334,7 +437,7 @@ def _strcomplex(s, *args):
|
|
|
334
437
|
'''(INTERNAL) C{Complex} 2- or 3-arg C{pow} error as C{str}.
|
|
335
438
|
'''
|
|
336
439
|
c = _strcomplex.__name__[4:]
|
|
337
|
-
n =
|
|
440
|
+
n = _sub_op_(len(args), _arg_)
|
|
338
441
|
t = unstr(pow, *args)
|
|
339
442
|
return _SPACE_(c, s, _from_, n, t)
|
|
340
443
|
|
|
@@ -350,9 +453,12 @@ def _stresidual(prefix, residual, R=0, **mod_ratio):
|
|
|
350
453
|
return _SPACE_(prefix, t, Fmt.exceeds_R(R), _threshold_)
|
|
351
454
|
|
|
352
455
|
|
|
353
|
-
def _2sum(a, b): #
|
|
354
|
-
'''(INTERNAL) Return C{a + b} as 2-tuple (sum, residual)
|
|
456
|
+
def _2sum(a, b, _isfine=_isfinite): # in .testFmath
|
|
457
|
+
'''(INTERNAL) Return C{a + b} as 2-tuple C{(sum, residual)} with finite C{sum},
|
|
458
|
+
otherwise as 2-tuple C{(nonfinite, 0)} iff I{non-finites} are OK.
|
|
355
459
|
'''
|
|
460
|
+
# FastTwoSum U{Algorithm 1.1<https://www.TUHH.De/ti3/paper/rump/OgRuOi05.pdf>}
|
|
461
|
+
|
|
356
462
|
# Neumaier, A. U{Rundungsfehleranalyse einiger Verfahren zur Summation endlicher
|
|
357
463
|
# Summen<https://OnlineLibrary.Wiley.com/doi/epdf/10.1002/zamm.19740540106>},
|
|
358
464
|
# 1974, Zeitschrift für Angewandte Mathmatik und Mechanik, vol 51, nr 1, p 39-51
|
|
@@ -363,10 +469,12 @@ def _2sum(a, b): # by .testFmath
|
|
|
363
469
|
r = (b - s) + a
|
|
364
470
|
else:
|
|
365
471
|
r = (a - s) + b
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
472
|
+
elif _isfine(s):
|
|
473
|
+
r = _NONFINITEr
|
|
474
|
+
else: # non-finite and not OK
|
|
475
|
+
t = unstr(_2sum, a, b)
|
|
476
|
+
raise _nfError(s, t)
|
|
477
|
+
return s, r
|
|
370
478
|
|
|
371
479
|
|
|
372
480
|
def _threshold(threshold=_0_0, **kwds):
|
|
@@ -374,29 +482,28 @@ def _threshold(threshold=_0_0, **kwds):
|
|
|
374
482
|
optionally from single kwds C{B{RESIDUAL}=scalar}.
|
|
375
483
|
'''
|
|
376
484
|
if kwds:
|
|
377
|
-
threshold
|
|
378
|
-
# threshold = kwds.pop('RESIDUAL', threshold)
|
|
379
|
-
if kwds:
|
|
380
|
-
raise _UnexpectedError(**kwds)
|
|
485
|
+
threshold = _xkwds_get1(kwds, RESIDUAL=threshold)
|
|
381
486
|
try:
|
|
382
487
|
return _2finite(threshold) # PYCHOK None
|
|
383
488
|
except Exception as x:
|
|
384
489
|
raise ResidualError(threshold=threshold, cause=x)
|
|
385
490
|
|
|
386
491
|
|
|
387
|
-
class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
388
|
-
'''Precision floating point summation
|
|
492
|
+
class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats, ...
|
|
493
|
+
'''Precision floating point summation, I{running} summation and accurate multiplication.
|
|
389
494
|
|
|
390
495
|
Unlike Python's C{math.fsum}, this class accumulates values and provides intermediate,
|
|
391
496
|
I{running}, precision floating point summations. Accumulation may continue after any
|
|
392
497
|
intermediate, I{running} summuation.
|
|
393
498
|
|
|
394
499
|
@note: Values may be L{Fsum}, L{Fsum2Tuple}, C{int}, C{float} or C{scalar} instances,
|
|
395
|
-
any C{type} having method C{__float__}
|
|
396
|
-
C{float}, except C{complex}.
|
|
500
|
+
i.e. any C{type} having method C{__float__}.
|
|
397
501
|
|
|
398
|
-
@note: Handling of
|
|
399
|
-
|
|
502
|
+
@note: Handling of I{non-finites} as C{inf}, C{INF}, C{NINF}, C{nan} and C{NAN} is
|
|
503
|
+
determined by function L{nonfiniterrors<fsums.nonfiniterrors>} for the default
|
|
504
|
+
and by method L{nonfinites<Fsum.nonfinites>} for individual C{Fsum} instances,
|
|
505
|
+
overruling the default. For backward compatibility, I{non-finites} raise
|
|
506
|
+
exceptions by default.
|
|
400
507
|
|
|
401
508
|
@see: U{Hettinger<https://GitHub.com/ActiveState/code/tree/master/recipes/Python/
|
|
402
509
|
393090_Binary_floating_point_summatiaccurate_full/recipe-393090.py>},
|
|
@@ -404,42 +511,41 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
404
511
|
<https://Link.Springer.com/article/10.1007/s00607-005-0139-x>}, Python 2.6+
|
|
405
512
|
file I{Modules/mathmodule.c} and the issue log U{Full precision summation
|
|
406
513
|
<https://Bugs.Python.org/issue2819>}.
|
|
514
|
+
|
|
515
|
+
@see: Method L{f2product<Fsum.f2product>} for details about accurate I{TwoProduct}
|
|
516
|
+
multiplication.
|
|
517
|
+
|
|
518
|
+
@see: Module L{fsums<pygeodesy.fsums>} for env variables C{PYGEODESY_FSUM_F2PRODUCT},
|
|
519
|
+
C{PYGEODESY_FSUM_NONFINITES} and C{PYGEODESY_FSUM_RESIDUAL}.
|
|
407
520
|
'''
|
|
408
|
-
_f2product =
|
|
409
|
-
|
|
410
|
-
_math_fsum = None
|
|
521
|
+
_f2product = _sys_version_info2 > (3, 12) or bool(_F2PRODUCT)
|
|
522
|
+
_isfine = {} # == _isfinite
|
|
411
523
|
_n = 0
|
|
412
524
|
# _ps = [] # partial sums
|
|
413
|
-
# _ps_max = 0 # max(Fsum._ps_max, len(Fsum._ps))
|
|
414
|
-
_RESIDUAL = _threshold(
|
|
525
|
+
# _ps_max = 0 # max(Fsum._ps_max, len(Fsum._ps)) # 41
|
|
526
|
+
_RESIDUAL = _threshold(_RESIDUAL_0_0)
|
|
415
527
|
|
|
416
|
-
def __init__(self, *xs, **
|
|
417
|
-
'''New L{Fsum}
|
|
528
|
+
def __init__(self, *xs, **name_f2product_nonfinites_RESIDUAL):
|
|
529
|
+
'''New L{Fsum}.
|
|
418
530
|
|
|
419
|
-
@arg xs: No, one or more initial items to
|
|
420
|
-
|
|
421
|
-
@kwarg
|
|
422
|
-
|
|
423
|
-
|
|
531
|
+
@arg xs: No, one or more initial items to accumulate (each C{scalar}, an
|
|
532
|
+
L{Fsum} or L{Fsum2Tuple}), all positional.
|
|
533
|
+
@kwarg name_f2product_nonfinites_RESIDUAL: Optional C{B{name}=NN} (C{str})
|
|
534
|
+
and settings C{B{f2product}=None} (C{bool}), C{B{nonfinites}=None}
|
|
535
|
+
(C{bool}) and C{B{RESIDUAL}=0.0} threshold (C{scalar}) for this
|
|
536
|
+
L{Fsum}.
|
|
424
537
|
|
|
425
|
-
@see: Methods L{Fsum.
|
|
538
|
+
@see: Methods L{Fsum.f2product}, L{Fsum.nonfinites}, L{Fsum.RESIDUAL},
|
|
539
|
+
L{Fsum.fadd} and L{Fsum.fadd_}.
|
|
426
540
|
'''
|
|
427
|
-
if
|
|
428
|
-
|
|
429
|
-
if kwds:
|
|
430
|
-
R = Fsum._RESIDUAL
|
|
431
|
-
t = _threshold(R, **kwds)
|
|
432
|
-
if t != R:
|
|
433
|
-
self._RESIDUAL = t
|
|
434
|
-
if n:
|
|
435
|
-
self.name = n
|
|
436
|
-
|
|
541
|
+
if name_f2product_nonfinites_RESIDUAL:
|
|
542
|
+
self._optionals(**name_f2product_nonfinites_RESIDUAL)
|
|
437
543
|
self._ps = [] # [_0_0], see L{Fsum._fprs}
|
|
438
544
|
if xs:
|
|
439
|
-
self.
|
|
545
|
+
self._facc_args(xs, up=False)
|
|
440
546
|
|
|
441
547
|
def __abs__(self):
|
|
442
|
-
'''Return
|
|
548
|
+
'''Return C{abs(self)} as an L{Fsum}.
|
|
443
549
|
'''
|
|
444
550
|
s = self.signOf() # == self._cmp_0(0)
|
|
445
551
|
return (-self) if s < 0 else self._copy_2(self.__abs__)
|
|
@@ -457,7 +563,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
457
563
|
return f._fadd(other, _add_op_)
|
|
458
564
|
|
|
459
565
|
def __bool__(self): # PYCHOK Python 3+
|
|
460
|
-
'''Return C{True}
|
|
566
|
+
'''Return C{bool(B{self})}, C{True} iff C{residual} is zero.
|
|
461
567
|
'''
|
|
462
568
|
s, r = self._fprs2
|
|
463
569
|
return bool(s or r) and s != -r # == self != 0
|
|
@@ -500,7 +606,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
500
606
|
return f._fdivmod2(other, _divmod_op_, **raiser_RESIDUAL)
|
|
501
607
|
|
|
502
608
|
def __eq__(self, other):
|
|
503
|
-
'''
|
|
609
|
+
'''Return C{(B{self} == B{other})} as C{bool} where B{C{other}}
|
|
610
|
+
is C{scalar}, an other L{Fsum} or L{Fsum2Tuple}.
|
|
504
611
|
'''
|
|
505
612
|
return self._cmp_0(other, _eq_op_) == 0
|
|
506
613
|
|
|
@@ -537,17 +644,17 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
537
644
|
return _NotImplemented(self, *other)
|
|
538
645
|
|
|
539
646
|
def __ge__(self, other):
|
|
540
|
-
'''
|
|
647
|
+
'''Return C{(B{self} >= B{other})}, see C{__eq__}.
|
|
541
648
|
'''
|
|
542
649
|
return self._cmp_0(other, _ge_op_) >= 0
|
|
543
650
|
|
|
544
651
|
def __gt__(self, other):
|
|
545
|
-
'''
|
|
652
|
+
'''Return C{(B{self} > B{other})}, see C{__eq__}.
|
|
546
653
|
'''
|
|
547
654
|
return self._cmp_0(other, _gt_op_) > 0
|
|
548
655
|
|
|
549
656
|
def __hash__(self): # PYCHOK no cover
|
|
550
|
-
'''Return
|
|
657
|
+
'''Return C{hash(B{self})} as C{float}.
|
|
551
658
|
'''
|
|
552
659
|
# @see: U{Notes for type implementors<https://docs.Python.org/
|
|
553
660
|
# 3/library/numbers.html#numbers.Rational>}
|
|
@@ -569,7 +676,9 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
569
676
|
try:
|
|
570
677
|
return self._fadd(other, _iadd_op_)
|
|
571
678
|
except TypeError:
|
|
572
|
-
|
|
679
|
+
pass
|
|
680
|
+
_xiterable(other)
|
|
681
|
+
return self._facc(other)
|
|
573
682
|
|
|
574
683
|
def __ifloordiv__(self, other):
|
|
575
684
|
'''Apply C{B{self} //= B{other}} to this instance.
|
|
@@ -583,7 +692,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
583
692
|
|
|
584
693
|
@raise TypeError: Invalid B{C{other}} type.
|
|
585
694
|
|
|
586
|
-
@raise ValueError: Invalid or non-finite B{C{other}}.
|
|
695
|
+
@raise ValueError: Invalid or I{non-finite} B{C{other}}.
|
|
587
696
|
|
|
588
697
|
@raise ZeroDivisionError: Zero B{C{other}}.
|
|
589
698
|
|
|
@@ -617,7 +726,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
617
726
|
|
|
618
727
|
@raise TypeError: Invalid B{C{other}} type.
|
|
619
728
|
|
|
620
|
-
@raise ValueError: Invalid or non-finite B{C{other}}.
|
|
729
|
+
@raise ValueError: Invalid or I{non-finite} B{C{other}}.
|
|
621
730
|
'''
|
|
622
731
|
return self._fmul(other, _mul_op_ + _fset_op_)
|
|
623
732
|
|
|
@@ -638,7 +747,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
638
747
|
def __ipow__(self, other, *mod, **raiser_RESIDUAL): # PYCHOK 2 vs 3 args
|
|
639
748
|
'''Apply C{B{self} **= B{other}} to this instance.
|
|
640
749
|
|
|
641
|
-
@arg other: The exponent (C{scalar}, L{Fsum} or L{Fsum2Tuple}).
|
|
750
|
+
@arg other: The exponent (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
|
|
642
751
|
@arg mod: Optional modulus (C{int} or C{None}) for the 3-argument
|
|
643
752
|
C{pow(B{self}, B{other}, B{mod})} version.
|
|
644
753
|
@kwarg raiser_RESIDUAL: Use C{B{raiser}=False} to ignore
|
|
@@ -688,7 +797,9 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
688
797
|
try:
|
|
689
798
|
return self._fsub(other, _isub_op_)
|
|
690
799
|
except TypeError:
|
|
691
|
-
|
|
800
|
+
pass
|
|
801
|
+
_xiterable(other)
|
|
802
|
+
return self._facc_neg(other)
|
|
692
803
|
|
|
693
804
|
def __iter__(self):
|
|
694
805
|
'''Return an C{iter}ator over a C{partials} duplicate.
|
|
@@ -712,7 +823,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
712
823
|
|
|
713
824
|
@raise TypeError: Invalid B{C{other}} type.
|
|
714
825
|
|
|
715
|
-
@raise ValueError: Invalid or non-finite B{C{other}}.
|
|
826
|
+
@raise ValueError: Invalid or I{non-finite} B{C{other}}.
|
|
716
827
|
|
|
717
828
|
@raise ZeroDivisionError: Zero B{C{other}}.
|
|
718
829
|
|
|
@@ -721,7 +832,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
721
832
|
return self._ftruediv(other, _truediv_op_ + _fset_op_, **raiser_RESIDUAL)
|
|
722
833
|
|
|
723
834
|
def __le__(self, other):
|
|
724
|
-
'''
|
|
835
|
+
'''Return C{(B{self} <= B{other})}, see C{__eq__}.
|
|
725
836
|
'''
|
|
726
837
|
return self._cmp_0(other, _le_op_) <= 0
|
|
727
838
|
|
|
@@ -731,7 +842,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
731
842
|
return self._n
|
|
732
843
|
|
|
733
844
|
def __lt__(self, other):
|
|
734
|
-
'''
|
|
845
|
+
'''Return C{(B{self} < B{other})}, see C{__eq__}.
|
|
735
846
|
'''
|
|
736
847
|
return self._cmp_0(other, _lt_op_) < 0
|
|
737
848
|
|
|
@@ -756,12 +867,12 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
756
867
|
return f._fmul(other, _mul_op_)
|
|
757
868
|
|
|
758
869
|
def __ne__(self, other):
|
|
759
|
-
'''
|
|
870
|
+
'''Return C{(B{self} != B{other})}, see C{__eq__}.
|
|
760
871
|
'''
|
|
761
872
|
return self._cmp_0(other, _ne_op_) != 0
|
|
762
873
|
|
|
763
874
|
def __neg__(self):
|
|
764
|
-
'''Return
|
|
875
|
+
'''Return C{copy(B{self})}, I{negated}.
|
|
765
876
|
'''
|
|
766
877
|
f = self._copy_2(self.__neg__)
|
|
767
878
|
return f._fset(self._neg)
|
|
@@ -909,11 +1020,13 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
909
1020
|
def as_integer_ratio(self):
|
|
910
1021
|
'''Return this instance as the ratio of 2 integers.
|
|
911
1022
|
|
|
912
|
-
@return: 2-Tuple C{(numerator, denominator)} both C{int}
|
|
913
|
-
|
|
914
|
-
non-
|
|
1023
|
+
@return: 2-Tuple C{(numerator, denominator)} both C{int} with
|
|
1024
|
+
C{numerator} signed and C{denominator} non-zero and
|
|
1025
|
+
positive. The C{numerator} is I{non-finite} if this
|
|
1026
|
+
instance is.
|
|
915
1027
|
|
|
916
|
-
@see:
|
|
1028
|
+
@see: Method L{Fsum.fint2} and C{float.as_integer_ratio} in
|
|
1029
|
+
Python 2.7+.
|
|
917
1030
|
'''
|
|
918
1031
|
n, r = self._fint2
|
|
919
1032
|
if r:
|
|
@@ -926,8 +1039,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
926
1039
|
|
|
927
1040
|
@property_RO
|
|
928
1041
|
def as_iscalar(self):
|
|
929
|
-
'''Get this instance I{as-is} (L{Fsum}
|
|
930
|
-
|
|
1042
|
+
'''Get this instance I{as-is} (L{Fsum} with C{non-zero residual},
|
|
1043
|
+
C{scalar} or I{non-finite}).
|
|
931
1044
|
'''
|
|
932
1045
|
s, r = self._fprs2
|
|
933
1046
|
return self if r else s
|
|
@@ -953,7 +1066,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
953
1066
|
def _cmp_0(self, other, op):
|
|
954
1067
|
'''(INTERNAL) Return C{scalar(self - B{other})} for 0-comparison.
|
|
955
1068
|
'''
|
|
956
|
-
if
|
|
1069
|
+
if _isFsum_2Tuple(other):
|
|
957
1070
|
s = self._ps_1sum(*other._ps)
|
|
958
1071
|
elif self._scalar(other, op):
|
|
959
1072
|
s = self._ps_1sum(other)
|
|
@@ -996,19 +1109,14 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
996
1109
|
return other._copy_2(which) if _isFsum(other) else \
|
|
997
1110
|
self._copy_2(which)._fset(other)
|
|
998
1111
|
|
|
999
|
-
# def _copy_RESIDUAL(self, other):
|
|
1000
|
-
# '''(INTERNAL) Copy C{other._RESIDUAL}.
|
|
1001
|
-
# '''
|
|
1002
|
-
# R = other._RESIDUAL
|
|
1003
|
-
# if R is not Fsum._RESIDUAL:
|
|
1004
|
-
# self._RESIDUAL = R
|
|
1005
|
-
|
|
1006
1112
|
divmod = __divmod__
|
|
1007
1113
|
|
|
1008
1114
|
def _Error(self, op, other, Error, **txt_cause):
|
|
1009
1115
|
'''(INTERNAL) Format an B{C{Error}} for C{{self} B{op} B{other}}.
|
|
1010
1116
|
'''
|
|
1011
|
-
|
|
1117
|
+
# self.as_iscalar causes RecursionError for ._fprs2 errors
|
|
1118
|
+
s = _Psum(self._ps, nonfinites=True, name=self.name)
|
|
1119
|
+
return Error(_SPACE_(s.as_iscalar, op, other), **txt_cause)
|
|
1012
1120
|
|
|
1013
1121
|
def _ErrorX(self, X, op, other, *mod):
|
|
1014
1122
|
'''(INTERNAL) Format the caught exception C{X}.
|
|
@@ -1029,28 +1137,21 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1029
1137
|
'''(INTERNAL) Accumulate more C{scalars} or L{Fsum}s.
|
|
1030
1138
|
'''
|
|
1031
1139
|
if xs:
|
|
1032
|
-
|
|
1140
|
+
kwds = _xkwds(self._isfine, **origin_X_x)
|
|
1141
|
+
fs = _2floats(xs, **kwds) # PYCHOK yield
|
|
1033
1142
|
ps = self._ps
|
|
1034
|
-
ps[:] = self._ps_acc(list(ps),
|
|
1143
|
+
ps[:] = self._ps_acc(list(ps), fs, up=up)
|
|
1035
1144
|
return self
|
|
1036
1145
|
|
|
1037
|
-
def
|
|
1038
|
-
'''(INTERNAL) Accumulate 0, 1 or more C{
|
|
1039
|
-
|
|
1146
|
+
def _facc_args(self, xs, **up):
|
|
1147
|
+
'''(INTERNAL) Accumulate 0, 1 or more C{xs}, all positional
|
|
1148
|
+
arguments in the caller of this method.
|
|
1040
1149
|
'''
|
|
1041
|
-
return self.
|
|
1042
|
-
self.
|
|
1043
|
-
|
|
1044
|
-
def _facc_inplace(self, other, op, _facc):
|
|
1045
|
-
'''(INTERNAL) Accumulate from an iterable.
|
|
1046
|
-
'''
|
|
1047
|
-
try:
|
|
1048
|
-
return _facc(other, origin=1) if _xiterable(other) else self
|
|
1049
|
-
except Exception as X:
|
|
1050
|
-
raise self._ErrorX(X, op, other)
|
|
1150
|
+
return self._facc(xs, origin=1, **up) if len(xs) != 1 else \
|
|
1151
|
+
self._fadd(xs[0], _add_op_, **up)
|
|
1051
1152
|
|
|
1052
1153
|
def _facc_neg(self, xs, **up_origin):
|
|
1053
|
-
'''(INTERNAL) Accumulate more C{
|
|
1154
|
+
'''(INTERNAL) Accumulate more C{xs}, negated.
|
|
1054
1155
|
'''
|
|
1055
1156
|
def _N(X):
|
|
1056
1157
|
return X._ps_neg
|
|
@@ -1065,7 +1166,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1065
1166
|
'''
|
|
1066
1167
|
def _Pow4(p):
|
|
1067
1168
|
r = 0
|
|
1068
|
-
if
|
|
1169
|
+
if _isFsum_2Tuple(p):
|
|
1069
1170
|
s, r = p._fprs2
|
|
1070
1171
|
if r:
|
|
1071
1172
|
m = Fsum._pow
|
|
@@ -1075,24 +1176,22 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1075
1176
|
p = s = int(p)
|
|
1076
1177
|
m = Fsum._pow_int
|
|
1077
1178
|
else:
|
|
1078
|
-
p = s = _2float(power=p)
|
|
1179
|
+
p = s = _2float(power=p, **self._isfine)
|
|
1079
1180
|
m = Fsum._pow_scalar
|
|
1080
1181
|
return m, p, s, r
|
|
1081
1182
|
|
|
1082
1183
|
_Pow, p, s, r = _Pow4(power)
|
|
1083
1184
|
if p: # and xs:
|
|
1084
1185
|
op = which.__name__
|
|
1085
|
-
|
|
1086
|
-
_Fs = Fsum
|
|
1087
|
-
_isa = isinstance
|
|
1186
|
+
_FsT = _Fsum_2Tuple_types
|
|
1088
1187
|
_pow = self._pow_2_3
|
|
1089
1188
|
|
|
1090
1189
|
def _P(X):
|
|
1091
1190
|
f = _Pow(X, p, power, op, **raiser_RESIDUAL)
|
|
1092
|
-
return f._ps if
|
|
1191
|
+
return f._ps if isinstance(f, _FsT) else (f,)
|
|
1093
1192
|
|
|
1094
1193
|
def _p(x):
|
|
1095
|
-
x =
|
|
1194
|
+
x = float(x)
|
|
1096
1195
|
f = _pow(x, s, power, op, **raiser_RESIDUAL)
|
|
1097
1196
|
if f and r:
|
|
1098
1197
|
f *= _pow(x, r, power, op, **raiser_RESIDUAL)
|
|
@@ -1104,18 +1203,27 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1104
1203
|
return f
|
|
1105
1204
|
|
|
1106
1205
|
def _facc_scalar(self, xs, **up):
|
|
1107
|
-
'''(INTERNAL) Accumulate all C{xs},
|
|
1206
|
+
'''(INTERNAL) Accumulate all C{xs}, each C{scalar}.
|
|
1108
1207
|
'''
|
|
1109
1208
|
if xs:
|
|
1110
1209
|
_ = self._ps_acc(self._ps, xs, **up)
|
|
1111
1210
|
return self
|
|
1112
1211
|
|
|
1113
1212
|
def _facc_scalar_(self, *xs, **up):
|
|
1114
|
-
'''(INTERNAL) Accumulate all positional C{xs},
|
|
1213
|
+
'''(INTERNAL) Accumulate all positional C{xs}, each C{scalar}.
|
|
1115
1214
|
'''
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1215
|
+
return self._facc_scalar(xs, **up)
|
|
1216
|
+
|
|
1217
|
+
def _facc_scalarf(self, xs, **origin_which):
|
|
1218
|
+
'''(INTERNAL) Accumulate all C{xs}, each C{scalar}, an L{Fsum} or
|
|
1219
|
+
L{Fsum2Tuple}, like function C{_xsum}.
|
|
1220
|
+
'''
|
|
1221
|
+
i_x = [0, xs]
|
|
1222
|
+
try:
|
|
1223
|
+
nf = self.nonfinitesOK
|
|
1224
|
+
return self._facc_scalar(_xs(xs, i_x, nf))
|
|
1225
|
+
except (OverflowError, TypeError, ValueError) as X:
|
|
1226
|
+
raise _ixError(X, xs, *i_x, **origin_which)
|
|
1119
1227
|
|
|
1120
1228
|
# def _facc_up(self, up=True):
|
|
1121
1229
|
# '''(INTERNAL) Update the C{partials}, by removing
|
|
@@ -1143,12 +1251,13 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1143
1251
|
|
|
1144
1252
|
@raise TypeError: An invalid B{C{xs}} item.
|
|
1145
1253
|
|
|
1146
|
-
@raise ValueError: Invalid or non-finite B{C{xs}} value.
|
|
1254
|
+
@raise ValueError: Invalid or I{non-finite} B{C{xs}} value.
|
|
1147
1255
|
'''
|
|
1148
|
-
if
|
|
1256
|
+
if _isFsum_2Tuple(xs):
|
|
1149
1257
|
self._facc_scalar(xs._ps)
|
|
1150
|
-
elif isscalar(xs):
|
|
1151
|
-
|
|
1258
|
+
elif isscalar(xs): # for backward compatibility # PYCHOK no cover
|
|
1259
|
+
x = _2float(x=xs, **self._isfine)
|
|
1260
|
+
self._facc_scalar_(x)
|
|
1152
1261
|
elif xs: # _xiterable(xs)
|
|
1153
1262
|
self._facc(xs)
|
|
1154
1263
|
return self
|
|
@@ -1161,17 +1270,21 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1161
1270
|
|
|
1162
1271
|
@see: Method L{Fsum.fadd} for further details.
|
|
1163
1272
|
'''
|
|
1164
|
-
return self.
|
|
1273
|
+
return self._facc_args(xs)
|
|
1165
1274
|
|
|
1166
1275
|
def _fadd(self, other, op, **up): # in .fmath.Fhorner
|
|
1167
1276
|
'''(INTERNAL) Apply C{B{self} += B{other}}.
|
|
1168
1277
|
'''
|
|
1169
|
-
if
|
|
1170
|
-
self.
|
|
1171
|
-
|
|
1172
|
-
|
|
1278
|
+
if _isFsum_2Tuple(other):
|
|
1279
|
+
if self._ps:
|
|
1280
|
+
self._facc_scalar(other._ps, **up)
|
|
1281
|
+
else:
|
|
1282
|
+
self._fset(other, op=op, **up)
|
|
1173
1283
|
elif self._scalar(other, op):
|
|
1174
|
-
self.
|
|
1284
|
+
if self._ps:
|
|
1285
|
+
self._facc_scalar_(other, **up)
|
|
1286
|
+
else:
|
|
1287
|
+
self._fset(other, op=op, **up)
|
|
1175
1288
|
return self
|
|
1176
1289
|
|
|
1177
1290
|
fcopy = copy # for backward compatibility
|
|
@@ -1186,7 +1299,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1186
1299
|
# but at least divmod(-3, 2) equals Cpython's result (-2, 1).
|
|
1187
1300
|
q = self._truediv(other, op, **raiser_RESIDUAL).floor
|
|
1188
1301
|
if q: # == float // other == floor(float / other)
|
|
1189
|
-
self -=
|
|
1302
|
+
self -= self._Fsum_as(q) * other # NOT other * q!
|
|
1190
1303
|
|
|
1191
1304
|
s = signOf(other) # make signOf(self) == signOf(other)
|
|
1192
1305
|
if s and self.signOf() == -s: # PYCHOK no cover
|
|
@@ -1203,12 +1316,12 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1203
1316
|
else sum(... i=len(cs)-1..0)}.
|
|
1204
1317
|
'''
|
|
1205
1318
|
if _xiterablen(cs):
|
|
1206
|
-
H =
|
|
1207
|
-
if
|
|
1319
|
+
H = self._Fsum_as(name__=self._fhorner)
|
|
1320
|
+
if _isFsum_2Tuple(x):
|
|
1208
1321
|
_mul = H._mul_Fsum
|
|
1209
1322
|
else:
|
|
1210
1323
|
_mul = H._mul_scalar
|
|
1211
|
-
x = _2float(x=x)
|
|
1324
|
+
x = _2float(x=x, **self._isfine)
|
|
1212
1325
|
if len(cs) > 1 and x:
|
|
1213
1326
|
for c in (reversed(cs) if incx else cs):
|
|
1214
1327
|
H._fset_ps(_mul(x, op))
|
|
@@ -1221,10 +1334,10 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1221
1334
|
def _finite(self, other, op=None):
|
|
1222
1335
|
'''(INTERNAL) Return B{C{other}} if C{finite}.
|
|
1223
1336
|
'''
|
|
1224
|
-
if
|
|
1337
|
+
if _isOK_or_finite(other, **self._isfine):
|
|
1225
1338
|
return other
|
|
1226
|
-
|
|
1227
|
-
|
|
1339
|
+
E = _NonfiniteError(other)
|
|
1340
|
+
raise self._Error(op, other, E, txt=_not_finite_)
|
|
1228
1341
|
|
|
1229
1342
|
def fint(self, name=NN, **raiser_RESIDUAL):
|
|
1230
1343
|
'''Return this instance' current running sum as C{integer}.
|
|
@@ -1248,7 +1361,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1248
1361
|
if R:
|
|
1249
1362
|
t = _stresidual(_integer_, r, **R)
|
|
1250
1363
|
raise ResidualError(_integer_, i, txt=t)
|
|
1251
|
-
return
|
|
1364
|
+
return self._Fsum_as(i, name=_name__(name, name__=self.fint))
|
|
1252
1365
|
|
|
1253
1366
|
def fint2(self, **name):
|
|
1254
1367
|
'''Return this instance' current running sum as C{int} and the
|
|
@@ -1259,6 +1372,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1259
1372
|
@return: An L{Fsum2Tuple}C{(fsum, residual)} with C{fsum}
|
|
1260
1373
|
an C{int} and I{integer} C{residual} a C{float} or
|
|
1261
1374
|
C{INT0} if the C{fsum} is considered to be I{exact}.
|
|
1375
|
+
The C{fsum} is I{non-finite} if this instance is.
|
|
1262
1376
|
'''
|
|
1263
1377
|
return Fsum2Tuple(*self._fint2, **name)
|
|
1264
1378
|
|
|
@@ -1266,18 +1380,35 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1266
1380
|
def _fint2(self): # see ._fset
|
|
1267
1381
|
'''(INTERNAL) Get 2-tuple (C{int}, I{integer} residual).
|
|
1268
1382
|
'''
|
|
1269
|
-
s,
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1383
|
+
s, _ = self._fprs2
|
|
1384
|
+
try:
|
|
1385
|
+
i = int(s)
|
|
1386
|
+
r = (self._ps_1sum(i) if len(self._ps) > 1 else
|
|
1387
|
+
float(s - i)) or INT0
|
|
1388
|
+
except (OverflowError, ValueError) as X:
|
|
1389
|
+
r = _NONFINITEr # INF, NAN, NINF
|
|
1390
|
+
i = self._fintX(X, sum(self._ps))
|
|
1391
|
+
return i, r # Fsum2Tuple?
|
|
1392
|
+
|
|
1393
|
+
@_fint2.setter_ # PYCHOK setter_UNDERscore!
|
|
1394
|
+
def _fint2(self, s): # in _fset
|
|
1277
1395
|
'''(INTERNAL) Replace the C{_fint2} value.
|
|
1278
1396
|
'''
|
|
1279
|
-
|
|
1280
|
-
|
|
1397
|
+
try:
|
|
1398
|
+
i = int(s)
|
|
1399
|
+
r = (s - i) or INT0
|
|
1400
|
+
except (OverflowError, ValueError) as X:
|
|
1401
|
+
r = _NONFINITEr # INF, NAN, NINF
|
|
1402
|
+
i = self._fintX(X, float(s))
|
|
1403
|
+
return i, r # like _fint2.getter
|
|
1404
|
+
|
|
1405
|
+
def _fintX(self, X, i): # PYCHOK X
|
|
1406
|
+
'''(INTERNAL) Handle I{non-finite} C{int}.
|
|
1407
|
+
'''
|
|
1408
|
+
# "cannot convert float infinity to integer"
|
|
1409
|
+
return i # ignore such Overflow-/ValueErrors
|
|
1410
|
+
# op = int.__name__
|
|
1411
|
+
# return self._nonfiniteX(X, op, i)
|
|
1281
1412
|
|
|
1282
1413
|
@deprecated_property_RO
|
|
1283
1414
|
def float_int(self): # PYCHOK no cover
|
|
@@ -1300,8 +1431,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1300
1431
|
f -= 1
|
|
1301
1432
|
return f # _floor(self._n_d)
|
|
1302
1433
|
|
|
1303
|
-
# ffloordiv = __ifloordiv__ # for naming consistency
|
|
1304
|
-
# floordiv = __floordiv__ # for naming consistency
|
|
1434
|
+
# ffloordiv = __ifloordiv__ # for naming consistency?
|
|
1435
|
+
# floordiv = __floordiv__ # for naming consistency?
|
|
1305
1436
|
|
|
1306
1437
|
def _floordiv(self, other, op, **raiser_RESIDUAL): # rather _ffloordiv?
|
|
1307
1438
|
'''Apply C{B{self} //= B{other}}.
|
|
@@ -1309,79 +1440,94 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1309
1440
|
q = self._ftruediv(other, op, **raiser_RESIDUAL) # == self
|
|
1310
1441
|
return self._fset(q.floor) # floor(q)
|
|
1311
1442
|
|
|
1312
|
-
def fma(self, other1, other2): #
|
|
1443
|
+
def fma(self, other1, other2, **nonfinites): # in .fmath.fma
|
|
1313
1444
|
'''Fused-multiply-add C{self *= B{other1}; self += B{other2}}.
|
|
1314
1445
|
|
|
1315
|
-
@arg other1:
|
|
1316
|
-
@arg other2:
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1446
|
+
@arg other1: Multiplier (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
|
|
1447
|
+
@arg other2: Addend (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
|
|
1448
|
+
@kwarg nonfinites: Use C{B{nonfinites}=True} or C{False}, to
|
|
1449
|
+
override L{nonfinites<Fsum.nonfinites>} and
|
|
1450
|
+
L{nonfiniterrors} default (C{bool}).
|
|
1320
1451
|
'''
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
if
|
|
1326
|
-
self.
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
#
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
# ps[:] = self._ps_acc(list(y), _2products(x, _2split3s(ps)))
|
|
1340
|
-
# for p in (ps if op else()):
|
|
1341
|
-
# self._finite(p, op)
|
|
1342
|
-
# return self
|
|
1452
|
+
op = self.fma.__name__
|
|
1453
|
+
_fs = self._ps_other
|
|
1454
|
+
try:
|
|
1455
|
+
s, r = self._fprs2
|
|
1456
|
+
if r:
|
|
1457
|
+
f = self._f2mul(self.fma, other1, **nonfinites)
|
|
1458
|
+
f += other2
|
|
1459
|
+
else:
|
|
1460
|
+
fs = _2split3s(_fs(op, other1))
|
|
1461
|
+
fs = _2products(s, fs, *_fs(op, other2))
|
|
1462
|
+
f = _Psum(self._ps_acc([], fs, up=False), name=op)
|
|
1463
|
+
except TypeError as X:
|
|
1464
|
+
raise self._ErrorX(X, op, (other1, other2))
|
|
1465
|
+
except (OverflowError, ValueError) as X: # from math.fma
|
|
1466
|
+
f = self._mul_reduce(op, s, other1) # INF, NAN, NINF
|
|
1467
|
+
f = sum(_fs(op, f, other2))
|
|
1468
|
+
f = self._nonfiniteX(X, op, f, **nonfinites)
|
|
1469
|
+
return self._fset(f)
|
|
1343
1470
|
|
|
1344
1471
|
fmul = __imul__
|
|
1345
1472
|
|
|
1346
1473
|
def _fmul(self, other, op):
|
|
1347
1474
|
'''(INTERNAL) Apply C{B{self} *= B{other}}.
|
|
1348
1475
|
'''
|
|
1349
|
-
if
|
|
1476
|
+
if _isFsum_2Tuple(other):
|
|
1350
1477
|
if len(self._ps) != 1:
|
|
1351
1478
|
f = self._mul_Fsum(other, op)
|
|
1352
1479
|
elif len(other._ps) != 1: # and len(self._ps) == 1
|
|
1353
|
-
f =
|
|
1480
|
+
f = self._ps_mul(op, *other._ps) if other._ps else _0_0
|
|
1354
1481
|
elif self._f2product: # len(other._ps) == 1
|
|
1355
1482
|
f = self._mul_scalar(other._ps[0], op)
|
|
1356
1483
|
else: # len(other._ps) == len(self._ps) == 1
|
|
1357
|
-
f = self._finite(self._ps[0] * other._ps[0])
|
|
1484
|
+
f = self._finite(self._ps[0] * other._ps[0], op=op)
|
|
1358
1485
|
else:
|
|
1359
1486
|
s = self._scalar(other, op)
|
|
1360
1487
|
f = self._mul_scalar(s, op)
|
|
1361
1488
|
return self._fset(f) # n=len(self) + 1
|
|
1362
1489
|
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1490
|
+
@deprecated_method
|
|
1491
|
+
def f2mul(self, *others, **raiser):
|
|
1492
|
+
'''DEPRECATED on 2024.09.13, use method L{f2mul_<Fsum.f2mul_>}.'''
|
|
1493
|
+
return self._fset(self.f2mul_(*others, **raiser))
|
|
1494
|
+
|
|
1495
|
+
def f2mul_(self, *others, **nonfinites): # in .fmath.f2mul
|
|
1496
|
+
'''Return C{B{self} * B{other} * B{other} ...} for all B{C{others}} using cascaded,
|
|
1497
|
+
accurate multiplication like with L{f2product<Fsum.f2product>} set to C{True}.
|
|
1498
|
+
|
|
1499
|
+
@arg others: Multipliers (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}), all
|
|
1500
|
+
positional.
|
|
1501
|
+
@kwarg nonfinites: Use C{B{nonfinites}=True} or C{False}, to override both
|
|
1502
|
+
L{nonfinites<Fsum.nonfinites>} and the L{nonfiniterrors}
|
|
1503
|
+
default (C{bool}).
|
|
1504
|
+
|
|
1505
|
+
@return: The cascaded I{TwoProduct} (L{Fsum} or C{float}).
|
|
1367
1506
|
|
|
1368
1507
|
@see: U{Equations 2.3<https://www.TUHH.De/ti3/paper/rump/OzOgRuOi06.pdf>}
|
|
1369
1508
|
'''
|
|
1370
|
-
return self._f2mul(self.
|
|
1509
|
+
return self._f2mul(self.f2mul_, *others, **nonfinites)
|
|
1371
1510
|
|
|
1372
|
-
def _f2mul(self,
|
|
1373
|
-
'''(INTERNAL) See
|
|
1511
|
+
def _f2mul(self, where, *others, **nonfinites_raiser):
|
|
1512
|
+
'''(INTERNAL) See methods C{fma} and C{f2mul_}.
|
|
1374
1513
|
'''
|
|
1375
|
-
|
|
1376
|
-
ps =
|
|
1514
|
+
f = self._copy_2(where)
|
|
1515
|
+
ps = f._ps
|
|
1377
1516
|
if ps and others:
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1517
|
+
op = where.__name__
|
|
1518
|
+
try:
|
|
1519
|
+
for other in others: # to pinpoint errors
|
|
1520
|
+
for p in self._ps_other(op, other):
|
|
1521
|
+
pfs = _2products(p, _2split3s(ps))
|
|
1522
|
+
ps[:] = f._ps_acc([], pfs, up=False)
|
|
1523
|
+
f._update()
|
|
1524
|
+
except TypeError as X:
|
|
1525
|
+
raise self._ErrorX(X, op, other)
|
|
1526
|
+
except (OverflowError, ValueError) as X:
|
|
1527
|
+
r = self._mul_reduce(op, sum(ps), other) # INF, NAN, NINF
|
|
1528
|
+
r = self._nonfiniteX(X, op, r, **nonfinites_raiser)
|
|
1529
|
+
f._fset(r)
|
|
1530
|
+
return f
|
|
1385
1531
|
|
|
1386
1532
|
def fover(self, over, **raiser_RESIDUAL):
|
|
1387
1533
|
'''Apply C{B{self} /= B{over}} and summate.
|
|
@@ -1410,32 +1556,37 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1410
1556
|
f = self._pow_2_3(self, other, other, op, *mod, **raiser_RESIDUAL)
|
|
1411
1557
|
elif self.is_integer():
|
|
1412
1558
|
# return an exact C{int} for C{int}**C{int}
|
|
1413
|
-
i, _ =
|
|
1559
|
+
i, _ = self._fint2 # assert _ == 0
|
|
1414
1560
|
x, r = _2scalar2(other) # C{int}, C{float} or other
|
|
1415
|
-
f =
|
|
1416
|
-
self._pow_2_3(i, x,
|
|
1561
|
+
f = self._Fsum_as(i)._pow_Fsum(other, op, **raiser_RESIDUAL) if r else \
|
|
1562
|
+
self._pow_2_3(i, x, other, op, **raiser_RESIDUAL)
|
|
1417
1563
|
else: # mod[0] is None, power(self, other)
|
|
1418
|
-
f =
|
|
1564
|
+
f = self._pow(other, other, op, **raiser_RESIDUAL)
|
|
1419
1565
|
else: # pow(self, other)
|
|
1420
1566
|
f = self._pow(other, other, op, **raiser_RESIDUAL)
|
|
1421
1567
|
return self._fset(f) # n=max(len(self), 1)
|
|
1422
1568
|
|
|
1423
1569
|
def f2product(self, *two):
|
|
1424
|
-
'''
|
|
1570
|
+
'''Get and set accurate I{TwoProduct} multiplication for this
|
|
1571
|
+
L{Fsum}, overriding the L{f2product} default.
|
|
1572
|
+
|
|
1573
|
+
@arg two: If omitted, leave the override unchanged, if C{True},
|
|
1574
|
+
turn I{TwoProduct} on, if C{False} off, if C{None}e
|
|
1575
|
+
remove th override (C{bool} or C{None}).
|
|
1425
1576
|
|
|
1426
|
-
@
|
|
1427
|
-
C{None} or if omitted, keep the current setting.
|
|
1577
|
+
@return: The previous setting (C{bool} or C{None} if not set).
|
|
1428
1578
|
|
|
1429
|
-
@
|
|
1579
|
+
@see: Function L{f2product<fsums.f2product>}.
|
|
1430
1580
|
|
|
1431
|
-
@
|
|
1432
|
-
|
|
1433
|
-
otherwise on the slower I{TwoProduct} and I{Split} U{Algorithms
|
|
1434
|
-
3.3 and 3.2<https://www.TUHH.De/ti3/paper/rump/OgRuOi05.pdf>}.
|
|
1581
|
+
@note: Use C{f.f2product() or f2product()} to determine whether
|
|
1582
|
+
multiplication is accurate for L{Fsum} C{f}.
|
|
1435
1583
|
'''
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1584
|
+
if two: # delattrof(self, _f2product=None)
|
|
1585
|
+
t = _xkwds_pop(self.__dict__, _f2product=None)
|
|
1586
|
+
if two[0] is not None:
|
|
1587
|
+
self._f2product = bool(two[0])
|
|
1588
|
+
else: # getattrof(self, _f2product=None)
|
|
1589
|
+
t = _xkwds_get(self.__dict__, _f2product=None)
|
|
1439
1590
|
return t
|
|
1440
1591
|
|
|
1441
1592
|
@Property
|
|
@@ -1449,7 +1600,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1449
1600
|
s, _ = self._fprs2
|
|
1450
1601
|
return s # ._fprs2.fsum
|
|
1451
1602
|
|
|
1452
|
-
@_fprs.setter_ # PYCHOK
|
|
1603
|
+
@_fprs.setter_ # PYCHOK setter_UNDERscore!
|
|
1453
1604
|
def _fprs(self, s):
|
|
1454
1605
|
'''(INTERNAL) Replace the C{_fprs} value.
|
|
1455
1606
|
'''
|
|
@@ -1461,54 +1612,63 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1461
1612
|
running sum and residual (L{Fsum2Tuple}).
|
|
1462
1613
|
'''
|
|
1463
1614
|
ps = self._ps
|
|
1464
|
-
n = len(ps)
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1615
|
+
n = len(ps)
|
|
1616
|
+
try:
|
|
1617
|
+
if n > 2:
|
|
1618
|
+
s = _psum(ps, **self._isfine)
|
|
1619
|
+
if not _isfinite(s):
|
|
1620
|
+
ps[:] = s, # collapse ps
|
|
1621
|
+
return Fsum2Tuple(s, _NONFINITEr)
|
|
1622
|
+
n = len(ps)
|
|
1623
|
+
# Fsum._ps_max = max(Fsum._ps_max, n)
|
|
1624
|
+
if n > 2:
|
|
1625
|
+
r = self._ps_1sum(s)
|
|
1626
|
+
return Fsum2Tuple(*_s_r(s, r))
|
|
1627
|
+
if n > 1: # len(ps) == 2
|
|
1628
|
+
s, r = _s_r(*_2sum(*ps, **self._isfine))
|
|
1629
|
+
ps[:] = (r, s) if r else (s,)
|
|
1630
|
+
elif ps: # len(ps) == 1
|
|
1631
|
+
s = ps[0]
|
|
1632
|
+
r = INT0 if _isfinite(s) else _NONFINITEr
|
|
1633
|
+
else: # len(ps) == 0
|
|
1634
|
+
s, r = _0_0, INT0
|
|
1635
|
+
ps[:] = s,
|
|
1636
|
+
except (OverflowError, ValueError) as X:
|
|
1637
|
+
op = sum.__name__ # INF, NAN, NINF
|
|
1638
|
+
ps[:] = sum(ps), # collapse ps
|
|
1639
|
+
s = self._nonfiniteX(X, op, ps[0])
|
|
1640
|
+
r = _NONFINITEr
|
|
1479
1641
|
# assert self._ps is ps
|
|
1480
1642
|
return Fsum2Tuple(s, r)
|
|
1481
1643
|
|
|
1482
|
-
@_fprs2.setter_ # PYCHOK
|
|
1644
|
+
@_fprs2.setter_ # PYCHOK setter_UNDERscore!
|
|
1483
1645
|
def _fprs2(self, s_r):
|
|
1484
1646
|
'''(INTERNAL) Replace the C{_fprs2} value.
|
|
1485
1647
|
'''
|
|
1486
1648
|
return Fsum2Tuple(s_r)
|
|
1487
1649
|
|
|
1488
1650
|
def fset_(self, *xs):
|
|
1489
|
-
'''
|
|
1651
|
+
'''Apply C{B{self}.partials = Fsum(*B{xs}).partials}.
|
|
1490
1652
|
|
|
1491
1653
|
@arg xs: Optional, new values (each C{scalar} or
|
|
1492
|
-
an L{Fsum} or L{Fsum2Tuple} instance),
|
|
1493
|
-
|
|
1654
|
+
an L{Fsum} or L{Fsum2Tuple} instance), all
|
|
1655
|
+
positional.
|
|
1494
1656
|
|
|
1495
1657
|
@return: This instance, replaced (C{Fsum}).
|
|
1496
1658
|
|
|
1497
1659
|
@see: Method L{Fsum.fadd} for further details.
|
|
1498
1660
|
'''
|
|
1499
|
-
f =
|
|
1500
|
-
|
|
1501
|
-
return self._fset(f)
|
|
1661
|
+
f = self._Fsum_as(*xs)
|
|
1662
|
+
return self._fset(f, up=False, op=_fset_op_)
|
|
1502
1663
|
|
|
1503
1664
|
def _fset(self, other, n=0, up=True, **op):
|
|
1504
1665
|
'''(INTERNAL) Overwrite this instance with an other or a C{scalar}.
|
|
1505
1666
|
'''
|
|
1506
1667
|
if other is self:
|
|
1507
1668
|
pass # from ._fmul, ._ftruediv and ._pow_0_1
|
|
1508
|
-
elif
|
|
1669
|
+
elif _isFsum_2Tuple(other):
|
|
1509
1670
|
self._ps[:] = other._ps
|
|
1510
1671
|
self._n = n or other._n
|
|
1511
|
-
# self._copy_RESIDUAL(other)
|
|
1512
1672
|
if up: # use or zap the C{Property_RO} values
|
|
1513
1673
|
Fsum._fint2._update_from(self, other)
|
|
1514
1674
|
Fsum._fprs ._update_from(self, other)
|
|
@@ -1524,13 +1684,13 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1524
1684
|
self._fprs = s
|
|
1525
1685
|
self._fprs2 = s, INT0
|
|
1526
1686
|
# assert self._fprs is s
|
|
1527
|
-
else:
|
|
1687
|
+
else:
|
|
1528
1688
|
op = _xkwds_get1(op, op=_fset_op_)
|
|
1529
1689
|
raise self._Error(op, other, _TypeError)
|
|
1530
1690
|
return self
|
|
1531
1691
|
|
|
1532
|
-
def _fset_ps(self, other): # in .fmath
|
|
1533
|
-
'''(INTERNAL) Set partials from a known C{
|
|
1692
|
+
def _fset_ps(self, other): # in .fmath._Fsum__init__
|
|
1693
|
+
'''(INTERNAL) Set partials from a known C{other}.
|
|
1534
1694
|
'''
|
|
1535
1695
|
return self._fset(other, up=False)
|
|
1536
1696
|
|
|
@@ -1546,13 +1706,13 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1546
1706
|
|
|
1547
1707
|
@see: Method L{Fsum.fadd_} for further details.
|
|
1548
1708
|
'''
|
|
1549
|
-
return self.
|
|
1550
|
-
self.
|
|
1709
|
+
return self._facc_neg(xs, origin=1) if len(xs) != 1 else \
|
|
1710
|
+
self._fsub(xs[0], _sub_op_)
|
|
1551
1711
|
|
|
1552
1712
|
def _fsub(self, other, op):
|
|
1553
1713
|
'''(INTERNAL) Apply C{B{self} -= B{other}}.
|
|
1554
1714
|
'''
|
|
1555
|
-
if
|
|
1715
|
+
if _isFsum_2Tuple(other):
|
|
1556
1716
|
if other is self: # or other._fprs2 == self._fprs2:
|
|
1557
1717
|
self._fset(_0_0, n=len(self) * 2)
|
|
1558
1718
|
elif other._ps:
|
|
@@ -1562,8 +1722,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1562
1722
|
return self
|
|
1563
1723
|
|
|
1564
1724
|
def fsum(self, xs=()):
|
|
1565
|
-
'''Add an iterable's items, summate and return the
|
|
1566
|
-
|
|
1725
|
+
'''Add an iterable's items, summate and return the current
|
|
1726
|
+
precision running sum.
|
|
1567
1727
|
|
|
1568
1728
|
@arg xs: Iterable of items to add (each item C{scalar}
|
|
1569
1729
|
or an L{Fsum} or L{Fsum2Tuple} instance).
|
|
@@ -1577,8 +1737,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1577
1737
|
return self._facc(xs)._fprs
|
|
1578
1738
|
|
|
1579
1739
|
def fsum_(self, *xs):
|
|
1580
|
-
'''Add any positional items, summate and return the
|
|
1581
|
-
|
|
1740
|
+
'''Add any positional items, summate and return the current
|
|
1741
|
+
precision running sum.
|
|
1582
1742
|
|
|
1583
1743
|
@arg xs: Items to add (each C{scalar} or an L{Fsum}
|
|
1584
1744
|
or L{Fsum2Tuple} instance), all positional.
|
|
@@ -1587,11 +1747,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1587
1747
|
|
|
1588
1748
|
@see: Methods L{Fsum.fsum}, L{Fsum.Fsum_} and L{Fsum.fsumf_}.
|
|
1589
1749
|
'''
|
|
1590
|
-
return self.
|
|
1591
|
-
|
|
1592
|
-
@property_RO
|
|
1593
|
-
def _Fsum(self): # like L{Fsum2Tuple._Fsum}, for C{_2floats}, .fstats
|
|
1594
|
-
return self # NOT @Property_RO, see .copy and ._copy_2
|
|
1750
|
+
return self._facc_args(xs)._fprs
|
|
1595
1751
|
|
|
1596
1752
|
def Fsum_(self, *xs, **name):
|
|
1597
1753
|
'''Like method L{Fsum.fsum_} but returning a named L{Fsum}.
|
|
@@ -1600,7 +1756,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1600
1756
|
|
|
1601
1757
|
@return: Copy of this updated instance (L{Fsum}).
|
|
1602
1758
|
'''
|
|
1603
|
-
return self.
|
|
1759
|
+
return self._facc_args(xs)._copy_2(self.Fsum_, **name)
|
|
1604
1760
|
|
|
1605
1761
|
def Fsum2Tuple_(self, *xs, **name):
|
|
1606
1762
|
'''Like method L{Fsum.fsum_} but returning a named L{Fsum2Tuple}.
|
|
@@ -1609,7 +1765,27 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1609
1765
|
|
|
1610
1766
|
@return: Precision running sum (L{Fsum2Tuple}).
|
|
1611
1767
|
'''
|
|
1612
|
-
return Fsum2Tuple(self.
|
|
1768
|
+
return Fsum2Tuple(self._facc_args(xs)._fprs2, **name)
|
|
1769
|
+
|
|
1770
|
+
@property_RO
|
|
1771
|
+
def _Fsum(self): # like L{Fsum2Tuple._Fsum}, for C{_2floats}, .fstats
|
|
1772
|
+
return self # NOT @Property_RO, see .copy and ._copy_2
|
|
1773
|
+
|
|
1774
|
+
def _Fsum_as(self, *xs, **name_f2product_nonfinites_RESIDUAL):
|
|
1775
|
+
'''(INTERNAL) Return an C{Fsum} with this C{Fsum}'s C{.f2product},
|
|
1776
|
+
C{.nonfinites} and C{.RESIDUAL} setting, optionally
|
|
1777
|
+
overridden with C{name_f2product_nonfinites_RESIDUAL} and
|
|
1778
|
+
with any C{xs} accumulated.
|
|
1779
|
+
'''
|
|
1780
|
+
kwds = _xkwds_not(None, Fsum._RESIDUAL, f2product =self.f2product(),
|
|
1781
|
+
nonfinites=self.nonfinites(),
|
|
1782
|
+
RESIDUAL =self.RESIDUAL())
|
|
1783
|
+
if name_f2product_nonfinites_RESIDUAL: # overwrites
|
|
1784
|
+
kwds.update(name_f2product_nonfinites_RESIDUAL)
|
|
1785
|
+
F = Fsum(**kwds)
|
|
1786
|
+
# assert all(v == self.__dict__[n] for n, v in F.__dict__.items())
|
|
1787
|
+
return F._fset(xs[0], op=_fset_op_) if len(xs) == 1 else (
|
|
1788
|
+
F._facc(xs, up=False) if xs else F)
|
|
1613
1789
|
|
|
1614
1790
|
def fsum2(self, xs=(), **name):
|
|
1615
1791
|
'''Add an iterable's items, summate and return the
|
|
@@ -1643,32 +1819,38 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1643
1819
|
|
|
1644
1820
|
@see: Methods L{Fsum.fsum_} and L{Fsum.fsum}.
|
|
1645
1821
|
'''
|
|
1646
|
-
return self._fsum2(xs, self.
|
|
1822
|
+
return self._fsum2(xs, self._facc_args)
|
|
1647
1823
|
|
|
1648
|
-
def _fsum2(self, xs, _facc, **
|
|
1824
|
+
def _fsum2(self, xs, _facc, **facc_kwds):
|
|
1649
1825
|
'''(INTERNAL) Helper for L{Fsum.fsum2_} and L{Fsum.fsum2f_}.
|
|
1650
1826
|
'''
|
|
1651
1827
|
p, q = self._fprs2
|
|
1652
1828
|
if xs:
|
|
1653
|
-
s, r = _facc(xs, **
|
|
1654
|
-
|
|
1829
|
+
s, r = _facc(xs, **facc_kwds)._fprs2
|
|
1830
|
+
if _isfinite(s): # _fsum(_1primed((s, -p, r, -q))
|
|
1831
|
+
d, r = _2sum(s - p, r - q, _isfine=_isOK)
|
|
1832
|
+
r, _ = _s_r(d, r)
|
|
1833
|
+
return s, (r if _isfinite(r) else _NONFINITEr)
|
|
1655
1834
|
else:
|
|
1656
1835
|
return p, _0_0
|
|
1657
1836
|
|
|
1658
1837
|
def fsumf_(self, *xs):
|
|
1659
|
-
'''Like method L{Fsum.fsum_} iff I{all} C{B{xs}}
|
|
1838
|
+
'''Like method L{Fsum.fsum_} iff I{all} C{B{xs}}, each I{known to be}
|
|
1839
|
+
C{scalar}, an L{Fsum} or L{Fsum2Tuple}.
|
|
1660
1840
|
'''
|
|
1661
|
-
return self.
|
|
1841
|
+
return self._facc_scalarf(xs, origin=1, which=self.fsumf_)._fprs
|
|
1662
1842
|
|
|
1663
1843
|
def Fsumf_(self, *xs):
|
|
1664
|
-
'''Like method L{Fsum.Fsum_} iff I{all} C{B{xs}}
|
|
1844
|
+
'''Like method L{Fsum.Fsum_} iff I{all} C{B{xs}}, each I{known to be}
|
|
1845
|
+
C{scalar}, an L{Fsum} or L{Fsum2Tuple}.
|
|
1665
1846
|
'''
|
|
1666
|
-
return self.
|
|
1847
|
+
return self._facc_scalarf(xs, origin=1, which=self.Fsumf_)._copy_2(self.Fsumf_)
|
|
1667
1848
|
|
|
1668
1849
|
def fsum2f_(self, *xs):
|
|
1669
|
-
'''Like method L{Fsum.fsum2_} iff I{all} C{B{xs}}
|
|
1850
|
+
'''Like method L{Fsum.fsum2_} iff I{all} C{B{xs}}, each I{known to be}
|
|
1851
|
+
C{scalar}, an L{Fsum} or L{Fsum2Tuple}.
|
|
1670
1852
|
'''
|
|
1671
|
-
return self._fsum2(xs, self.
|
|
1853
|
+
return self._fsum2(xs, self._facc_scalarf, origin=1, which=self.fsum2f_)
|
|
1672
1854
|
|
|
1673
1855
|
# ftruediv = __itruediv__ # for naming consistency?
|
|
1674
1856
|
|
|
@@ -1676,7 +1858,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1676
1858
|
'''(INTERNAL) Apply C{B{self} /= B{other}}.
|
|
1677
1859
|
'''
|
|
1678
1860
|
n = _1_0
|
|
1679
|
-
if
|
|
1861
|
+
if _isFsum_2Tuple(other):
|
|
1680
1862
|
if other is self or self == other:
|
|
1681
1863
|
return self._fset(n, n=len(self))
|
|
1682
1864
|
d, r = other._fprs2
|
|
@@ -1709,15 +1891,14 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1709
1891
|
L{ResidualError}s (C{bool}) and C{B{RESIDUAL}=scalar}
|
|
1710
1892
|
to override the current L{RESIDUAL<Fsum.RESIDUAL>}.
|
|
1711
1893
|
|
|
1712
|
-
@return: This C{
|
|
1713
|
-
|
|
1714
|
-
zero or not significant.
|
|
1894
|
+
@return: This C{int} sum if this instance C{is_integer}, otherwise
|
|
1895
|
+
the C{float} sum if the residual is zero or not significant.
|
|
1715
1896
|
|
|
1716
1897
|
@raise ResidualError: Non-zero, significant residual or invalid
|
|
1717
1898
|
B{C{RESIDUAL}}.
|
|
1718
1899
|
|
|
1719
|
-
@see: Methods L{Fsum.fint}, L{Fsum.fint2}, L{Fsum.
|
|
1720
|
-
property L{Fsum.as_iscalar}.
|
|
1900
|
+
@see: Methods L{Fsum.fint}, L{Fsum.fint2}, L{Fsum.is_integer},
|
|
1901
|
+
L{Fsum.RESIDUAL} and property L{Fsum.as_iscalar}.
|
|
1721
1902
|
'''
|
|
1722
1903
|
s, r = self._fint2
|
|
1723
1904
|
if r:
|
|
@@ -1736,27 +1917,38 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1736
1917
|
'''
|
|
1737
1918
|
return self.residual is INT0
|
|
1738
1919
|
|
|
1920
|
+
def is_finite(self): # in .constants
|
|
1921
|
+
'''Is this instance C{finite}? (C{bool}).
|
|
1922
|
+
|
|
1923
|
+
@see: Function L{isfinite<pygeodesy.isfinite>}.
|
|
1924
|
+
'''
|
|
1925
|
+
return _isfinite(sum(self._ps)) # == sum(self)
|
|
1926
|
+
|
|
1739
1927
|
def is_integer(self):
|
|
1740
1928
|
'''Is this instance' running sum C{integer}? (C{bool}).
|
|
1741
1929
|
|
|
1742
1930
|
@see: Methods L{Fsum.fint}, L{Fsum.fint2} and L{Fsum.is_scalar}.
|
|
1743
1931
|
'''
|
|
1744
|
-
|
|
1745
|
-
return False if r else
|
|
1932
|
+
s, r = self._fint2
|
|
1933
|
+
return False if r else (_isfinite(s) and isint(s))
|
|
1934
|
+
|
|
1935
|
+
def is_math_fma(self):
|
|
1936
|
+
'''Is accurate L{f2product} multiplication based on Python's C{math.fma}?
|
|
1937
|
+
|
|
1938
|
+
@return: C{True} if accurate multiplication uses C{math.fma}, C{False}
|
|
1939
|
+
an C{fma} implementation as C{math.fma} or C{None}, a previous
|
|
1940
|
+
C{PyGeodesy} implementation.
|
|
1941
|
+
'''
|
|
1942
|
+
return (_2split3s is _passarg) or (False if _2n_d is None else None)
|
|
1746
1943
|
|
|
1747
1944
|
def is_math_fsum(self):
|
|
1748
|
-
'''
|
|
1749
|
-
L{fsum1_}
|
|
1750
|
-
C{math.fsum} or not.
|
|
1945
|
+
'''Are the summation functions L{fsum}, L{fsum_}, L{fsumf_}, L{fsum1},
|
|
1946
|
+
L{fsum1_} and L{fsum1f_} based on Python's C{math.fsum}?
|
|
1751
1947
|
|
|
1752
|
-
@return: C{
|
|
1753
|
-
|
|
1754
|
-
the functions are based on C{math.fsum} (and
|
|
1755
|
-
partials summation is not) or C{False} if
|
|
1756
|
-
none are.
|
|
1948
|
+
@return: C{True} if summation functions use C{math.fsum}, C{False}
|
|
1949
|
+
otherwise.
|
|
1757
1950
|
'''
|
|
1758
|
-
|
|
1759
|
-
return 2 if _psum is f else bool(f)
|
|
1951
|
+
return _sum is _fsum # _fsum.__module__ is fabs.__module__
|
|
1760
1952
|
|
|
1761
1953
|
def is_scalar(self, **raiser_RESIDUAL):
|
|
1762
1954
|
'''Is this instance' running sum C{scalar} without residual or with
|
|
@@ -1781,13 +1973,21 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1781
1973
|
def _mul_Fsum(self, other, op=_mul_op_): # in .fmath.Fhorner
|
|
1782
1974
|
'''(INTERNAL) Return C{B{self} * B{other}} as L{Fsum} or C{0}.
|
|
1783
1975
|
'''
|
|
1784
|
-
# assert
|
|
1976
|
+
# assert _isFsum_2Tuple(other)
|
|
1785
1977
|
if self._ps and other._ps:
|
|
1786
1978
|
f = self._ps_mul(op, *other._ps) # NO .as_iscalar!
|
|
1787
1979
|
else:
|
|
1788
1980
|
f = _0_0
|
|
1789
1981
|
return f
|
|
1790
1982
|
|
|
1983
|
+
def _mul_reduce(self, op, start, *others):
|
|
1984
|
+
'''(INTERNAL) Like fmath.freduce(_operator.mul, ...)
|
|
1985
|
+
for I{non-finite} C{start} and/or C{others}.
|
|
1986
|
+
'''
|
|
1987
|
+
for p in self._ps_other(op, *others):
|
|
1988
|
+
start *= p
|
|
1989
|
+
return start
|
|
1990
|
+
|
|
1791
1991
|
def _mul_scalar(self, factor, op): # in .fmath.Fhorner
|
|
1792
1992
|
'''(INTERNAL) Return C{B{self} * scalar B{factor}} as L{Fsum}, C{0.0} or C{self}.
|
|
1793
1993
|
'''
|
|
@@ -1811,6 +2011,79 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1811
2011
|
'''
|
|
1812
2012
|
return _Psum(self._ps_neg) if self._ps else NEG0
|
|
1813
2013
|
|
|
2014
|
+
def nonfinites(self, *OK):
|
|
2015
|
+
'''Handle I{non-finite} C{float}s as C{inf}, C{INF}, C{NINF}, C{nan}
|
|
2016
|
+
and C{NAN} for this L{Fsum} or throw C{OverflowError} respectively
|
|
2017
|
+
C{ValueError} exceptions, overriding the L{nonfiniterrors} default.
|
|
2018
|
+
|
|
2019
|
+
@arg OK: If omitted, leave the override unchanged, if C{True},
|
|
2020
|
+
I{non-finites} are C{OK}, if C{False} throw exceptions
|
|
2021
|
+
or if C{None} remove the override (C{bool} or C{None}).
|
|
2022
|
+
|
|
2023
|
+
@return: The previous setting (C{bool} or C{None} if not set).
|
|
2024
|
+
|
|
2025
|
+
@see: Function L{nonfiniterrors<fsums.nonfiniterrors>}.
|
|
2026
|
+
|
|
2027
|
+
@note: Use property L{nonfinitesOK<Fsum.nonfinitesOK>} to determine
|
|
2028
|
+
whether I{non-finites} are C{OK} for this L{Fsum} and by the
|
|
2029
|
+
L{nonfiniterrors} default.
|
|
2030
|
+
'''
|
|
2031
|
+
_ks = Fsum._nonfinites_isfine_kwds
|
|
2032
|
+
if OK: # delattrof(self, _isfine=None)
|
|
2033
|
+
k = _xkwds_pop(self.__dict__, _isfine=None)
|
|
2034
|
+
if OK[0] is not None:
|
|
2035
|
+
self._isfine = _ks[bool(OK[0])]
|
|
2036
|
+
self._update()
|
|
2037
|
+
else: # getattrof(self, _isfine=None)
|
|
2038
|
+
k = _xkwds_get(self.__dict__, _isfine=None)
|
|
2039
|
+
# dict(map(reversed, _ks.items())).get(k, None)
|
|
2040
|
+
# raises a TypeError: unhashable type: 'dict'
|
|
2041
|
+
return True if k is _ks[True] else (
|
|
2042
|
+
False if k is _ks[False] else None)
|
|
2043
|
+
|
|
2044
|
+
_nonfinites_isfine_kwds = {True: dict(_isfine=_isOK),
|
|
2045
|
+
False: dict(_isfine=_isfinite)}
|
|
2046
|
+
|
|
2047
|
+
@property_RO
|
|
2048
|
+
def nonfinitesOK(self):
|
|
2049
|
+
'''Are I{non-finites} C{OK} for this L{Fsum} or by default? (C{bool}).
|
|
2050
|
+
'''
|
|
2051
|
+
nf = self.nonfinites()
|
|
2052
|
+
if nf is None:
|
|
2053
|
+
nf = not nonfiniterrors()
|
|
2054
|
+
return nf
|
|
2055
|
+
|
|
2056
|
+
def _nonfiniteX(self, X, op, f, nonfinites=None, raiser=None):
|
|
2057
|
+
'''(INTERNAL) Handle a I{non-finite} exception.
|
|
2058
|
+
'''
|
|
2059
|
+
if nonfinites is None:
|
|
2060
|
+
nonfinites = _isOK_or_finite(f, **self._isfine) if raiser is None else (not raiser)
|
|
2061
|
+
if not nonfinites:
|
|
2062
|
+
raise self._ErrorX(X, op, f)
|
|
2063
|
+
return f
|
|
2064
|
+
|
|
2065
|
+
def _optionals(self, f2product=None, nonfinites=None, **name_RESIDUAL):
|
|
2066
|
+
'''(INTERNAL) Re/set options from keyword arguments.
|
|
2067
|
+
'''
|
|
2068
|
+
if f2product is not None:
|
|
2069
|
+
self.f2product(f2product)
|
|
2070
|
+
if nonfinites is not None:
|
|
2071
|
+
self.nonfinites(nonfinites)
|
|
2072
|
+
if name_RESIDUAL: # MUST be last
|
|
2073
|
+
n, kwds = _name2__(**name_RESIDUAL)
|
|
2074
|
+
if kwds:
|
|
2075
|
+
R = Fsum._RESIDUAL
|
|
2076
|
+
t = _threshold(R, **kwds)
|
|
2077
|
+
if t != R:
|
|
2078
|
+
self._RESIDUAL = t
|
|
2079
|
+
if n:
|
|
2080
|
+
self.name = n # self.rename(n)
|
|
2081
|
+
|
|
2082
|
+
def _1_Over(self, x, op, **raiser_RESIDUAL): # vs _1_over
|
|
2083
|
+
'''(INTERNAL) Return C{Fsum(1) / B{x}}.
|
|
2084
|
+
'''
|
|
2085
|
+
return self._Fsum_as(_1_0)._ftruediv(x, op, **raiser_RESIDUAL)
|
|
2086
|
+
|
|
1814
2087
|
@property_RO
|
|
1815
2088
|
def partials(self):
|
|
1816
2089
|
'''Get this instance' current, partial sums (C{tuple} of C{float}s).
|
|
@@ -1820,7 +2093,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1820
2093
|
def pow(self, x, *mod, **raiser_RESIDUAL):
|
|
1821
2094
|
'''Return C{B{self}**B{x}} as L{Fsum}.
|
|
1822
2095
|
|
|
1823
|
-
@arg x: The exponent (C{scalar}
|
|
2096
|
+
@arg x: The exponent (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
|
|
1824
2097
|
@arg mod: Optional modulus (C{int} or C{None}) for the 3-argument
|
|
1825
2098
|
C{pow(B{self}, B{other}, B{mod})} version.
|
|
1826
2099
|
@kwarg raiser_RESIDUAL: Use C{B{raiser}=False} to ignore
|
|
@@ -1846,7 +2119,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1846
2119
|
def _pow(self, other, unused, op, **raiser_RESIDUAL):
|
|
1847
2120
|
'''Return C{B{self} ** B{other}}.
|
|
1848
2121
|
'''
|
|
1849
|
-
if
|
|
2122
|
+
if _isFsum_2Tuple(other):
|
|
1850
2123
|
f = self._pow_Fsum(other, op, **raiser_RESIDUAL)
|
|
1851
2124
|
elif self._scalar(other, op):
|
|
1852
2125
|
x = self._finite(other, op)
|
|
@@ -1867,7 +2140,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1867
2140
|
|
|
1868
2141
|
if mod: # b, x, mod all C{int}, unless C{mod} is C{None}
|
|
1869
2142
|
m = mod[0]
|
|
1870
|
-
# assert
|
|
2143
|
+
# assert _isFsum_2Tuple(b)
|
|
1871
2144
|
|
|
1872
2145
|
def _s(s, r):
|
|
1873
2146
|
R = self._raiser(r, s, **raiser_RESIDUAL)
|
|
@@ -1889,9 +2162,9 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1889
2162
|
raise self._ErrorX(X, op, other, *mod)
|
|
1890
2163
|
|
|
1891
2164
|
def _pow_Fsum(self, other, op, **raiser_RESIDUAL):
|
|
1892
|
-
'''(INTERNAL) Return C{B{self} **= B{other}} for C{
|
|
2165
|
+
'''(INTERNAL) Return C{B{self} **= B{other}} for C{_isFsum_2Tuple(other)}.
|
|
1893
2166
|
'''
|
|
1894
|
-
# assert
|
|
2167
|
+
# assert _isFsum_2Tuple(other)
|
|
1895
2168
|
x, r = other._fprs2
|
|
1896
2169
|
f = self._pow_scalar(x, other, op, **raiser_RESIDUAL)
|
|
1897
2170
|
if f and r:
|
|
@@ -1907,7 +2180,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1907
2180
|
_mul_Fsum = Fsum._mul_Fsum
|
|
1908
2181
|
if x > 4:
|
|
1909
2182
|
p = self
|
|
1910
|
-
f = self if (x & 1) else
|
|
2183
|
+
f = self if (x & 1) else self._Fsum_as(_1_0)
|
|
1911
2184
|
m = x >> 1 # // 2
|
|
1912
2185
|
while m:
|
|
1913
2186
|
p = _mul_Fsum(p, p, op) # p **= 2
|
|
@@ -1945,14 +2218,14 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1945
2218
|
if _isFsum(f):
|
|
1946
2219
|
s, r = f._fprs2
|
|
1947
2220
|
if r:
|
|
1948
|
-
return _1_Over(f, op, **raiser_RESIDUAL)
|
|
2221
|
+
return self._1_Over(f, op, **raiser_RESIDUAL)
|
|
1949
2222
|
else: # scalar
|
|
1950
2223
|
s = f
|
|
1951
2224
|
# use s**(-1) to get the CPython
|
|
1952
2225
|
# float_pow error iff s is zero
|
|
1953
2226
|
x = -1
|
|
1954
2227
|
elif x < 0: # self**(-1)
|
|
1955
|
-
return _1_Over(self, op, **raiser_RESIDUAL) # 1 / self
|
|
2228
|
+
return self._1_Over(self, op, **raiser_RESIDUAL) # 1 / self
|
|
1956
2229
|
else: # self**1 or self**0
|
|
1957
2230
|
return self._pow_0_1(x, other) # self, 1 or 1.0
|
|
1958
2231
|
else: # self**fractional
|
|
@@ -1971,12 +2244,13 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1971
2244
|
'''
|
|
1972
2245
|
n = 0
|
|
1973
2246
|
_2s = _2sum
|
|
2247
|
+
_fi = self._isfine
|
|
1974
2248
|
for x in (tuple(xs) if xs is ps else xs):
|
|
1975
|
-
# assert isscalar(x) and
|
|
2249
|
+
# assert isscalar(x) and _isOK_or_finite(x, **self._isfine)
|
|
1976
2250
|
if x:
|
|
1977
2251
|
i = 0
|
|
1978
2252
|
for p in ps:
|
|
1979
|
-
x, p = _2s(x, p)
|
|
2253
|
+
x, p = _2s(x, p, **_fi)
|
|
1980
2254
|
if p:
|
|
1981
2255
|
ps[i] = p
|
|
1982
2256
|
i += 1
|
|
@@ -1984,6 +2258,10 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1984
2258
|
n += 1
|
|
1985
2259
|
if n:
|
|
1986
2260
|
self._n += n
|
|
2261
|
+
# if _fi: # collapse ps if non-finite
|
|
2262
|
+
# x = sum(ps)
|
|
2263
|
+
# if not _isfinite(x):
|
|
2264
|
+
# ps[:] = x,
|
|
1987
2265
|
# Fsum._ps_max = max(Fsum._ps_max, len(ps))
|
|
1988
2266
|
if up:
|
|
1989
2267
|
self._update()
|
|
@@ -1993,22 +2271,25 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1993
2271
|
'''(INTERNAL) Multiply this instance' C{partials} with
|
|
1994
2272
|
each scalar C{factor} and accumulate into an C{Fsum}.
|
|
1995
2273
|
'''
|
|
1996
|
-
def
|
|
2274
|
+
def _psfs(ps, fs, _isfine=_isfinite):
|
|
1997
2275
|
if len(ps) < len(fs):
|
|
1998
2276
|
ps, fs = fs, ps
|
|
1999
2277
|
if self._f2product:
|
|
2000
|
-
|
|
2001
|
-
|
|
2278
|
+
fs, p = _2split3s(fs), fs
|
|
2279
|
+
if len(ps) > 1 and fs is not p:
|
|
2280
|
+
fs = tuple(fs) # several ps
|
|
2281
|
+
_pfs = _2products
|
|
2002
2282
|
else:
|
|
2003
|
-
def
|
|
2004
|
-
return (
|
|
2283
|
+
def _pfs(p, fs):
|
|
2284
|
+
return (p * f for f in fs)
|
|
2005
2285
|
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
yield p if _fin(p) else self._finite(p, op)
|
|
2286
|
+
for p in ps:
|
|
2287
|
+
for f in _pfs(p, fs):
|
|
2288
|
+
yield f if _isfine(f) else self._finite(f, op)
|
|
2010
2289
|
|
|
2011
|
-
|
|
2290
|
+
fs = _psfs(self._ps, factors, **self._isfine)
|
|
2291
|
+
f = _Psum(self._ps_acc([], fs, up=False), name=op)
|
|
2292
|
+
return f
|
|
2012
2293
|
|
|
2013
2294
|
@property_RO
|
|
2014
2295
|
def _ps_neg(self):
|
|
@@ -2018,10 +2299,10 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
2018
2299
|
yield -p
|
|
2019
2300
|
|
|
2020
2301
|
def _ps_other(self, op, *others):
|
|
2021
|
-
'''(INTERNAL) Yield
|
|
2302
|
+
'''(INTERNAL) Yield all C{other}s as C{scalar}.
|
|
2022
2303
|
'''
|
|
2023
2304
|
for other in others:
|
|
2024
|
-
if
|
|
2305
|
+
if _isFsum_2Tuple(other):
|
|
2025
2306
|
for p in other._ps:
|
|
2026
2307
|
yield p
|
|
2027
2308
|
else:
|
|
@@ -2030,7 +2311,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
2030
2311
|
def _ps_1sum(self, *less):
|
|
2031
2312
|
'''(INTERNAL) Return the partials sum, 1-primed C{less} some scalars.
|
|
2032
2313
|
'''
|
|
2033
|
-
def
|
|
2314
|
+
def _1psls(ps, ls):
|
|
2034
2315
|
yield _1_0
|
|
2035
2316
|
for p in ps:
|
|
2036
2317
|
yield p
|
|
@@ -2038,7 +2319,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
2038
2319
|
yield -p
|
|
2039
2320
|
yield _N_1_0
|
|
2040
2321
|
|
|
2041
|
-
return _fsum(
|
|
2322
|
+
return _fsum(_1psls(self._ps, less))
|
|
2042
2323
|
|
|
2043
2324
|
def _raiser(self, r, s, raiser=True, **RESIDUAL):
|
|
2044
2325
|
'''(INTERNAL) Does ratio C{r / s} exceed the RESIDUAL threshold
|
|
@@ -2065,12 +2346,12 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
2065
2346
|
and properties L{Fsum.ceil}, L{Fsum.floor},
|
|
2066
2347
|
L{Fsum.imag} and L{Fsum.residual}.
|
|
2067
2348
|
'''
|
|
2068
|
-
return float(self
|
|
2349
|
+
return float(self)
|
|
2069
2350
|
|
|
2070
2351
|
@property_RO
|
|
2071
2352
|
def residual(self):
|
|
2072
|
-
'''Get this instance' residual (C{float} or C{int}):
|
|
2073
|
-
C{sum(partials)} less the precision running sum C{fsum}.
|
|
2353
|
+
'''Get this instance' residual or residue (C{float} or C{int}):
|
|
2354
|
+
the C{sum(partials)} less the precision running sum C{fsum}.
|
|
2074
2355
|
|
|
2075
2356
|
@note: The C{residual is INT0} iff the precision running
|
|
2076
2357
|
C{fsum} is considered to be I{exact}.
|
|
@@ -2085,7 +2366,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
2085
2366
|
|
|
2086
2367
|
@arg threshold: If C{scalar}, the I{ratio} to exceed for raising
|
|
2087
2368
|
L{ResidualError}s in division and exponention, if
|
|
2088
|
-
C{None} restore the default set with env variable
|
|
2369
|
+
C{None}, restore the default set with env variable
|
|
2089
2370
|
C{PYGEODESY_FSUM_RESIDUAL} or if omitted, keep the
|
|
2090
2371
|
current setting.
|
|
2091
2372
|
|
|
@@ -2095,11 +2376,11 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
2095
2376
|
|
|
2096
2377
|
@note: L{ResidualError}s may be thrown if (1) the non-zero I{ratio}
|
|
2097
2378
|
C{residual / fsum} exceeds the given B{C{threshold}} and (2)
|
|
2098
|
-
the C{residual} is non-zero and (3) I{significant} vs the
|
|
2379
|
+
the C{residual} is non-zero and (3) is I{significant} vs the
|
|
2099
2380
|
C{fsum}, i.e. C{(fsum + residual) != fsum} and (4) optional
|
|
2100
2381
|
keyword argument C{raiser=False} is missing. Specify a
|
|
2101
2382
|
negative B{C{threshold}} for only non-zero C{residual}
|
|
2102
|
-
testing without I{significant}.
|
|
2383
|
+
testing without the I{significant} case.
|
|
2103
2384
|
'''
|
|
2104
2385
|
r = self._RESIDUAL
|
|
2105
2386
|
if threshold:
|
|
@@ -2122,9 +2403,9 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
2122
2403
|
def root(self, root, **raiser_RESIDUAL):
|
|
2123
2404
|
'''Return C{B{self}**(1 / B{root})} as L{Fsum}.
|
|
2124
2405
|
|
|
2125
|
-
@arg root:
|
|
2126
|
-
@kwarg raiser_RESIDUAL: Use C{B{raiser}=False} to ignore
|
|
2127
|
-
L{ResidualError}s (C{bool})
|
|
2406
|
+
@arg root: Non-zero order (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
|
|
2407
|
+
@kwarg raiser_RESIDUAL: Use C{B{raiser}=False} to ignore any
|
|
2408
|
+
L{ResidualError}s (C{bool}) or C{B{RESIDUAL}=scalar}
|
|
2128
2409
|
to override the current L{RESIDUAL<Fsum.RESIDUAL>}.
|
|
2129
2410
|
|
|
2130
2411
|
@return: The C{self ** (1 / B{root})} result (L{Fsum}).
|
|
@@ -2134,12 +2415,12 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
2134
2415
|
|
|
2135
2416
|
@see: Method L{Fsum.pow}.
|
|
2136
2417
|
'''
|
|
2137
|
-
x = _1_Over(root, _truediv_op_, **raiser_RESIDUAL)
|
|
2138
|
-
f =
|
|
2418
|
+
x = self._1_Over(root, _truediv_op_, **raiser_RESIDUAL)
|
|
2419
|
+
f = self._copy_2(self.root)
|
|
2139
2420
|
return f._fpow(x, f.name, **raiser_RESIDUAL) # == pow(f, x)
|
|
2140
2421
|
|
|
2141
2422
|
def _scalar(self, other, op, **txt):
|
|
2142
|
-
'''(INTERNAL) Return scalar C{other}.
|
|
2423
|
+
'''(INTERNAL) Return scalar C{other} or throw a C{TypeError}.
|
|
2143
2424
|
'''
|
|
2144
2425
|
if isscalar(other):
|
|
2145
2426
|
return other
|
|
@@ -2148,8 +2429,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
2148
2429
|
def signOf(self, res=True):
|
|
2149
2430
|
'''Determine the sign of this instance.
|
|
2150
2431
|
|
|
2151
|
-
@kwarg res: If C{True}, consider
|
|
2152
|
-
the
|
|
2432
|
+
@kwarg res: If C{True}, consider the residual,
|
|
2433
|
+
otherwise ignore the latter (C{bool}).
|
|
2153
2434
|
|
|
2154
2435
|
@return: The sign (C{int}, -1, 0 or +1).
|
|
2155
2436
|
'''
|
|
@@ -2204,23 +2485,17 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
2204
2485
|
|
|
2205
2486
|
_ROs = _allPropertiesOf_n(3, Fsum, Property_RO) # PYCHOK see Fsum._update
|
|
2206
2487
|
|
|
2488
|
+
if _NONFINITES == _std_: # PYCHOK no cover
|
|
2489
|
+
_ = nonfiniterrors(False)
|
|
2490
|
+
|
|
2207
2491
|
|
|
2208
2492
|
def _Float_Int(arg, **name_Error):
|
|
2209
|
-
'''(INTERNAL)
|
|
2493
|
+
'''(INTERNAL) L{DivMod2Tuple}, L{Fsum2Tuple} Unit.
|
|
2210
2494
|
'''
|
|
2211
2495
|
U = Int if isint(arg) else Float
|
|
2212
2496
|
return U(arg, **name_Error)
|
|
2213
2497
|
|
|
2214
2498
|
|
|
2215
|
-
def Fsum2product(*xs, **name_RESIDUAL):
|
|
2216
|
-
'''Return an L{Fsum} with L{f2product<Fsum.f2product>} accurate
|
|
2217
|
-
multiplication I{turned on}.
|
|
2218
|
-
'''
|
|
2219
|
-
F = Fsum(*xs, **name_RESIDUAL)
|
|
2220
|
-
F.f2product(True)
|
|
2221
|
-
return F
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
2499
|
class DivMod2Tuple(_NamedTuple):
|
|
2225
2500
|
'''2-Tuple C{(div, mod)} with the quotient C{div} and remainder
|
|
2226
2501
|
C{mod} results of a C{divmod} operation.
|
|
@@ -2228,7 +2503,7 @@ class DivMod2Tuple(_NamedTuple):
|
|
|
2228
2503
|
@note: Quotient C{div} an C{int} in Python 3+ but a C{float}
|
|
2229
2504
|
in Python 2-. Remainder C{mod} an L{Fsum} instance.
|
|
2230
2505
|
'''
|
|
2231
|
-
_Names_ = (
|
|
2506
|
+
_Names_ = ('div', 'mod')
|
|
2232
2507
|
_Units_ = (_Float_Int, Fsum)
|
|
2233
2508
|
|
|
2234
2509
|
|
|
@@ -2302,17 +2577,23 @@ class Fsum2Tuple(_NamedTuple): # in .fstats
|
|
|
2302
2577
|
ps = (r, s) if r else (s,)
|
|
2303
2578
|
return _Psum(ps, name=self.name)
|
|
2304
2579
|
|
|
2305
|
-
def Fsum_(self, *xs, **
|
|
2580
|
+
def Fsum_(self, *xs, **name_f2product_nonfinites_RESIDUAL):
|
|
2306
2581
|
'''Return this C{Fsum2Tuple} as an L{Fsum} plus some C{xs}.
|
|
2307
2582
|
'''
|
|
2308
|
-
|
|
2309
|
-
return f._facc_1(xs, up=False) if xs else f
|
|
2583
|
+
return Fsum(self, *xs, **name_f2product_nonfinites_RESIDUAL)
|
|
2310
2584
|
|
|
2311
2585
|
def is_exact(self):
|
|
2312
2586
|
'''Is this L{Fsum2Tuple} considered to be exact? (C{bool}).
|
|
2313
2587
|
'''
|
|
2314
2588
|
return self._Fsum.is_exact()
|
|
2315
2589
|
|
|
2590
|
+
def is_finite(self): # in .constants
|
|
2591
|
+
'''Is this L{Fsum2Tuple} C{finite}? (C{bool}).
|
|
2592
|
+
|
|
2593
|
+
@see: Function L{isfinite<pygeodesy.isfinite>}.
|
|
2594
|
+
'''
|
|
2595
|
+
return self._Fsum.is_finite()
|
|
2596
|
+
|
|
2316
2597
|
def is_integer(self):
|
|
2317
2598
|
'''Is this L{Fsum2Tuple} C{integer}? (C{bool}).
|
|
2318
2599
|
'''
|
|
@@ -2351,7 +2632,7 @@ class Fsum2Tuple(_NamedTuple): # in .fstats
|
|
|
2351
2632
|
'''
|
|
2352
2633
|
return Fmt.PAREN(fstr(self, fmt=fmt, strepr=str, force=False, **prec_sep))
|
|
2353
2634
|
|
|
2354
|
-
|
|
2635
|
+
_Fsum_2Tuple_types = Fsum, Fsum2Tuple # PYCHOK lines
|
|
2355
2636
|
|
|
2356
2637
|
|
|
2357
2638
|
class ResidualError(_ValueError):
|
|
@@ -2373,105 +2654,132 @@ try:
|
|
|
2373
2654
|
del _fsum # nope, remove _fsum ...
|
|
2374
2655
|
raise ImportError() # ... use _fsum below
|
|
2375
2656
|
|
|
2376
|
-
|
|
2657
|
+
_sum = _fsum # in .elliptic
|
|
2377
2658
|
except ImportError:
|
|
2378
|
-
_sum =
|
|
2659
|
+
_sum = sum # in .elliptic
|
|
2379
2660
|
|
|
2380
2661
|
def _fsum(xs):
|
|
2381
2662
|
'''(INTERNAL) Precision summation, Python 2.5-.
|
|
2382
2663
|
'''
|
|
2383
|
-
F = Fsum()
|
|
2384
|
-
F.
|
|
2385
|
-
return F._facc(xs, up=False)._fprs2.fsum
|
|
2664
|
+
F = Fsum(name=_fsum.name, f2product=False, nonfinites=True)
|
|
2665
|
+
return float(F._facc(xs, up=False))
|
|
2386
2666
|
|
|
2387
2667
|
|
|
2388
|
-
def fsum(xs, floats
|
|
2389
|
-
'''Precision floating point summation
|
|
2668
|
+
def fsum(xs, nonfinites=None, **floats):
|
|
2669
|
+
'''Precision floating point summation from Python's C{math.fsum}.
|
|
2390
2670
|
|
|
2391
|
-
@arg xs: Iterable of items to add (each C{scalar}
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2671
|
+
@arg xs: Iterable of items to add (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
|
|
2672
|
+
@kwarg nonfinites: Use C{B{nonfinites}=True} if I{non-finites} are C{OK}, if
|
|
2673
|
+
C{False} I{non-finites} raise an Overflow-/ValueError or if
|
|
2674
|
+
C{None}, L{nonfiniterrors} applies (C{bool} or C{None}).
|
|
2675
|
+
@kwarg floats: DEPRECATED keyword argument C{B{floats}=False} (C{bool}), use
|
|
2676
|
+
keyword argument C{B{nonfinites}=False} instead.
|
|
2395
2677
|
|
|
2396
2678
|
@return: Precision C{fsum} (C{float}).
|
|
2397
2679
|
|
|
2398
|
-
@raise OverflowError:
|
|
2399
|
-
|
|
2400
|
-
@raise TypeError: Non-scalar B{C{xs}} item.
|
|
2680
|
+
@raise OverflowError: Infinite B{C{xs}} item or intermediate C{math.fsum} overflow.
|
|
2401
2681
|
|
|
2402
|
-
@raise
|
|
2682
|
+
@raise TypeError: Invalid B{C{xs}} item.
|
|
2403
2683
|
|
|
2404
|
-
@
|
|
2405
|
-
on Python's C{math.fsum}.
|
|
2684
|
+
@raise ValueError: Invalid or C{NAN} B{C{xs}} item.
|
|
2406
2685
|
|
|
2407
|
-
@see:
|
|
2686
|
+
@see: Function L{nonfiniterrors}, class L{Fsum} and methods L{Fsum.nonfinites},
|
|
2687
|
+
L{Fsum.fsum}, L{Fsum.fadd} and L{Fsum.fadd_}.
|
|
2408
2688
|
'''
|
|
2409
|
-
return
|
|
2689
|
+
return _xsum(fsum, xs, nonfinites=nonfinites, **floats) if xs else _0_0
|
|
2410
2690
|
|
|
2411
2691
|
|
|
2412
|
-
def fsum_(*xs, **
|
|
2692
|
+
def fsum_(*xs, **nonfinites):
|
|
2413
2693
|
'''Precision floating point summation of all positional items.
|
|
2414
2694
|
|
|
2415
|
-
@arg xs: Items to add (each C{scalar}
|
|
2416
|
-
|
|
2417
|
-
@kwarg floats: Use C{B{floats}=True} iff I{all} B{C{xs}} items are I{known to
|
|
2418
|
-
be scalar} (C{bool}).
|
|
2695
|
+
@arg xs: Items to add (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}), all positional.
|
|
2696
|
+
@kwarg nonfinites: Use C{B{nonfinites}=True} if I{non-finites} are C{OK} (C{bool}).
|
|
2419
2697
|
|
|
2420
2698
|
@see: Function L{fsum<fsums.fsum>} for further details.
|
|
2421
2699
|
'''
|
|
2422
|
-
return
|
|
2423
|
-
_2floats(xs, origin=1)) if xs else _0_0 # PYCHOK yield
|
|
2700
|
+
return _xsum(fsum_, xs, origin=1, **nonfinites) if xs else _0_0
|
|
2424
2701
|
|
|
2425
2702
|
|
|
2426
2703
|
def fsumf_(*xs):
|
|
2427
|
-
'''Precision floating point summation
|
|
2704
|
+
'''Precision floating point summation of all positional items with I{non-finites} C{OK}.
|
|
2705
|
+
|
|
2706
|
+
@arg xs: Items to add (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}),
|
|
2707
|
+
all positional.
|
|
2428
2708
|
|
|
2429
2709
|
@see: Function L{fsum_<fsums.fsum_>} for further details.
|
|
2430
2710
|
'''
|
|
2431
|
-
return
|
|
2711
|
+
return _xsum(fsumf_, xs, nonfinites=True, origin=1) if xs else _0_0
|
|
2432
2712
|
|
|
2433
2713
|
|
|
2434
|
-
def fsum1(xs,
|
|
2714
|
+
def fsum1(xs, **nonfinites):
|
|
2435
2715
|
'''Precision floating point summation, 1-primed.
|
|
2436
2716
|
|
|
2437
|
-
@arg xs: Iterable of items to add (each C{scalar}
|
|
2438
|
-
|
|
2439
|
-
@kwarg floats: Use C{B{floats}=True} iff I{all} B{C{xs}} items are I{known to
|
|
2440
|
-
be scalar} (C{bool}).
|
|
2717
|
+
@arg xs: Iterable of items to add (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
|
|
2718
|
+
@kwarg nonfinites: Use C{B{nonfinites}=True} if I{non-finites} are C{OK} (C{bool}).
|
|
2441
2719
|
|
|
2442
2720
|
@see: Function L{fsum<fsums.fsum>} for further details.
|
|
2443
2721
|
'''
|
|
2444
|
-
return
|
|
2722
|
+
return _xsum(fsum1, xs, primed=1, **nonfinites) if xs else _0_0
|
|
2445
2723
|
|
|
2446
2724
|
|
|
2447
|
-
def fsum1_(*xs, **
|
|
2448
|
-
'''Precision floating point summation
|
|
2725
|
+
def fsum1_(*xs, **nonfinites):
|
|
2726
|
+
'''Precision floating point summation of all positional items, 1-primed.
|
|
2449
2727
|
|
|
2450
|
-
@arg xs: Items to add (each C{scalar}
|
|
2451
|
-
|
|
2452
|
-
@kwarg floats: Use C{B{floats}=True} iff I{all} B{C{xs}} items are I{known to
|
|
2453
|
-
be scalar} (C{bool}).
|
|
2728
|
+
@arg xs: Items to add (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}), all positional.
|
|
2729
|
+
@kwarg nonfinites: Use C{B{nonfinites}=True} if I{non-finites} are C{OK} (C{bool}).
|
|
2454
2730
|
|
|
2455
2731
|
@see: Function L{fsum_<fsums.fsum_>} for further details.
|
|
2456
2732
|
'''
|
|
2457
|
-
return
|
|
2458
|
-
_2floats(xs, origin=1))) if xs else _0_0 # PYCHOK yield
|
|
2733
|
+
return _xsum(fsum1_, xs, origin=1, primed=1, **nonfinites) if xs else _0_0
|
|
2459
2734
|
|
|
2460
2735
|
|
|
2461
2736
|
def fsum1f_(*xs):
|
|
2462
|
-
'''Precision floating point summation
|
|
2737
|
+
'''Precision floating point summation of all positional items, 1-primed and
|
|
2738
|
+
with I{non-finites} C{OK}.
|
|
2463
2739
|
|
|
2464
2740
|
@see: Function L{fsum_<fsums.fsum_>} for further details.
|
|
2465
2741
|
'''
|
|
2466
|
-
return
|
|
2742
|
+
return _xsum(fsum1f_, xs, nonfinites=True, primed=1) if xs else _0_0
|
|
2467
2743
|
|
|
2468
2744
|
|
|
2469
|
-
|
|
2745
|
+
def _xs(xs, i_x, nfOK): # in Fsum._facc_scalarf
|
|
2746
|
+
'''(INTERNAL) Yield all C{xs} as C{scalar}.
|
|
2747
|
+
'''
|
|
2748
|
+
_x = _passarg if nfOK else _2finite
|
|
2749
|
+
for i, x in enumerate(xs):
|
|
2750
|
+
i_x[:] = i, x
|
|
2751
|
+
if _isFsum_2Tuple(x):
|
|
2752
|
+
for p in map(_x, x._ps):
|
|
2753
|
+
yield p
|
|
2754
|
+
else:
|
|
2755
|
+
yield _x(x)
|
|
2470
2756
|
|
|
2471
|
-
# usage: [env _psum=fsum] python3 -m pygeodesy.fsums
|
|
2472
2757
|
|
|
2473
|
-
|
|
2474
|
-
|
|
2758
|
+
def _xsum(which, xs, nonfinites=None, origin=0, primed=0, **floats):
|
|
2759
|
+
'''(INTERNAL) Precision summation of C{xs} with conditions.
|
|
2760
|
+
'''
|
|
2761
|
+
i_x = [0, xs]
|
|
2762
|
+
try:
|
|
2763
|
+
if floats: # for backward compatibility
|
|
2764
|
+
nonfinites = _xkwds_get1(floats, floats=nonfinites)
|
|
2765
|
+
elif nonfinites is None:
|
|
2766
|
+
nonfinites = not nonfiniterrors()
|
|
2767
|
+
fs = _xs(xs, i_x, nonfinites)
|
|
2768
|
+
return _fsum(_1primed(fs) if primed else fs)
|
|
2769
|
+
except (OverflowError, TypeError, ValueError) as X:
|
|
2770
|
+
origin -= 1 if primed else 0
|
|
2771
|
+
i_x += [origin, which]
|
|
2772
|
+
raise _ixError(X, xs, *i_x)
|
|
2773
|
+
|
|
2774
|
+
|
|
2775
|
+
# delete all decorators, etc.
|
|
2776
|
+
del _allPropertiesOf_n, deprecated_method, deprecated_property_RO, \
|
|
2777
|
+
Property, Property_RO, property_RO, _ALL_LAZY, _F2PRODUCT, \
|
|
2778
|
+
MANT_DIG, _NONFINITES, _RESIDUAL_0_0, _getenv, _std_
|
|
2779
|
+
|
|
2780
|
+
if __name__ == '__main__':
|
|
2781
|
+
|
|
2782
|
+
# usage: python3 -m pygeodesy.fsums
|
|
2475
2783
|
|
|
2476
2784
|
def _test(n):
|
|
2477
2785
|
# copied from Hettinger, see L{Fsum} reference
|