pygeodesy 24.3.24__py2.py3-none-any.whl → 24.4.4__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.3.24.dist-info → PyGeodesy-24.4.4.dist-info}/METADATA +5 -5
- {PyGeodesy-24.3.24.dist-info → PyGeodesy-24.4.4.dist-info}/RECORD +13 -13
- pygeodesy/__init__.py +4 -4
- pygeodesy/azimuthal.py +2 -2
- pygeodesy/basics.py +16 -5
- pygeodesy/constants.py +2 -2
- pygeodesy/fmath.py +187 -194
- pygeodesy/fsums.py +489 -402
- pygeodesy/lazily.py +2 -2
- pygeodesy/resections.py +28 -28
- pygeodesy/utily.py +11 -10
- {PyGeodesy-24.3.24.dist-info → PyGeodesy-24.4.4.dist-info}/WHEEL +0 -0
- {PyGeodesy-24.3.24.dist-info → PyGeodesy-24.4.4.dist-info}/top_level.txt +0 -0
pygeodesy/fsums.py
CHANGED
|
@@ -14,8 +14,8 @@ L{Fsum.__rpow__} return a (very long) C{int} if invoked with optional argument
|
|
|
14
14
|
C{mod} set to C{None}. The C{residual} of an C{integer} L{Fsum} may be between
|
|
15
15
|
C{-1.0} and C{+1.0}, including C{INT0} if considered to be I{exact}.
|
|
16
16
|
|
|
17
|
-
Set env variable C{PYGEODESY_FSUM_PARTIALS} to
|
|
18
|
-
|
|
17
|
+
Set env variable C{PYGEODESY_FSUM_PARTIALS} to string C{"fsum"}) for summation
|
|
18
|
+
of L{Fsum} partials by Python function C{math.fsum}.
|
|
19
19
|
|
|
20
20
|
Set env variable C{PYGEODESY_FSUM_RESIDUAL} to a C{float} string greater
|
|
21
21
|
than C{"0.0"} as the threshold to throw a L{ResidualError} in division or
|
|
@@ -27,11 +27,11 @@ and L{Fsum.__itruediv__}.
|
|
|
27
27
|
from __future__ import division as _; del _ # PYCHOK semicolon
|
|
28
28
|
|
|
29
29
|
from pygeodesy.basics import iscomplex, isint, isscalar, itemsorted, \
|
|
30
|
-
signOf, _signOf
|
|
31
|
-
from pygeodesy.constants import INT0, _isfinite, isinf, isnan, _pos_self, \
|
|
30
|
+
signOf, _signOf
|
|
31
|
+
from pygeodesy.constants import INT0, _isfinite, isinf, isnan, NEG0, _pos_self, \
|
|
32
32
|
_0_0, _1_0, _N_1_0, Float, Int
|
|
33
|
-
from pygeodesy.errors import _OverflowError, _TypeError, _ValueError,
|
|
34
|
-
_xkwds_get, _ZeroDivisionError
|
|
33
|
+
from pygeodesy.errors import _OverflowError, _TypeError, _ValueError, _xError, \
|
|
34
|
+
_xError2, _xkwds_get, _ZeroDivisionError
|
|
35
35
|
from pygeodesy.interns import NN, _arg_, _COMMASPACE_, _DASH_, _DOT_, _EQUAL_, \
|
|
36
36
|
_exceeds_, _from_, _iadd_op_, _LANGLE_, _negative_, \
|
|
37
37
|
_NOTEQUAL_, _not_finite_, _not_scalar_, _PERCENT_, \
|
|
@@ -46,11 +46,12 @@ from pygeodesy.props import _allPropertiesOf_n, deprecated_property_RO, \
|
|
|
46
46
|
from math import ceil as _ceil, fabs, floor as _floor # PYCHOK used! .ltp
|
|
47
47
|
|
|
48
48
|
__all__ = _ALL_LAZY.fsums
|
|
49
|
-
__version__ = '24.
|
|
49
|
+
__version__ = '24.04.04'
|
|
50
50
|
|
|
51
51
|
_add_op_ = _PLUS_ # in .auxilats.auxAngle
|
|
52
52
|
_eq_op_ = _EQUAL_ * 2 # _DEQUAL_
|
|
53
53
|
_COMMASPACE_R_ = _COMMASPACE_ + _R_
|
|
54
|
+
_div_ = 'div'
|
|
54
55
|
_exceeds_R_ = _SPACE_ + _exceeds_(_R_)
|
|
55
56
|
_floordiv_op_ = _SLASH_ * 2 # _DSLASH_
|
|
56
57
|
_fset_op_ = _EQUAL_
|
|
@@ -59,6 +60,7 @@ _gt_op_ = _RANGLE_
|
|
|
59
60
|
_integer_ = 'integer'
|
|
60
61
|
_le_op_ = _LANGLE_ + _EQUAL_
|
|
61
62
|
_lt_op_ = _LANGLE_
|
|
63
|
+
_mod_ = 'mod'
|
|
62
64
|
_mod_op_ = _PERCENT_
|
|
63
65
|
_mul_op_ = _STAR_
|
|
64
66
|
_ne_op_ = _NOTEQUAL_
|
|
@@ -78,63 +80,30 @@ def _2float(index=None, **name_value): # in .fmath, .fstats
|
|
|
78
80
|
v = float(v)
|
|
79
81
|
if _isfinite(v):
|
|
80
82
|
return v
|
|
81
|
-
|
|
82
|
-
except Exception as
|
|
83
|
-
|
|
84
|
-
raise E(Fmt.INDEX(n, index), v, txt=t)
|
|
83
|
+
raise ValueError(_not_finite_)
|
|
84
|
+
except Exception as X:
|
|
85
|
+
raise _xError(X, Fmt.INDEX(n, index), v)
|
|
85
86
|
|
|
86
87
|
|
|
87
|
-
def _2floats(xs, origin=0,
|
|
88
|
+
def _2floats(xs, origin=0, neg=False):
|
|
88
89
|
'''(INTERNAL) Yield each B{C{xs}} as a C{float}.
|
|
89
90
|
'''
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
_Fsum = Fsum
|
|
94
|
-
for x in xs:
|
|
95
|
-
if isinstance(x, _Fsum):
|
|
96
|
-
for p in x._ps:
|
|
97
|
-
yield (-p) if sub else p
|
|
98
|
-
else:
|
|
99
|
-
f = float(x)
|
|
100
|
-
if not _fin(f):
|
|
101
|
-
raise ValueError(_not_finite_)
|
|
102
|
-
if f:
|
|
103
|
-
yield (-f) if sub else f
|
|
104
|
-
i += 1
|
|
105
|
-
except Exception as e:
|
|
106
|
-
E, t = _xError2(e)
|
|
107
|
-
n = Fmt.SQUARE(xs=i)
|
|
108
|
-
raise E(n, x, txt=t)
|
|
91
|
+
if neg:
|
|
92
|
+
def _X(X):
|
|
93
|
+
return X._ps_neg
|
|
109
94
|
|
|
95
|
+
def _x(x):
|
|
96
|
+
return -float(x)
|
|
97
|
+
else:
|
|
98
|
+
def _X(X): # PYCHOK re-def
|
|
99
|
+
return X._ps
|
|
110
100
|
|
|
111
|
-
|
|
112
|
-
'''(INTERNAL) Yield each C{xs} as C{float(x**power)}.
|
|
113
|
-
'''
|
|
114
|
-
_xisscalar(power=power)
|
|
115
|
-
try:
|
|
116
|
-
i, x = origin, None
|
|
117
|
-
_fin = _isfinite
|
|
118
|
-
_Fsum = Fsum
|
|
119
|
-
_pow = pow # XXX math.pow
|
|
120
|
-
for x in xs:
|
|
121
|
-
if isinstance(x, _Fsum):
|
|
122
|
-
P = x.pow(power)
|
|
123
|
-
for p in P._ps:
|
|
124
|
-
yield p
|
|
125
|
-
else:
|
|
126
|
-
p = _pow(float(x), power)
|
|
127
|
-
if not _fin(p):
|
|
128
|
-
raise ValueError(_not_finite_)
|
|
129
|
-
yield p
|
|
130
|
-
i += 1
|
|
131
|
-
except Exception as e:
|
|
132
|
-
E, t = _xError2(e)
|
|
133
|
-
n = Fmt.SQUARE(xs=i)
|
|
134
|
-
raise E(n, x, txt=t)
|
|
101
|
+
_x = float
|
|
135
102
|
|
|
103
|
+
return _2yield(xs, origin, _X, _x)
|
|
136
104
|
|
|
137
|
-
|
|
105
|
+
|
|
106
|
+
def _1primed(xs): # in .fmath
|
|
138
107
|
'''(INTERNAL) 1-Prime the summation of C{xs}
|
|
139
108
|
arguments I{known} to be C{finite float}.
|
|
140
109
|
'''
|
|
@@ -145,27 +114,38 @@ def _1primed(xs):
|
|
|
145
114
|
yield _N_1_0
|
|
146
115
|
|
|
147
116
|
|
|
117
|
+
def _2ps(s, r):
|
|
118
|
+
'''(INTERNAL) Return a C{s} and C{r} pair, I{ps-ordered}.
|
|
119
|
+
'''
|
|
120
|
+
if fabs(s) < fabs(r):
|
|
121
|
+
s, r = r, s
|
|
122
|
+
return ((r, s) if s else (r,)) if r else (s,)
|
|
123
|
+
|
|
124
|
+
|
|
148
125
|
def _psum(ps): # PYCHOK used!
|
|
149
|
-
'''(INTERNAL) Partials
|
|
126
|
+
'''(INTERNAL) Partials sum, updating C{ps}, I{overridden below}.
|
|
150
127
|
'''
|
|
151
|
-
|
|
152
|
-
|
|
128
|
+
# assert isinstance(ps, list)
|
|
129
|
+
i = len(ps) - 1
|
|
130
|
+
s = _0_0 if i < 0 else ps[i]
|
|
153
131
|
_2s = _2sum
|
|
154
132
|
while i > 0:
|
|
155
133
|
i -= 1
|
|
156
134
|
s, r = _2s(s, ps[i])
|
|
157
135
|
if r: # sum(ps) became inexact
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
136
|
+
if s:
|
|
137
|
+
ps[i:] = r, s
|
|
138
|
+
if i > 0:
|
|
139
|
+
p = ps[i-1] # round half-even
|
|
140
|
+
if (p > 0 and r > 0) or \
|
|
141
|
+
(p < 0 and r < 0): # signs match
|
|
142
|
+
r *= 2
|
|
143
|
+
t = s + r
|
|
144
|
+
if r == (t - s):
|
|
145
|
+
s = t
|
|
146
|
+
break # return s
|
|
147
|
+
s = r # PYCHOK no cover
|
|
148
|
+
ps[i:] = s,
|
|
169
149
|
return s
|
|
170
150
|
|
|
171
151
|
|
|
@@ -188,24 +168,24 @@ def _2scalar(other, _raiser=None):
|
|
|
188
168
|
|
|
189
169
|
|
|
190
170
|
def _strcomplex(s, *args):
|
|
191
|
-
'''(INTERNAL) C{Complex} 2- or 3-arg C{pow} error C{str}.
|
|
171
|
+
'''(INTERNAL) C{Complex} 2- or 3-arg C{pow} error as C{str}.
|
|
192
172
|
'''
|
|
193
|
-
c =
|
|
173
|
+
c = _strcomplex.__name__[4:]
|
|
194
174
|
n = _DASH_(len(args), _arg_)
|
|
195
|
-
t =
|
|
196
|
-
return
|
|
175
|
+
t = unstr(pow, *args)
|
|
176
|
+
return _SPACE_(c, s, _from_, n, t)
|
|
197
177
|
|
|
198
178
|
|
|
199
179
|
def _stresidual(prefix, residual, **name_values):
|
|
200
|
-
'''(INTERNAL) Residual error C{str}.
|
|
180
|
+
'''(INTERNAL) Residual error as C{str}.
|
|
201
181
|
'''
|
|
202
|
-
p =
|
|
182
|
+
p = _stresidual.__name__[3:]
|
|
203
183
|
t = Fmt.PARENSPACED(p, Fmt(residual))
|
|
204
184
|
for n, v in itemsorted(name_values):
|
|
205
185
|
n = n.replace(_UNDER_, _SPACE_)
|
|
206
186
|
p = Fmt.PARENSPACED(n, Fmt(v))
|
|
207
187
|
t = _COMMASPACE_(t, p)
|
|
208
|
-
return t
|
|
188
|
+
return _SPACE_(prefix, t)
|
|
209
189
|
|
|
210
190
|
|
|
211
191
|
def _2sum(a, b): # by .testFmath
|
|
@@ -221,16 +201,37 @@ def _2sum(a, b): # by .testFmath
|
|
|
221
201
|
return s, (b - (s - a))
|
|
222
202
|
|
|
223
203
|
|
|
204
|
+
def _2yield(xs, i, _X_ps, _x):
|
|
205
|
+
'''(INTERNAL) Yield each B{C{xs}} as a C{float}.
|
|
206
|
+
'''
|
|
207
|
+
x = None
|
|
208
|
+
try:
|
|
209
|
+
_fin = _isfinite
|
|
210
|
+
_Fs = Fsum
|
|
211
|
+
for x in xs:
|
|
212
|
+
if isinstance(x, _Fs):
|
|
213
|
+
for p in _X_ps(x):
|
|
214
|
+
yield p
|
|
215
|
+
else:
|
|
216
|
+
f = _x(x)
|
|
217
|
+
if f:
|
|
218
|
+
if not _fin(f):
|
|
219
|
+
raise ValueError(_not_finite_)
|
|
220
|
+
yield f
|
|
221
|
+
i += 1
|
|
222
|
+
except Exception as X:
|
|
223
|
+
raise _xError(X, Fmt.INDEX(xs=i), x)
|
|
224
|
+
|
|
225
|
+
|
|
224
226
|
class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
225
|
-
'''Precision floating point I{running} summation.
|
|
227
|
+
'''Precision floating point summation and I{running} summation.
|
|
226
228
|
|
|
227
229
|
Unlike Python's C{math.fsum}, this class accumulates values and provides intermediate,
|
|
228
|
-
I{running} precision floating point
|
|
230
|
+
I{running}, precision floating point summations. Accumulation may continue after any
|
|
229
231
|
intermediate, I{running} summuation.
|
|
230
232
|
|
|
231
|
-
@note: Accumulated values may be L{Fsum} or C{scalar} instances
|
|
232
|
-
|
|
233
|
-
method C{__float__}.
|
|
233
|
+
@note: Accumulated values may be L{Fsum} or C{scalar} instances, any C{type} having
|
|
234
|
+
method C{__float__} to convert the C{scalar} to a single C{float}.
|
|
234
235
|
|
|
235
236
|
@note: Handling of exceptions and C{inf}, C{INF}, C{nan} and C{NAN} differs from
|
|
236
237
|
Python's C{math.fsum}.
|
|
@@ -245,42 +246,40 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
245
246
|
_math_fsum = None
|
|
246
247
|
_n = 0
|
|
247
248
|
# _ps = [] # partial sums
|
|
248
|
-
# _px = 0
|
|
249
|
+
# _px = 0 # max(Fsum._px, len(Fsum._ps))
|
|
249
250
|
_ratio = None
|
|
250
251
|
_RESIDUAL = max(float(_getenv('PYGEODESY_FSUM_RESIDUAL', _0_0)), _0_0)
|
|
251
252
|
|
|
252
253
|
def __init__(self, *xs, **name_RESIDUAL):
|
|
253
|
-
'''New L{Fsum} for precision floating point
|
|
254
|
+
'''New L{Fsum} for I{running} precision floating point summation.
|
|
254
255
|
|
|
255
|
-
@arg xs: No, one or more initial values (each C{scalar}
|
|
256
|
-
L{Fsum} instance).
|
|
257
|
-
@kwarg name_RESIDUAL: Optional C{B{name}=NN} for this L{Fsum}
|
|
258
|
-
|
|
259
|
-
L{ResidualError} threshold.
|
|
256
|
+
@arg xs: No, one or more initial values, all positional (each C{scalar}
|
|
257
|
+
or an L{Fsum} instance).
|
|
258
|
+
@kwarg name_RESIDUAL: Optional C{B{name}=NN} for this L{Fsum} and
|
|
259
|
+
C{B{RESIDUAL}=None} for the L{ResidualError} threshold.
|
|
260
260
|
|
|
261
261
|
@see: Methods L{Fsum.fadd} and L{Fsum.RESIDUAL}.
|
|
262
262
|
'''
|
|
263
263
|
if name_RESIDUAL:
|
|
264
264
|
n = _xkwds_get(name_RESIDUAL, name=NN)
|
|
265
|
-
if n: # set name ...
|
|
265
|
+
if n: # set name before ...
|
|
266
266
|
self.name = n
|
|
267
267
|
r = _xkwds_get(name_RESIDUAL, RESIDUAL=None)
|
|
268
268
|
if r is not None:
|
|
269
|
-
self.RESIDUAL(r) # ...
|
|
269
|
+
self.RESIDUAL(r) # ... ResidualError
|
|
270
270
|
# self._n = 0
|
|
271
271
|
self._ps = [] # [_0_0], see L{Fsum._fprs}
|
|
272
272
|
if len(xs) > 1:
|
|
273
273
|
self._facc(_2floats(xs, origin=1), up=False) # PYCHOK yield
|
|
274
274
|
elif xs: # len(xs) == 1
|
|
275
|
-
self.
|
|
276
|
-
self.
|
|
275
|
+
self._n = 1
|
|
276
|
+
self._ps[:] = _2float(x=xs[0]),
|
|
277
277
|
|
|
278
278
|
def __abs__(self):
|
|
279
279
|
'''Return this instance' absolute value as an L{Fsum}.
|
|
280
280
|
'''
|
|
281
281
|
s = _fsum(self._ps_1()) # == self._cmp_0(0, ...)
|
|
282
|
-
return
|
|
283
|
-
self._copy_2(self.__abs__)
|
|
282
|
+
return (-self) if s < 0 else self._copy_2(self.__abs__)
|
|
284
283
|
|
|
285
284
|
def __add__(self, other):
|
|
286
285
|
'''Return the C{Fsum(B{self}, B{other})}.
|
|
@@ -322,9 +321,9 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
322
321
|
cmp = __cmp__
|
|
323
322
|
|
|
324
323
|
def __divmod__(self, other):
|
|
325
|
-
'''Return C{divmod(B{self}, B{other})} as
|
|
326
|
-
|
|
327
|
-
and an L{Fsum}.
|
|
324
|
+
'''Return C{divmod(B{self}, B{other})} as a L{DivMod2Tuple}
|
|
325
|
+
with quotient C{div} an C{int} in Python 3+ or C{float}
|
|
326
|
+
in Python 2- and remainder C{mod} an L{Fsum}.
|
|
328
327
|
|
|
329
328
|
@arg other: An L{Fsum} or C{scalar} modulus.
|
|
330
329
|
|
|
@@ -431,8 +430,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
431
430
|
|
|
432
431
|
@see: Method L{Fsum.__divmod__}.
|
|
433
432
|
'''
|
|
434
|
-
self._fdivmod2(other, _mod_op_ + _fset_op_)
|
|
435
|
-
return self
|
|
433
|
+
return self._fdivmod2(other, _mod_op_ + _fset_op_).mod
|
|
436
434
|
|
|
437
435
|
def __imul__(self, other):
|
|
438
436
|
'''Apply C{B{self} *= B{other}} to this instance.
|
|
@@ -566,7 +564,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
566
564
|
@see: Method L{Fsum.__imod__}.
|
|
567
565
|
'''
|
|
568
566
|
f = self._copy_2(self.__mod__)
|
|
569
|
-
return f._fdivmod2(other, _mod_op_)
|
|
567
|
+
return f._fdivmod2(other, _mod_op_).mod
|
|
570
568
|
|
|
571
569
|
def __mul__(self, other):
|
|
572
570
|
'''Return C{B{self} * B{other}} as an L{Fsum}.
|
|
@@ -582,9 +580,10 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
582
580
|
return self._cmp_0(other, _ne_op_) != 0
|
|
583
581
|
|
|
584
582
|
def __neg__(self):
|
|
585
|
-
'''Return I{a copy of} this instance, negated.
|
|
583
|
+
'''Return I{a copy of} this instance, I{negated}.
|
|
586
584
|
'''
|
|
587
|
-
|
|
585
|
+
f = self._copy_2(self.__neg__)
|
|
586
|
+
return f._fset(self._neg)
|
|
588
587
|
|
|
589
588
|
def __pos__(self):
|
|
590
589
|
'''Return this instance I{as-is}, like C{float.__pos__()}.
|
|
@@ -604,7 +603,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
604
603
|
|
|
605
604
|
@see: Method L{Fsum.__iadd__}.
|
|
606
605
|
'''
|
|
607
|
-
f = self.
|
|
606
|
+
f = self._copy_2r(other, self.__radd__)
|
|
608
607
|
return f._fadd(self, _add_op_)
|
|
609
608
|
|
|
610
609
|
def __rdivmod__(self, other):
|
|
@@ -613,7 +612,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
613
612
|
|
|
614
613
|
@see: Method L{Fsum.__divmod__}.
|
|
615
614
|
'''
|
|
616
|
-
f = self.
|
|
615
|
+
f = self._copy_2r(other, self.__rdivmod__)
|
|
617
616
|
return f._fdivmod2(self, _divmod_op_)
|
|
618
617
|
|
|
619
618
|
# def __repr__(self):
|
|
@@ -626,7 +625,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
626
625
|
|
|
627
626
|
@see: Method L{Fsum.__ifloordiv__}.
|
|
628
627
|
'''
|
|
629
|
-
f = self.
|
|
628
|
+
f = self._copy_2r(other, self.__rfloordiv__)
|
|
630
629
|
return f._floordiv(self, _floordiv_op_)
|
|
631
630
|
|
|
632
631
|
def __rmatmul__(self, other): # PYCHOK no cover
|
|
@@ -638,15 +637,15 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
638
637
|
|
|
639
638
|
@see: Method L{Fsum.__imod__}.
|
|
640
639
|
'''
|
|
641
|
-
f = self.
|
|
642
|
-
return f._fdivmod2(self, _mod_op_)
|
|
640
|
+
f = self._copy_2r(other, self.__rmod__)
|
|
641
|
+
return f._fdivmod2(self, _mod_op_).mod
|
|
643
642
|
|
|
644
643
|
def __rmul__(self, other):
|
|
645
644
|
'''Return C{B{other} * B{self}} as an L{Fsum}.
|
|
646
645
|
|
|
647
646
|
@see: Method L{Fsum.__imul__}.
|
|
648
647
|
'''
|
|
649
|
-
f = self.
|
|
648
|
+
f = self._copy_2r(other, self.__rmul__)
|
|
650
649
|
return f._fmul(self, _mul_op_)
|
|
651
650
|
|
|
652
651
|
def __round__(self, *ndigits): # PYCHOK no cover
|
|
@@ -655,17 +654,15 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
655
654
|
@arg ndigits: Optional number of digits (C{int}).
|
|
656
655
|
'''
|
|
657
656
|
# <https://docs.Python.org/3.12/reference/datamodel.html?#object.__round__>
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
f._ps = [round(float(self), *ndigits)] # can be C{int}
|
|
661
|
-
return f
|
|
657
|
+
return _Fsum_ps(round(float(self), *ndigits), # can be C{int}
|
|
658
|
+
name=self.__round__.__name__)
|
|
662
659
|
|
|
663
660
|
def __rpow__(self, other, *mod):
|
|
664
661
|
'''Return C{B{other}**B{self}} as an L{Fsum}.
|
|
665
662
|
|
|
666
663
|
@see: Method L{Fsum.__ipow__}.
|
|
667
664
|
'''
|
|
668
|
-
f = self.
|
|
665
|
+
f = self._copy_2r(other, self.__rpow__)
|
|
669
666
|
return f._fpow(self, _pow_op_, *mod)
|
|
670
667
|
|
|
671
668
|
def __rsub__(self, other):
|
|
@@ -673,7 +670,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
673
670
|
|
|
674
671
|
@see: Method L{Fsum.__isub__}.
|
|
675
672
|
'''
|
|
676
|
-
f = self.
|
|
673
|
+
f = self._copy_2r(other, self.__rsub__)
|
|
677
674
|
return f._fsub(self, _sub_op_)
|
|
678
675
|
|
|
679
676
|
def __rtruediv__(self, other):
|
|
@@ -681,7 +678,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
681
678
|
|
|
682
679
|
@see: Method L{Fsum.__itruediv__}.
|
|
683
680
|
'''
|
|
684
|
-
f = self.
|
|
681
|
+
f = self._copy_2r(other, self.__rtruediv__)
|
|
685
682
|
return f._ftruediv(self, _truediv_op_)
|
|
686
683
|
|
|
687
684
|
def __str__(self):
|
|
@@ -759,14 +756,14 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
759
756
|
def _cmp_0(self, other, op):
|
|
760
757
|
'''(INTERNAL) Return C{scalar(self - B{other})} for 0-comparison.
|
|
761
758
|
'''
|
|
762
|
-
if
|
|
759
|
+
if isinstance(other, Fsum):
|
|
760
|
+
s = _fsum(self._ps_1(*other._ps))
|
|
761
|
+
elif isscalar(other):
|
|
763
762
|
if other:
|
|
764
763
|
s = _fsum(self._ps_1(other))
|
|
765
764
|
else:
|
|
766
765
|
s, r = self._fprs2
|
|
767
766
|
s = _signOf(s, -r)
|
|
768
|
-
elif isinstance(other, Fsum):
|
|
769
|
-
s = _fsum(self._ps_1(*other._ps))
|
|
770
767
|
else:
|
|
771
768
|
raise self._TypeError(op, other) # txt=_invalid_
|
|
772
769
|
return s
|
|
@@ -781,57 +778,28 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
781
778
|
f._ps = list(self._ps) # separate list
|
|
782
779
|
return f
|
|
783
780
|
|
|
784
|
-
def
|
|
785
|
-
'''(INTERNAL) Copy with/-out overriding C{partials}.
|
|
786
|
-
'''
|
|
787
|
-
# for x in xs:
|
|
788
|
-
# assert isscalar(x)
|
|
789
|
-
f = self._Fsum(self._n + len(xs), *xs)
|
|
790
|
-
if self.name:
|
|
791
|
-
f._name = self.name # .rename calls _update_attrs
|
|
792
|
-
return f
|
|
793
|
-
|
|
794
|
-
def _copy_2(self, which):
|
|
781
|
+
def _copy_2(self, which, name=NN):
|
|
795
782
|
'''(INTERNAL) Copy for I{dyadic} operators.
|
|
796
783
|
'''
|
|
784
|
+
n = name or which.__name__
|
|
797
785
|
# NOT .classof due to .Fdot(a, *b) args, etc.
|
|
798
|
-
f = _Named.copy(self, deep=False, name=
|
|
786
|
+
f = _Named.copy(self, deep=False, name=n)
|
|
799
787
|
# assert f._n == self._n
|
|
800
788
|
f._ps = list(self._ps) # separate list
|
|
801
789
|
return f
|
|
802
790
|
|
|
803
|
-
def
|
|
804
|
-
'''(INTERNAL) Negated copy for I{monadic} C{__abs__} and C{__neg__}.
|
|
805
|
-
'''
|
|
806
|
-
if self._ps:
|
|
807
|
-
f = self._Fsum(self._n)
|
|
808
|
-
f._ps[:] = self._ps_n()
|
|
809
|
-
# f._facc_up(up=False)
|
|
810
|
-
else:
|
|
811
|
-
f = self._Fsum(self._n, _0_0)
|
|
812
|
-
f._name = which.__name__ # .rename calls _update_attrs
|
|
813
|
-
return f
|
|
814
|
-
|
|
815
|
-
def _copy_r2(self, other, which):
|
|
791
|
+
def _copy_2r(self, other, which):
|
|
816
792
|
'''(INTERNAL) Copy for I{reverse-dyadic} operators.
|
|
817
793
|
'''
|
|
818
794
|
return other._copy_2(which) if isinstance(other, Fsum) else \
|
|
819
|
-
Fsum(other, name=which.__name__)
|
|
795
|
+
Fsum(other, name=which.__name__)
|
|
820
796
|
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
def _copy_up(self, _fprs2=False):
|
|
829
|
-
'''(INTERNAL) Minimal, anonymous copy.
|
|
830
|
-
'''
|
|
831
|
-
f = self._Fsum(self._n, *self._ps)
|
|
832
|
-
if _fprs2: # only the ._fprs2 2-tuple
|
|
833
|
-
Fsum._fprs2._update_from(f, self)
|
|
834
|
-
return f
|
|
797
|
+
# def _copy_RESIDUAL(self, other):
|
|
798
|
+
# '''(INTERNAL) Copy C{other._RESIDUAL}.
|
|
799
|
+
# '''
|
|
800
|
+
# R = other._RESIDUAL
|
|
801
|
+
# if R is not Fsum._RESIDUAL:
|
|
802
|
+
# self._RESIDUAL = R
|
|
835
803
|
|
|
836
804
|
def divmod(self, other):
|
|
837
805
|
'''Return C{divmod(B{self}, B{other})} as 2-tuple C{(quotient,
|
|
@@ -839,22 +807,30 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
839
807
|
|
|
840
808
|
@arg other: An L{Fsum} or C{scalar} divisor.
|
|
841
809
|
|
|
842
|
-
@return:
|
|
843
|
-
an C{int} in Python 3+ or
|
|
844
|
-
|
|
810
|
+
@return: A L{DivMod2Tuple}C{(div, mod)}, with quotient C{div}
|
|
811
|
+
an C{int} in Python 3+ or C{float} in Python 2- and
|
|
812
|
+
remainder C{mod} an L{Fsum} instance.
|
|
845
813
|
|
|
846
814
|
@see: Method L{Fsum.__itruediv__}.
|
|
847
815
|
'''
|
|
848
816
|
f = self._copy_2(self.divmod)
|
|
849
817
|
return f._fdivmod2(other, _divmod_op_)
|
|
850
818
|
|
|
851
|
-
def _Error(self, op, other, Error, **
|
|
819
|
+
def _Error(self, op, other, Error, **txt_cause):
|
|
852
820
|
'''(INTERNAL) Format an B{C{Error}} for C{{self} B{op} B{other}}.
|
|
853
821
|
'''
|
|
854
|
-
return Error(_SPACE_(self.toRepr(), op, repr(other)), **
|
|
822
|
+
return Error(_SPACE_(self.toRepr(), op, repr(other)), **txt_cause)
|
|
855
823
|
|
|
856
|
-
def _ErrorX(self, X,
|
|
857
|
-
'''(INTERNAL) Format
|
|
824
|
+
def _ErrorX(self, X, op, other, *mod):
|
|
825
|
+
'''(INTERNAL) Format the caught exception C{X}.
|
|
826
|
+
'''
|
|
827
|
+
E, t = _xError2(X)
|
|
828
|
+
if mod:
|
|
829
|
+
t = _COMMASPACE_(Fmt.PARENSPACED(mod=mod[0]), t)
|
|
830
|
+
return self._Error(op, other, E, txt=t, cause=X)
|
|
831
|
+
|
|
832
|
+
def _ErrorXs(self, X, xs, **kwds): # in .fmath
|
|
833
|
+
'''(INTERNAL) Format the caught exception C{X}.
|
|
858
834
|
'''
|
|
859
835
|
E, t = _xError2(X)
|
|
860
836
|
n = unstr(self.named3, *xs[:3], _ELLIPSIS=len(xs) > 3, **kwds)
|
|
@@ -866,13 +842,14 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
866
842
|
n, ps, _2s = 0, self._ps, _2sum
|
|
867
843
|
for x in xs: # _iter()
|
|
868
844
|
# assert isscalar(x) and isfinite(x)
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
845
|
+
if x:
|
|
846
|
+
i = 0
|
|
847
|
+
for p in ps:
|
|
848
|
+
x, p = _2s(x, p)
|
|
849
|
+
if p:
|
|
850
|
+
ps[i] = p
|
|
851
|
+
i += 1
|
|
852
|
+
ps[i:] = (x,) if x else ()
|
|
876
853
|
n += 1
|
|
877
854
|
# assert self._ps is ps
|
|
878
855
|
if n:
|
|
@@ -887,6 +864,38 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
887
864
|
'''
|
|
888
865
|
return self._facc(xs, **up) if xs else self
|
|
889
866
|
|
|
867
|
+
def _facc_power(self, power, xs, which): # in .fmath
|
|
868
|
+
'''(INTERNAL) Add each C{xs} as C{float(x**power)}.
|
|
869
|
+
'''
|
|
870
|
+
p = power
|
|
871
|
+
if isinstance(p, Fsum):
|
|
872
|
+
if p.is_exact:
|
|
873
|
+
return self._facc_power(p._fprs, xs, which)
|
|
874
|
+
_Pow = Fsum._pow_any
|
|
875
|
+
elif isint(p, both=True) and p >= 0:
|
|
876
|
+
_Pow, p = Fsum._pow_int, int(p)
|
|
877
|
+
else:
|
|
878
|
+
_Pow, p = Fsum._pow_scalar, _2float(power=p)
|
|
879
|
+
|
|
880
|
+
if p:
|
|
881
|
+
from math import pow as _pow
|
|
882
|
+
op = which.__name__
|
|
883
|
+
|
|
884
|
+
def _X(X):
|
|
885
|
+
f = _Pow(X, p, power, op)
|
|
886
|
+
try: # isinstance(f, Fsum)
|
|
887
|
+
return f._ps
|
|
888
|
+
except AttributeError: # scalar
|
|
889
|
+
return f,
|
|
890
|
+
|
|
891
|
+
def _x(x):
|
|
892
|
+
return _pow(float(x), p)
|
|
893
|
+
|
|
894
|
+
self._facc(_2yield(xs, 1, _X, _x)) # PYCHOK yield
|
|
895
|
+
else:
|
|
896
|
+
self._facc_(float(len(xs))) # x**0 == 1
|
|
897
|
+
return self
|
|
898
|
+
|
|
890
899
|
# def _facc_up(self, up=True):
|
|
891
900
|
# '''(INTERNAL) Update the C{partials}, by removing
|
|
892
901
|
# and re-accumulating the final C{partial}.
|
|
@@ -942,18 +951,18 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
942
951
|
'''
|
|
943
952
|
return self._facc(_2floats(xs, origin=1)) # PYCHOK yield
|
|
944
953
|
|
|
945
|
-
def _fadd(self, other, op): # in .fmath.Fhorner
|
|
954
|
+
def _fadd(self, other, op, **up): # in .fmath.Fhorner
|
|
946
955
|
'''(INTERNAL) Apply C{B{self} += B{other}}.
|
|
947
956
|
'''
|
|
948
957
|
if isinstance(other, Fsum):
|
|
949
958
|
if other is self:
|
|
950
|
-
self._facc_(*other._ps) # == ._facc(tuple(other._ps))
|
|
959
|
+
self._facc_(*other._ps, **up) # == ._facc(tuple(other._ps))
|
|
951
960
|
elif other._ps:
|
|
952
|
-
self._facc(other._ps)
|
|
961
|
+
self._facc(other._ps, **up)
|
|
953
962
|
elif not isscalar(other):
|
|
954
963
|
raise self._TypeError(op, other) # txt=_invalid_
|
|
955
964
|
elif other:
|
|
956
|
-
self._facc_(other)
|
|
965
|
+
self._facc_(other, **up)
|
|
957
966
|
return self
|
|
958
967
|
|
|
959
968
|
fcopy = copy # for backward compatibility
|
|
@@ -961,13 +970,12 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
961
970
|
fdivmod = __divmod__ # for backward compatibility
|
|
962
971
|
|
|
963
972
|
def _fdivmod2(self, other, op):
|
|
964
|
-
'''(INTERNAL) C{
|
|
965
|
-
(C{int} or C{float}, remainder C{self}).
|
|
973
|
+
'''(INTERNAL) Apply C{B{self} %= B{other}} and return a L{DivMod2Tuple}.
|
|
966
974
|
'''
|
|
967
975
|
# result mostly follows CPython function U{float_divmod
|
|
968
976
|
# <https://GitHub.com/python/cpython/blob/main/Objects/floatobject.c>},
|
|
969
977
|
# but at least divmod(-3, 2) equals Cpython's result (-2, 1).
|
|
970
|
-
q = self.
|
|
978
|
+
q = self._copy_2(self._fdivmod2)._ftruediv(other, op).floor
|
|
971
979
|
if q: # == float // other == floor(float / other)
|
|
972
980
|
self -= other * q
|
|
973
981
|
|
|
@@ -975,22 +983,20 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
975
983
|
if s and self.signOf() == -s: # PYCHOK no cover
|
|
976
984
|
self += other
|
|
977
985
|
q -= 1
|
|
978
|
-
|
|
979
|
-
# t = self.signOf()
|
|
986
|
+
# t = self.signOf()
|
|
980
987
|
# if t and t != s:
|
|
981
|
-
# from pygeodesy.errors import _AssertionError
|
|
982
988
|
# raise self._Error(op, other, _AssertionError, txt=signOf.__name__)
|
|
983
|
-
return q, self # q is C{int} in Python 3+, but C{float} in Python 2-
|
|
989
|
+
return DivMod2Tuple(q, self) # q is C{int} in Python 3+, but C{float} in Python 2-
|
|
984
990
|
|
|
985
991
|
def _finite(self, other, op=None):
|
|
986
992
|
'''(INTERNAL) Return B{C{other}} if C{finite}.
|
|
987
993
|
'''
|
|
988
994
|
if _isfinite(other):
|
|
989
995
|
return other
|
|
990
|
-
raise ValueError(_not_finite_) if
|
|
996
|
+
raise ValueError(_not_finite_) if op is None else \
|
|
991
997
|
self._ValueError(op, other, txt=_not_finite_)
|
|
992
998
|
|
|
993
|
-
def fint(self, raiser=True, name
|
|
999
|
+
def fint(self, raiser=True, **name):
|
|
994
1000
|
'''Return this instance' current running sum as C{integer}.
|
|
995
1001
|
|
|
996
1002
|
@kwarg raiser: If C{True} throw a L{ResidualError} if the
|
|
@@ -1007,8 +1013,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1007
1013
|
if r and raiser:
|
|
1008
1014
|
t = _stresidual(_integer_, r)
|
|
1009
1015
|
raise ResidualError(_integer_, i, txt=t)
|
|
1010
|
-
|
|
1011
|
-
return
|
|
1016
|
+
f = self._copy_2(self.fint, **name)
|
|
1017
|
+
return f._fset(i)
|
|
1012
1018
|
|
|
1013
1019
|
def fint2(self, **name):
|
|
1014
1020
|
'''Return this instance' current running sum as C{int} and
|
|
@@ -1026,9 +1032,9 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1026
1032
|
def _fint2(self): # see ._fset
|
|
1027
1033
|
'''(INTERNAL) Get 2-tuple (C{int}, I{integer} residual).
|
|
1028
1034
|
'''
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1035
|
+
s, r = self._fprs2
|
|
1036
|
+
i = int(s)
|
|
1037
|
+
r = _fsum(self._ps_1(i)) if r else float(s - i)
|
|
1032
1038
|
return i, (r or INT0)
|
|
1033
1039
|
|
|
1034
1040
|
@deprecated_property_RO
|
|
@@ -1048,7 +1054,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1048
1054
|
'''
|
|
1049
1055
|
s, r = self._fprs2
|
|
1050
1056
|
f = _floor(s) + _floor(r) + 1
|
|
1051
|
-
while
|
|
1057
|
+
while (f - s) > r: # f > (s + r)
|
|
1052
1058
|
f -= 1
|
|
1053
1059
|
return f
|
|
1054
1060
|
|
|
@@ -1058,25 +1064,25 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1058
1064
|
'''Apply C{B{self} //= B{other}}.
|
|
1059
1065
|
'''
|
|
1060
1066
|
q = self._ftruediv(other, op) # == self
|
|
1061
|
-
return self._fset(q.floor
|
|
1067
|
+
return self._fset(q.floor) # floor(q)
|
|
1062
1068
|
|
|
1063
1069
|
fmul = __imul__ # for backward compatibility
|
|
1064
1070
|
|
|
1065
1071
|
def _fmul(self, other, op):
|
|
1066
1072
|
'''(INTERNAL) Apply C{B{self} *= B{other}}.
|
|
1067
1073
|
'''
|
|
1068
|
-
if
|
|
1074
|
+
if isinstance(other, Fsum):
|
|
1075
|
+
if len(self._ps) != 1:
|
|
1076
|
+
f = self._mul_Fsum(other, op)
|
|
1077
|
+
elif len(other._ps) != 1: # and len(self._ps) == 1
|
|
1078
|
+
f = other._mul_scalar(self._ps[0], op)
|
|
1079
|
+
else: # len(other._ps) == len(self._ps) == 1
|
|
1080
|
+
f = self._finite(self._ps[0] * other._ps[0])
|
|
1081
|
+
elif isscalar(other):
|
|
1069
1082
|
f = self._mul_scalar(other, op)
|
|
1070
|
-
|
|
1083
|
+
else:
|
|
1071
1084
|
raise self._TypeError(op, other) # txt=_invalid_
|
|
1072
|
-
|
|
1073
|
-
f = self._mul_Fsum(other, op)
|
|
1074
|
-
elif len(other._ps) != 1: # len(self._ps) == 1
|
|
1075
|
-
f = other._copy_up()._mul_scalar(self._ps[0], op)
|
|
1076
|
-
else: # len(other._ps) == len(self._ps) == 1
|
|
1077
|
-
s = self._finite(self._ps[0] * other._ps[0])
|
|
1078
|
-
return self._fset(s, asis=True, n=len(self) + 1)
|
|
1079
|
-
return self._fset(f)
|
|
1085
|
+
return self._fset(f) # n=len(self) + 1
|
|
1080
1086
|
|
|
1081
1087
|
def fover(self, over):
|
|
1082
1088
|
'''Apply C{B{self} /= B{over}} and summate.
|
|
@@ -1094,30 +1100,20 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1094
1100
|
def _fpow(self, other, op, *mod):
|
|
1095
1101
|
'''Apply C{B{self} **= B{other}}, optional B{C{mod}} or C{None}.
|
|
1096
1102
|
'''
|
|
1097
|
-
if mod
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1103
|
+
if mod:
|
|
1104
|
+
if mod[0] is not None: # == 3-arg C{pow}
|
|
1105
|
+
f = self._pow_3(other, mod[0], op)
|
|
1106
|
+
elif self.is_integer():
|
|
1107
|
+
# return an exact C{int} for C{int}**C{int}
|
|
1108
|
+
x = _2scalar(other) # C{int}, C{float} or other
|
|
1109
|
+
i = self._fint2[0] # assert _fint2[1] == 0
|
|
1110
|
+
f = self._pow_2(i, x, other, op) if isscalar(x) else \
|
|
1111
|
+
_Fsum_ps(i)._pow_any(x, other, op)
|
|
1112
|
+
else: # mod[0] is None, power(self, other)
|
|
1113
|
+
f = self._pow_any(other, other, op)
|
|
1104
1114
|
else: # pow(self, other) == pow(self, other, None)
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
x, r = other._fprs2
|
|
1108
|
-
if r:
|
|
1109
|
-
if self._raiser(r, x):
|
|
1110
|
-
raise self._ResidualError(op, other, r)
|
|
1111
|
-
p = self._pow_scalar(r, other, op)
|
|
1112
|
-
# p = _2scalar(p) # _raiser = None
|
|
1113
|
-
elif not isscalar(other):
|
|
1114
|
-
raise self._TypeError(op, other) # txt=_invalid_
|
|
1115
|
-
else:
|
|
1116
|
-
x = self._finite(other, op)
|
|
1117
|
-
s = self._pow_scalar(x, other, op)
|
|
1118
|
-
if p is not None:
|
|
1119
|
-
s *= p
|
|
1120
|
-
return self._fset(s, asis=isint(s), n=max(len(self), 1))
|
|
1115
|
+
f = self._pow_any(other, other, op)
|
|
1116
|
+
return self._fset(f, asis=isint(f)) # n=max(len(self), 1)
|
|
1121
1117
|
|
|
1122
1118
|
@Property_RO
|
|
1123
1119
|
def _fprs(self):
|
|
@@ -1127,30 +1123,28 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1127
1123
|
@note: The precision running C{fsum} after a C{//=} or
|
|
1128
1124
|
C{//} C{floor} division is C{int} in Python 3+.
|
|
1129
1125
|
'''
|
|
1130
|
-
|
|
1131
|
-
n = len(ps) - 1
|
|
1132
|
-
if n > 1:
|
|
1133
|
-
s = _psum(ps)
|
|
1134
|
-
elif n > 0: # len(ps) == 2
|
|
1135
|
-
s, p = _2sum(*ps) if ps[1] else ps
|
|
1136
|
-
ps[:] = ([p, s] if s else [p]) if p else [s]
|
|
1137
|
-
elif n < 0: # see L{Fsum.__init__}
|
|
1138
|
-
s = _0_0
|
|
1139
|
-
ps[:] = [s]
|
|
1140
|
-
else: # len(ps) == 1
|
|
1141
|
-
s = ps[0]
|
|
1142
|
-
# assert self._ps is ps
|
|
1143
|
-
# assert Fsum._fprs2.name not in self.__dict__
|
|
1144
|
-
return s
|
|
1126
|
+
return self._fprs2.fsum
|
|
1145
1127
|
|
|
1146
1128
|
@Property_RO
|
|
1147
1129
|
def _fprs2(self):
|
|
1148
1130
|
'''(INTERNAL) Get and cache this instance' precision
|
|
1149
1131
|
running sum and residual (L{Fsum2Tuple}).
|
|
1150
1132
|
'''
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1133
|
+
ps = self._ps
|
|
1134
|
+
n = len(ps) - 2
|
|
1135
|
+
if n > 0: # len(ps) > 2
|
|
1136
|
+
s = _psum(ps)
|
|
1137
|
+
r = _fsum(self._ps_1(s)) or INT0
|
|
1138
|
+
elif n == 0: # len(ps) == 2
|
|
1139
|
+
ps[:] = _2ps(*_2sum(*ps))
|
|
1140
|
+
r, s = (INT0, ps[0]) if len(ps) != 2 else ps
|
|
1141
|
+
elif ps: # len(ps) == 1
|
|
1142
|
+
s, r = ps[0], INT0
|
|
1143
|
+
else: # len(ps) == 0
|
|
1144
|
+
s, r = _0_0, INT0
|
|
1145
|
+
ps[:] = s,
|
|
1146
|
+
# assert self._ps is ps
|
|
1147
|
+
return Fsum2Tuple(s, r)
|
|
1154
1148
|
|
|
1155
1149
|
# def _fpsqz(self):
|
|
1156
1150
|
# '''(INTERNAL) Compress, squeeze the C{partials}.
|
|
@@ -1159,15 +1153,29 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1159
1153
|
# _ = self._fprs
|
|
1160
1154
|
# return self
|
|
1161
1155
|
|
|
1162
|
-
def
|
|
1156
|
+
def fset_(self, *xs):
|
|
1157
|
+
'''Replace this instance' value with C{xs}.
|
|
1158
|
+
|
|
1159
|
+
@arg xs: Optional, new values (C{scalar} or L{Fsum}
|
|
1160
|
+
instances), all positional.
|
|
1161
|
+
|
|
1162
|
+
@return: This instance (C{Fsum}).
|
|
1163
|
+
|
|
1164
|
+
@see: Method L{Fsum.fadd} for further details.
|
|
1165
|
+
'''
|
|
1166
|
+
self._n = 0
|
|
1167
|
+
self._ps[:] = 0,
|
|
1168
|
+
return self.fadd(xs) if xs else self._update()
|
|
1169
|
+
|
|
1170
|
+
def _fset(self, other, asis=True, n=0):
|
|
1163
1171
|
'''(INTERNAL) Overwrite this instance with an other or a C{scalar}.
|
|
1164
1172
|
'''
|
|
1165
1173
|
if other is self:
|
|
1166
1174
|
pass # from ._fmul, ._ftruediv and ._pow_scalar
|
|
1167
1175
|
elif isinstance(other, Fsum):
|
|
1168
|
-
self._n = other._n
|
|
1176
|
+
self._n = n or other._n
|
|
1169
1177
|
self._ps[:] = other._ps
|
|
1170
|
-
|
|
1178
|
+
# self._copy_RESIDUAL(other)
|
|
1171
1179
|
# use or zap the C{Property_RO} values
|
|
1172
1180
|
Fsum._fint2._update_from(self, other)
|
|
1173
1181
|
Fsum._fprs ._update_from(self, other)
|
|
@@ -1176,65 +1184,65 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1176
1184
|
s = other if asis else float(other)
|
|
1177
1185
|
i = int(s) # see ._fint2
|
|
1178
1186
|
t = i, ((s - i) or INT0)
|
|
1179
|
-
self._n =
|
|
1180
|
-
self._ps[:] =
|
|
1181
|
-
#
|
|
1187
|
+
self._n = n or 1
|
|
1188
|
+
self._ps[:] = s,
|
|
1189
|
+
# Property_ROs _fint2, _fprs and _fprs2 can't be a Property:
|
|
1182
1190
|
# Property's _fset zaps the value just set by the @setter
|
|
1183
1191
|
self.__dict__.update(_fint2=t, _fprs=s, _fprs2=Fsum2Tuple(s, INT0))
|
|
1184
1192
|
else: # PYCHOK no cover
|
|
1185
1193
|
raise self._TypeError(_fset_op_, other) # txt=_invalid_
|
|
1186
1194
|
return self
|
|
1187
1195
|
|
|
1196
|
+
def _fset_ps(self, other, n=0): # in .fmath
|
|
1197
|
+
'''(INTERNAL) Set a known C{Fsum} or C{scalar}.
|
|
1198
|
+
'''
|
|
1199
|
+
if isinstance(other, Fsum):
|
|
1200
|
+
self._n = n or other._n
|
|
1201
|
+
self._ps[:] = other._ps
|
|
1202
|
+
else: # assert isscalar(other)
|
|
1203
|
+
self._n = n or 1
|
|
1204
|
+
self._ps[:] = other,
|
|
1205
|
+
|
|
1188
1206
|
def fsub(self, xs=()):
|
|
1189
|
-
'''Subtract an iterable of C{scalar} or L{Fsum} instances
|
|
1190
|
-
|
|
1207
|
+
'''Subtract an iterable of C{scalar} or L{Fsum} instances from
|
|
1208
|
+
this instance.
|
|
1191
1209
|
|
|
1192
|
-
@arg xs: Iterable, list, tuple. etc. (C{scalar}
|
|
1193
|
-
|
|
1210
|
+
@arg xs: Iterable, list, tuple. etc. (C{scalar} or L{Fsum}
|
|
1211
|
+
instances).
|
|
1194
1212
|
|
|
1195
1213
|
@return: This instance, updated (L{Fsum}).
|
|
1196
1214
|
|
|
1197
1215
|
@see: Method L{Fsum.fadd}.
|
|
1198
1216
|
'''
|
|
1199
|
-
return self._facc(_2floats(xs,
|
|
1217
|
+
return self._facc(_2floats(xs, neg=True)) if xs else self # PYCHOK yield
|
|
1200
1218
|
|
|
1201
1219
|
def fsub_(self, *xs):
|
|
1202
|
-
'''Subtract all positional C{scalar} or L{Fsum} instances
|
|
1203
|
-
|
|
1220
|
+
'''Subtract all positional C{scalar} or L{Fsum} instances from
|
|
1221
|
+
this instance.
|
|
1204
1222
|
|
|
1205
|
-
@arg xs: Values to subtract (C{scalar} or
|
|
1206
|
-
|
|
1223
|
+
@arg xs: Values to subtract (C{scalar} or L{Fsum} instances),
|
|
1224
|
+
all positional.
|
|
1207
1225
|
|
|
1208
1226
|
@return: This instance, updated (L{Fsum}).
|
|
1209
1227
|
|
|
1210
1228
|
@see: Method L{Fsum.fadd}.
|
|
1211
1229
|
'''
|
|
1212
|
-
return self._facc(_2floats(xs, origin=1,
|
|
1230
|
+
return self._facc(_2floats(xs, origin=1, neg=True)) if xs else self # PYCHOK yield
|
|
1213
1231
|
|
|
1214
1232
|
def _fsub(self, other, op):
|
|
1215
1233
|
'''(INTERNAL) Apply C{B{self} -= B{other}}.
|
|
1216
1234
|
'''
|
|
1217
1235
|
if isinstance(other, Fsum):
|
|
1218
1236
|
if other is self: # or other._fprs2 == self._fprs2:
|
|
1219
|
-
self._fset(_0_0
|
|
1237
|
+
self._fset(_0_0) # n=len(self) * 2, self -= self
|
|
1220
1238
|
elif other._ps:
|
|
1221
|
-
self._facc(other.
|
|
1239
|
+
self._facc(other._ps_neg)
|
|
1222
1240
|
elif not isscalar(other):
|
|
1223
1241
|
raise self._TypeError(op, other) # txt=_invalid_
|
|
1224
1242
|
elif self._finite(other, op):
|
|
1225
1243
|
self._facc_(-other)
|
|
1226
1244
|
return self
|
|
1227
1245
|
|
|
1228
|
-
def _Fsum(self, n, *ps):
|
|
1229
|
-
'''(INTERNAL) New L{Fsum} instance.
|
|
1230
|
-
'''
|
|
1231
|
-
f = Fsum()
|
|
1232
|
-
f._n = n
|
|
1233
|
-
if ps:
|
|
1234
|
-
f._ps[:] = ps
|
|
1235
|
-
f._copy_RESIDUAL(self)
|
|
1236
|
-
return f
|
|
1237
|
-
|
|
1238
1246
|
def fsum(self, xs=()):
|
|
1239
1247
|
'''Add more C{scalar} or L{Fsum} instances and summate.
|
|
1240
1248
|
|
|
@@ -1263,12 +1271,12 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1263
1271
|
f = self._facc(_2floats(xs, origin=1)) if xs else self # PYCHOK yield
|
|
1264
1272
|
return f._fprs
|
|
1265
1273
|
|
|
1266
|
-
def fsum2(self, xs=(),
|
|
1274
|
+
def fsum2(self, xs=(), name=NN):
|
|
1267
1275
|
'''Add more C{scalar} or L{Fsum} instances and return the
|
|
1268
1276
|
current precision running sum and the C{residual}.
|
|
1269
1277
|
|
|
1270
|
-
@kwarg xs: Iterable, list, tuple, etc. (C{scalar} or
|
|
1271
|
-
|
|
1278
|
+
@kwarg xs: Iterable, list, tuple, etc. (C{scalar} or L{Fsum}
|
|
1279
|
+
instances).
|
|
1272
1280
|
@kwarg name: Optional name (C{str}).
|
|
1273
1281
|
|
|
1274
1282
|
@return: L{Fsum2Tuple}C{(fsum, residual)} with C{fsum} the
|
|
@@ -1282,7 +1290,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1282
1290
|
f = self._facc(_2floats(xs)) if xs else self # PYCHOK yield
|
|
1283
1291
|
t = f._fprs2
|
|
1284
1292
|
if name:
|
|
1285
|
-
t = t.dup(name=
|
|
1293
|
+
t = t.dup(name=name)
|
|
1286
1294
|
return t
|
|
1287
1295
|
|
|
1288
1296
|
def fsum2_(self, *xs):
|
|
@@ -1318,16 +1326,16 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1318
1326
|
'''
|
|
1319
1327
|
n = _1_0
|
|
1320
1328
|
if isinstance(other, Fsum):
|
|
1321
|
-
if other is self or other
|
|
1322
|
-
return self._fset(_1_0
|
|
1329
|
+
if other is self or other == self:
|
|
1330
|
+
return self._fset(_1_0) # n=len(self)
|
|
1323
1331
|
d, r = other._fprs2
|
|
1324
1332
|
if r:
|
|
1325
|
-
if
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
raise self._ResidualError(op, other, r)
|
|
1329
|
-
else:
|
|
1333
|
+
if d:
|
|
1334
|
+
if self._raiser(r, d):
|
|
1335
|
+
raise self._ResidualError(op, other, r)
|
|
1330
1336
|
d, n = other.as_integer_ratio()
|
|
1337
|
+
else: # PYCHOK no cover
|
|
1338
|
+
d = r
|
|
1331
1339
|
elif isscalar(other):
|
|
1332
1340
|
d = other
|
|
1333
1341
|
else: # PYCHOK no cover
|
|
@@ -1335,11 +1343,10 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1335
1343
|
try:
|
|
1336
1344
|
s = 0 if isinf(d) else (
|
|
1337
1345
|
d if isnan(d) else self._finite(n / d))
|
|
1338
|
-
except Exception as
|
|
1339
|
-
|
|
1340
|
-
raise self._Error(op, other, E, txt=t)
|
|
1346
|
+
except Exception as X:
|
|
1347
|
+
raise self._ErrorX(X, op, other)
|
|
1341
1348
|
f = self._mul_scalar(s, _mul_op_) # handles 0, NAN, etc.
|
|
1342
|
-
return self._fset(f)
|
|
1349
|
+
return self._fset(f, asis=False)
|
|
1343
1350
|
|
|
1344
1351
|
@property_RO
|
|
1345
1352
|
def imag(self):
|
|
@@ -1387,9 +1394,9 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1387
1394
|
return False if r else True
|
|
1388
1395
|
|
|
1389
1396
|
def is_math_fsum(self):
|
|
1390
|
-
'''Return whether functions L{fsum}, L{fsum_}, L{fsum1}
|
|
1391
|
-
|
|
1392
|
-
|
|
1397
|
+
'''Return whether functions L{fsum}, L{fsum_}, L{fsum1} and
|
|
1398
|
+
L{fsum1_} plus partials summation are based on Python's
|
|
1399
|
+
C{math.fsum} or not.
|
|
1393
1400
|
|
|
1394
1401
|
@return: C{2} if all functions and partials summation
|
|
1395
1402
|
are based on C{math.fsum}, C{True} if only
|
|
@@ -1400,24 +1407,34 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1400
1407
|
f = Fsum._math_fsum
|
|
1401
1408
|
return 2 if _psum is f else bool(f)
|
|
1402
1409
|
|
|
1403
|
-
def _mul_Fsum(self, other, op=_mul_op_):
|
|
1404
|
-
'''(INTERNAL) Return C{B{self} * Fsum B{other}} as L{Fsum}.
|
|
1410
|
+
def _mul_Fsum(self, other, op=_mul_op_): # in .fmath.Fhorner
|
|
1411
|
+
'''(INTERNAL) Return C{B{self} * Fsum B{other}} as L{Fsum} or C{0}.
|
|
1405
1412
|
'''
|
|
1406
1413
|
# assert isinstance(other, Fsum)
|
|
1407
|
-
|
|
1414
|
+
if self._ps and other._ps:
|
|
1415
|
+
f = _Fsum_xs(self._ps_mul(op, *other._ps))
|
|
1416
|
+
else:
|
|
1417
|
+
f = _0_0
|
|
1418
|
+
return f
|
|
1408
1419
|
|
|
1409
|
-
def _mul_scalar(self, factor, op):
|
|
1410
|
-
'''(INTERNAL) Return C{B{self} * scalar B{factor}} as L{Fsum} or C{
|
|
1420
|
+
def _mul_scalar(self, factor, op): # in .fmath.Fhorner
|
|
1421
|
+
'''(INTERNAL) Return C{B{self} * scalar B{factor}} as L{Fsum}, C{0} or C{self}.
|
|
1411
1422
|
'''
|
|
1412
1423
|
# assert isscalar(factor)
|
|
1413
|
-
if self._finite(factor, op)
|
|
1414
|
-
if factor == _1_0
|
|
1415
|
-
|
|
1416
|
-
|
|
1424
|
+
if self._ps and self._finite(factor, op):
|
|
1425
|
+
f = self if factor == _1_0 else (
|
|
1426
|
+
self._neg if factor == _N_1_0 else
|
|
1427
|
+
_Fsum_xs(self._ps_mul(op, factor))) # PYCHOK indent
|
|
1417
1428
|
else:
|
|
1418
|
-
f =
|
|
1429
|
+
f = _0_0
|
|
1419
1430
|
return f
|
|
1420
1431
|
|
|
1432
|
+
@property_RO
|
|
1433
|
+
def _neg(self):
|
|
1434
|
+
'''(INTERNAL) Return C{-self}.
|
|
1435
|
+
'''
|
|
1436
|
+
return _Fsum_ps(*self._ps_neg) if self._ps else NEG0
|
|
1437
|
+
|
|
1421
1438
|
@property_RO
|
|
1422
1439
|
def partials(self):
|
|
1423
1440
|
'''Get this instance' current partial sums (C{tuple} of C{float}s and/or C{int}s).
|
|
@@ -1436,36 +1453,30 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1436
1453
|
|
|
1437
1454
|
@note: If B{C{mod}} is given as C{None}, the result will be an
|
|
1438
1455
|
C{integer} L{Fsum} provided this instance C{is_integer}
|
|
1439
|
-
or set C{integer} with L{Fsum.fint}.
|
|
1456
|
+
or set to C{integer} with L{Fsum.fint}.
|
|
1440
1457
|
|
|
1441
1458
|
@see: Methods L{Fsum.__ipow__}, L{Fsum.fint} and L{Fsum.is_integer}.
|
|
1442
1459
|
'''
|
|
1443
1460
|
f = self._copy_2(self.pow)
|
|
1444
|
-
|
|
1445
|
-
f._pow_int(x, x, _pow_op_) # f **= x
|
|
1446
|
-
else:
|
|
1447
|
-
f._fpow(x, _pow_op_, *mod) # f = pow(f, x, *mod)
|
|
1448
|
-
return f
|
|
1461
|
+
return f._fpow(x, _pow_op_, *mod) # f = pow(f, x, *mod)
|
|
1449
1462
|
|
|
1450
1463
|
def _pow_0_1(self, x, other):
|
|
1451
1464
|
'''(INTERNAL) Return B{C{self}**1} or C{B{self}**0 == 1.0}.
|
|
1452
1465
|
'''
|
|
1453
|
-
return self if x else (1 if
|
|
1466
|
+
return self if x else (1 if isint(other) and self.is_integer() else _1_0)
|
|
1454
1467
|
|
|
1455
|
-
def _pow_2(self, x, other, op):
|
|
1456
|
-
'''(INTERNAL) 2-arg C{pow(B{
|
|
1468
|
+
def _pow_2(self, b, x, other, op):
|
|
1469
|
+
'''(INTERNAL) 2-arg C{pow(B{b}, scalar B{x})} embellishing errors.
|
|
1457
1470
|
'''
|
|
1458
|
-
# assert
|
|
1459
|
-
b = self._ps[0] # assert isscalar(b)
|
|
1471
|
+
# assert isscalar(b) and isscalar(x)
|
|
1460
1472
|
try: # type(s) == type(x) if x in (_1_0, 1)
|
|
1461
1473
|
s = pow(b, x) # -1**2.3 == -(1**2.3)
|
|
1462
1474
|
if not iscomplex(s):
|
|
1463
1475
|
return self._finite(s) # 0**INF == 0.0, 1**INF==1.0
|
|
1464
1476
|
# neg**frac == complex in Python 3+, but ValueError in 2-
|
|
1465
|
-
|
|
1466
|
-
except Exception as
|
|
1467
|
-
|
|
1468
|
-
raise self._Error(op, other, E, txt=t)
|
|
1477
|
+
raise ValueError(_strcomplex(s, b, x)) # PYCHOK no cover
|
|
1478
|
+
except Exception as X:
|
|
1479
|
+
raise self._ErrorX(X, op, other)
|
|
1469
1480
|
|
|
1470
1481
|
def _pow_3(self, other, mod, op):
|
|
1471
1482
|
'''(INTERNAL) 3-arg C{pow(B{self}, B{other}, int B{mod} or C{None})}.
|
|
@@ -1473,49 +1484,71 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1473
1484
|
b, r = self._fprs2 if mod is None else self._fint2
|
|
1474
1485
|
if r and self._raiser(r, b):
|
|
1475
1486
|
t = _non_zero_ if mod is None else _integer_
|
|
1476
|
-
|
|
1487
|
+
t = _stresidual(t, r, mod=mod)
|
|
1488
|
+
raise self._Error(op, other, ResidualError, txt=t)
|
|
1489
|
+
|
|
1490
|
+
try: # b, other, mod all C{int}, unless C{mod} is C{None}
|
|
1491
|
+
x = _2scalar(other, _raiser=self._raiser)
|
|
1492
|
+
s = pow(b, x, mod)
|
|
1493
|
+
if not iscomplex(s):
|
|
1494
|
+
return self._finite(s)
|
|
1495
|
+
# neg**frac == complex in Python 3+, but ValueError in 2-
|
|
1496
|
+
raise ValueError(_strcomplex(s, b, x, mod)) # PYCHOK no cover
|
|
1497
|
+
except Exception as X:
|
|
1498
|
+
raise self._ErrorX(X, op, other, mod)
|
|
1499
|
+
|
|
1500
|
+
def _pow_any(self, other, unused, op):
|
|
1501
|
+
'''Return C{B{self} ** B{other}}.
|
|
1502
|
+
'''
|
|
1503
|
+
if isinstance(other, Fsum):
|
|
1504
|
+
x, r = other._fprs2
|
|
1505
|
+
f = self._pow_scalar(x, other, op)
|
|
1506
|
+
if r:
|
|
1507
|
+
if self._raiser(r, x):
|
|
1508
|
+
raise self._ResidualError(op, other, r)
|
|
1509
|
+
s = self._pow_scalar(r, other, op)
|
|
1510
|
+
# s = _2scalar(s) # _raiser = None
|
|
1511
|
+
f *= s
|
|
1512
|
+
elif isscalar(other):
|
|
1513
|
+
x = self._finite(other, op)
|
|
1514
|
+
f = self._pow_scalar(x, other, op)
|
|
1477
1515
|
else:
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
s = pow(b, x, mod)
|
|
1481
|
-
if not iscomplex(s):
|
|
1482
|
-
return self._finite(s)
|
|
1483
|
-
# neg**frac == complex in Python 3+, but ValueError in 2-
|
|
1484
|
-
E, t = _ValueError, _strcomplex(s, b, x, mod) # PYCHOK no cover
|
|
1485
|
-
except Exception as x:
|
|
1486
|
-
E, t = _xError2(x)
|
|
1487
|
-
t = _COMMASPACE_(Fmt.PARENSPACED(mod=mod), t)
|
|
1488
|
-
raise self._Error(op, other, E, txt=t)
|
|
1516
|
+
raise self._TypeError(op, other) # txt=_invalid_
|
|
1517
|
+
return f
|
|
1489
1518
|
|
|
1490
1519
|
def _pow_int(self, x, other, op):
|
|
1491
1520
|
'''(INTERNAL) Return C{B{self} **= B{x}} for C{int B{x} >= 0}.
|
|
1492
1521
|
'''
|
|
1493
1522
|
# assert isint(x) and x >= 0
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1523
|
+
ps = self._ps
|
|
1524
|
+
if len(ps) > 1:
|
|
1525
|
+
f = self
|
|
1526
|
+
if x > 4:
|
|
1497
1527
|
m = 1 # single-bit mask
|
|
1498
|
-
if x & m:
|
|
1528
|
+
if (x & m):
|
|
1499
1529
|
x -= m # x ^= m
|
|
1500
|
-
f = p._copy_up()
|
|
1501
1530
|
else:
|
|
1502
|
-
f =
|
|
1531
|
+
f = _Fsum_ps(_1_0)
|
|
1532
|
+
p = self
|
|
1503
1533
|
while x:
|
|
1504
1534
|
p = p._mul_Fsum(p, op) # p **= 2
|
|
1505
1535
|
m += m # m <<= 1
|
|
1506
|
-
if x & m:
|
|
1536
|
+
if (x & m):
|
|
1507
1537
|
x -= m # x ^= m
|
|
1508
1538
|
f = f._mul_Fsum(p, op) # f *= p
|
|
1509
|
-
elif x > 1: # self**2
|
|
1510
|
-
f =
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1539
|
+
elif x > 1: # self**2, 3 or 4
|
|
1540
|
+
f = f._mul_Fsum(f, op)
|
|
1541
|
+
if x > 2: # self**3 or 4
|
|
1542
|
+
p = self if x < 4 else f
|
|
1543
|
+
f = f._mul_Fsum(p, op)
|
|
1544
|
+
else: # self**1 or self**0 == 1 or _1_0
|
|
1545
|
+
f = f._pow_0_1(x, other)
|
|
1546
|
+
elif ps: # self._ps[0]**x
|
|
1547
|
+
f = self._pow_2(ps[0], x, other, op)
|
|
1515
1548
|
else: # PYCHOK no cover
|
|
1516
1549
|
# 0**pos_int == 0, but 0**0 == 1
|
|
1517
1550
|
f = 0 if x else 1 # like ._fprs
|
|
1518
|
-
return
|
|
1551
|
+
return f
|
|
1519
1552
|
|
|
1520
1553
|
def _pow_scalar(self, x, other, op):
|
|
1521
1554
|
'''(INTERNAL) Return C{self**B{x}} for C{scalar B{x}}.
|
|
@@ -1526,26 +1559,21 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1526
1559
|
y = abs(x)
|
|
1527
1560
|
if y > 1:
|
|
1528
1561
|
if r:
|
|
1529
|
-
f = self.
|
|
1562
|
+
f = self._pow_int(y, other, op)
|
|
1530
1563
|
if x > 0: # > 1
|
|
1531
1564
|
return f
|
|
1532
1565
|
# assert x < 0 # < -1
|
|
1533
|
-
s, r = f._fprs2
|
|
1566
|
+
s, r = f._fprs2 if isinstance(f, Fsum) else (f, 0)
|
|
1534
1567
|
if r:
|
|
1535
|
-
return
|
|
1568
|
+
return _Fsum_ps(_1_0)._ftruediv(f, op)
|
|
1536
1569
|
# use **= -1 for the CPython float_pow
|
|
1537
1570
|
# error if s is zero, and not s = 1 / s
|
|
1538
1571
|
x = -1
|
|
1539
|
-
# elif y > 1: # self**2 or self**-2
|
|
1540
|
-
# f = self._mul_Fsum(self, op)
|
|
1541
|
-
# if x < 0:
|
|
1542
|
-
# f = f._copy_0(_1_0)._ftruediv(f, op)
|
|
1543
|
-
# return f
|
|
1544
1572
|
elif x < 0: # self**-1 == 1 / self
|
|
1545
1573
|
if r:
|
|
1546
|
-
return
|
|
1574
|
+
return _Fsum_ps(_1_0)._ftruediv(self, op)
|
|
1547
1575
|
else: # self**1 or self**0
|
|
1548
|
-
return self._pow_0_1(x, other) # self or
|
|
1576
|
+
return self._pow_0_1(x, other) # self, 1 or 1.0
|
|
1549
1577
|
elif not isscalar(x): # assert ...
|
|
1550
1578
|
raise self._TypeError(op, other, txt=_not_scalar_)
|
|
1551
1579
|
elif r and self._raiser(r, s): # non-zero residual**fractional
|
|
@@ -1553,42 +1581,40 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1553
1581
|
t = _stresidual(_non_zero_, r, fractional_power=x)
|
|
1554
1582
|
raise self._Error(op, other, ResidualError, txt=t)
|
|
1555
1583
|
# assert isscalar(s) and isscalar(x)
|
|
1556
|
-
return self.
|
|
1584
|
+
return self._pow_2(s, x, other, op)
|
|
1557
1585
|
|
|
1558
1586
|
def _ps_1(self, *less):
|
|
1559
1587
|
'''(INTERNAL) Yield partials, 1-primed and subtract any C{less}.
|
|
1560
1588
|
'''
|
|
1561
|
-
|
|
1589
|
+
n = len(self._ps) + len(less) - 4
|
|
1590
|
+
if n < 0:
|
|
1591
|
+
yield _1_0
|
|
1562
1592
|
for p in self._ps:
|
|
1563
|
-
|
|
1564
|
-
yield p
|
|
1593
|
+
yield p
|
|
1565
1594
|
for p in less:
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1595
|
+
yield -p
|
|
1596
|
+
if n < 0:
|
|
1597
|
+
yield _N_1_0
|
|
1569
1598
|
|
|
1570
|
-
def
|
|
1571
|
-
'''(INTERNAL) Yield partials, negated.
|
|
1572
|
-
'''
|
|
1573
|
-
for p in self._ps:
|
|
1574
|
-
if p:
|
|
1575
|
-
yield -p
|
|
1576
|
-
|
|
1577
|
-
def _ps_x(self, op, *factors): # see .fmath.Fhorner
|
|
1599
|
+
def _ps_mul(self, op, *factors): # see .fmath.Fhorner
|
|
1578
1600
|
'''(INTERNAL) Yield all C{partials} times each B{C{factor}},
|
|
1579
1601
|
in total, up to C{len(partials) * len(factors)} items.
|
|
1580
1602
|
'''
|
|
1581
|
-
ps = self._ps
|
|
1603
|
+
ps = self._ps # tuple(self._ps)
|
|
1582
1604
|
if len(ps) < len(factors):
|
|
1583
1605
|
ps, factors = factors, ps
|
|
1584
1606
|
_f = _isfinite
|
|
1585
1607
|
for f in factors:
|
|
1586
1608
|
for p in ps:
|
|
1587
1609
|
p *= f
|
|
1588
|
-
if _f(p)
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1610
|
+
yield p if _f(p) else self._finite(p, op)
|
|
1611
|
+
|
|
1612
|
+
@property_RO
|
|
1613
|
+
def _ps_neg(self):
|
|
1614
|
+
'''(INTERNAL) Yield the partials, I{negated}.
|
|
1615
|
+
'''
|
|
1616
|
+
for p in self._ps:
|
|
1617
|
+
yield -p
|
|
1592
1618
|
|
|
1593
1619
|
@property_RO
|
|
1594
1620
|
def real(self):
|
|
@@ -1613,7 +1639,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1613
1639
|
return self._fprs2.residual
|
|
1614
1640
|
|
|
1615
1641
|
def _raiser(self, r, s):
|
|
1616
|
-
'''(INTERNAL) Does
|
|
1642
|
+
'''(INTERNAL) Does ratio C{r / s} exceed threshold?
|
|
1617
1643
|
'''
|
|
1618
1644
|
self._ratio = t = fabs((r / s) if s else r)
|
|
1619
1645
|
return t > self._RESIDUAL
|
|
@@ -1628,12 +1654,12 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1628
1654
|
C{PYGEODESY_FSUM_RESIDUAL} or if omitted, keep the
|
|
1629
1655
|
current setting.
|
|
1630
1656
|
|
|
1631
|
-
@return: The previous C{RESIDUAL} setting (C{float}).
|
|
1657
|
+
@return: The previous C{RESIDUAL} setting (C{float}), default C{0}.
|
|
1632
1658
|
|
|
1633
1659
|
@raise ValueError: Negative B{C{threshold}}.
|
|
1634
1660
|
|
|
1635
1661
|
@note: A L{ResidualError} is thrown if the non-zero I{ratio}
|
|
1636
|
-
C{residual
|
|
1662
|
+
C{residual / fsum} exceeds the B{C{threshold}}.
|
|
1637
1663
|
'''
|
|
1638
1664
|
r = self._RESIDUAL
|
|
1639
1665
|
if threshold:
|
|
@@ -1651,7 +1677,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1651
1677
|
'''(INTERNAL) Non-zero B{C{residual}} etc.
|
|
1652
1678
|
'''
|
|
1653
1679
|
t = _stresidual(_non_zero_, residual, ratio=self._ratio,
|
|
1654
|
-
|
|
1680
|
+
RESIDUAL=self._RESIDUAL)
|
|
1655
1681
|
t = t.replace(_COMMASPACE_R_, _exceeds_R_)
|
|
1656
1682
|
return self._Error(op, other, ResidualError, txt=t)
|
|
1657
1683
|
|
|
@@ -1703,13 +1729,17 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1703
1729
|
'''
|
|
1704
1730
|
return self._Error(op, other, _TypeError, **txt)
|
|
1705
1731
|
|
|
1706
|
-
def _update(self): # see ._fset
|
|
1732
|
+
def _update(self, updated=True): # see ._fset
|
|
1707
1733
|
'''(INTERNAL) Zap all cached C{Property_RO} values.
|
|
1708
1734
|
'''
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1735
|
+
if updated:
|
|
1736
|
+
_pop = self.__dict__.pop
|
|
1737
|
+
for p in _ROs:
|
|
1738
|
+
_ = _pop(p, None)
|
|
1739
|
+
# Fsum._fint2._update(self)
|
|
1740
|
+
# Fsum._fprs ._update(self)
|
|
1741
|
+
# Fsum._fprs2._update(self)
|
|
1742
|
+
return self # for .fset_
|
|
1713
1743
|
|
|
1714
1744
|
def _ValueError(self, op, other, **txt): # PYCHOK no cover
|
|
1715
1745
|
'''(INTERNAL) Return a C{ValueError}.
|
|
@@ -1721,7 +1751,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1721
1751
|
'''
|
|
1722
1752
|
return self._Error(op, other, _ZeroDivisionError, **txt)
|
|
1723
1753
|
|
|
1724
|
-
_allPropertiesOf_n(3, Fsum, Property_RO) # PYCHOK assert, see Fsum._fset, -._update
|
|
1754
|
+
_ROs = _allPropertiesOf_n(3, Fsum, Property_RO) # PYCHOK assert, see Fsum._fset, -._update
|
|
1725
1755
|
|
|
1726
1756
|
|
|
1727
1757
|
def _Float_Int(arg, **name_Error):
|
|
@@ -1731,6 +1761,17 @@ def _Float_Int(arg, **name_Error):
|
|
|
1731
1761
|
return U(arg, **name_Error)
|
|
1732
1762
|
|
|
1733
1763
|
|
|
1764
|
+
class DivMod2Tuple(_NamedTuple):
|
|
1765
|
+
'''2-Tuple C{(div, mod)} with the quotient C{div} and remainder
|
|
1766
|
+
C{mod} results of a C{divmod} operation.
|
|
1767
|
+
|
|
1768
|
+
@note: Quotient C{div} an C{int} in Python 3+ or a C{float} in
|
|
1769
|
+
Python 2-. Remainder C{mod} an L{Fsum} instance.
|
|
1770
|
+
'''
|
|
1771
|
+
_Names_ = (_div_, _mod_)
|
|
1772
|
+
_Units_ = (_Float_Int, Fsum)
|
|
1773
|
+
|
|
1774
|
+
|
|
1734
1775
|
class Fsum2Tuple(_NamedTuple):
|
|
1735
1776
|
'''2-Tuple C{(fsum, residual)} with the precision running C{fsum}
|
|
1736
1777
|
and the C{residual}, the sum of the remaining partials. Each
|
|
@@ -1746,8 +1787,8 @@ class Fsum2Tuple(_NamedTuple):
|
|
|
1746
1787
|
def Fsum(self):
|
|
1747
1788
|
'''Get this L{Fsum2Tuple} as an L{Fsum}.
|
|
1748
1789
|
'''
|
|
1749
|
-
|
|
1750
|
-
return
|
|
1790
|
+
s, r = map(float, self)
|
|
1791
|
+
return _Fsum_ps(*_2ps(s, r), name=self.name)
|
|
1751
1792
|
|
|
1752
1793
|
def is_exact(self):
|
|
1753
1794
|
'''Is this L{Fsum2Tuple} considered to be exact? (C{bool}).
|
|
@@ -1769,6 +1810,23 @@ class ResidualError(_ValueError):
|
|
|
1769
1810
|
pass
|
|
1770
1811
|
|
|
1771
1812
|
|
|
1813
|
+
def _Fsum_ps(*ps, **name):
|
|
1814
|
+
'''(INTERNAL) Return an C{Fsum} from I{ordered} partials C{ps}.
|
|
1815
|
+
'''
|
|
1816
|
+
f = Fsum(**name) if name else Fsum()
|
|
1817
|
+
if ps:
|
|
1818
|
+
f._n = len(ps)
|
|
1819
|
+
f._ps[:] = ps
|
|
1820
|
+
return f
|
|
1821
|
+
|
|
1822
|
+
|
|
1823
|
+
def _Fsum_xs(xs, up=False, **name):
|
|
1824
|
+
'''(INTERNAL) Return an C{Fsum} from known floats C{xs}.
|
|
1825
|
+
'''
|
|
1826
|
+
f = Fsum(**name) if name else Fsum()
|
|
1827
|
+
return f._facc(xs, up=up)
|
|
1828
|
+
|
|
1829
|
+
|
|
1772
1830
|
try:
|
|
1773
1831
|
from math import fsum as _fsum # precision IEEE-754 sum, Python 2.6+
|
|
1774
1832
|
|
|
@@ -1780,8 +1838,8 @@ try:
|
|
|
1780
1838
|
|
|
1781
1839
|
Fsum._math_fsum = _sum = _fsum # PYCHOK exported
|
|
1782
1840
|
|
|
1783
|
-
if _getenv('PYGEODESY_FSUM_PARTIALS',
|
|
1784
|
-
_psum = _fsum # PYCHOK
|
|
1841
|
+
if _getenv('PYGEODESY_FSUM_PARTIALS', NN) == _fsum.__name__:
|
|
1842
|
+
_psum = _fsum # PYCHOK re-def
|
|
1785
1843
|
|
|
1786
1844
|
except ImportError:
|
|
1787
1845
|
_sum = sum # Fsum(NAN) exception fall-back
|
|
@@ -1789,16 +1847,16 @@ except ImportError:
|
|
|
1789
1847
|
def _fsum(xs):
|
|
1790
1848
|
'''(INTERNAL) Precision summation, Python 2.5-.
|
|
1791
1849
|
'''
|
|
1792
|
-
return Fsum(name=_fsum.__name__).
|
|
1850
|
+
return Fsum(name=_fsum.__name__).fsum(xs) if xs else _0_0
|
|
1793
1851
|
|
|
1794
1852
|
|
|
1795
1853
|
def fsum(xs, floats=False):
|
|
1796
1854
|
'''Precision floating point summation based on or like Python's C{math.fsum}.
|
|
1797
1855
|
|
|
1798
|
-
@arg xs: Iterable, list, tuple, etc. of values (C{scalar} or
|
|
1799
|
-
|
|
1800
|
-
@kwarg floats: Optionally, use C{B{floats}=True} iff I{all}
|
|
1801
|
-
|
|
1856
|
+
@arg xs: Iterable, list, tuple, etc. of values (C{scalar} or L{Fsum}
|
|
1857
|
+
instances).
|
|
1858
|
+
@kwarg floats: Optionally, use C{B{floats}=True} iff I{all} B{C{xs}}
|
|
1859
|
+
are known to be C{float}.
|
|
1802
1860
|
|
|
1803
1861
|
@return: Precision C{fsum} (C{float}).
|
|
1804
1862
|
|
|
@@ -1819,10 +1877,10 @@ def fsum(xs, floats=False):
|
|
|
1819
1877
|
def fsum_(*xs, **floats):
|
|
1820
1878
|
'''Precision floating point summation of all positional arguments.
|
|
1821
1879
|
|
|
1822
|
-
@arg xs: Values to be added (C{scalar} or L{Fsum} instances),
|
|
1823
|
-
|
|
1824
|
-
@kwarg floats: Optionally, use C{B{floats}=True} iff I{all}
|
|
1825
|
-
|
|
1880
|
+
@arg xs: Values to be added (C{scalar} or L{Fsum} instances), all
|
|
1881
|
+
positional.
|
|
1882
|
+
@kwarg floats: Optionally, use C{B{floats}=True} iff I{all} B{C{xs}}
|
|
1883
|
+
are known to be C{float}.
|
|
1826
1884
|
|
|
1827
1885
|
@return: Precision C{fsum} (C{float}).
|
|
1828
1886
|
|
|
@@ -1841,10 +1899,10 @@ def fsumf_(*xs):
|
|
|
1841
1899
|
def fsum1(xs, floats=False):
|
|
1842
1900
|
'''Precision floating point summation of a few arguments, 1-primed.
|
|
1843
1901
|
|
|
1844
|
-
@arg xs: Iterable, list, tuple, etc. of values (C{scalar} or
|
|
1845
|
-
|
|
1846
|
-
@kwarg floats: Optionally, use C{B{floats}=True} iff I{all}
|
|
1847
|
-
|
|
1902
|
+
@arg xs: Iterable, list, tuple, etc. of values (C{scalar} or L{Fsum}
|
|
1903
|
+
instances).
|
|
1904
|
+
@kwarg floats: Optionally, use C{B{floats}=True} iff I{all} B{C{xs}}
|
|
1905
|
+
are known to be C{float}.
|
|
1848
1906
|
|
|
1849
1907
|
@return: Precision C{fsum} (C{float}).
|
|
1850
1908
|
|
|
@@ -1856,10 +1914,10 @@ def fsum1(xs, floats=False):
|
|
|
1856
1914
|
def fsum1_(*xs, **floats):
|
|
1857
1915
|
'''Precision floating point summation of a few arguments, 1-primed.
|
|
1858
1916
|
|
|
1859
|
-
@arg xs: Values to be added (C{scalar} or L{Fsum} instances),
|
|
1860
|
-
|
|
1861
|
-
@kwarg floats: Optionally, use C{B{floats}=True} iff I{all}
|
|
1862
|
-
|
|
1917
|
+
@arg xs: Values to be added (C{scalar} or L{Fsum} instances), all
|
|
1918
|
+
positional.
|
|
1919
|
+
@kwarg floats: Optionally, use C{B{floats}=True} iff I{all} B{C{xs}}
|
|
1920
|
+
are known to be C{float}.
|
|
1863
1921
|
|
|
1864
1922
|
@return: Precision C{fsum} (C{float}).
|
|
1865
1923
|
|
|
@@ -1875,6 +1933,35 @@ def fsum1f_(*xs):
|
|
|
1875
1933
|
return _fsum(_1primed(xs)) if xs else _0_0
|
|
1876
1934
|
|
|
1877
1935
|
|
|
1936
|
+
if __name__ == '__main__':
|
|
1937
|
+
|
|
1938
|
+
# usage: [env PYGEODESY_FSUM_PARTIALS=fsum] python3 -m pygeodesy.fsums
|
|
1939
|
+
|
|
1940
|
+
def _test(n):
|
|
1941
|
+
# copied from Hettinger, see L{Fsum} reference
|
|
1942
|
+
from pygeodesy import printf
|
|
1943
|
+
from random import gauss, random, shuffle
|
|
1944
|
+
|
|
1945
|
+
printf(_fsum.__name__, end=_COMMASPACE_)
|
|
1946
|
+
printf(_psum.__name__, end=_COMMASPACE_)
|
|
1947
|
+
|
|
1948
|
+
F = Fsum()
|
|
1949
|
+
if F.is_math_fsum:
|
|
1950
|
+
c = (7, 1e100, -7, -1e100, -9e-20, 8e-20) * 10
|
|
1951
|
+
for _ in range(n):
|
|
1952
|
+
t = list(c)
|
|
1953
|
+
s = 0
|
|
1954
|
+
for _ in range(n * 8):
|
|
1955
|
+
v = gauss(0, random())**7 - s
|
|
1956
|
+
t.append(v)
|
|
1957
|
+
s += v
|
|
1958
|
+
shuffle(t)
|
|
1959
|
+
assert float(F.fset_(*t)) == _fsum(t)
|
|
1960
|
+
printf(_DOT_, end=NN)
|
|
1961
|
+
printf(NN)
|
|
1962
|
+
|
|
1963
|
+
_test(128)
|
|
1964
|
+
|
|
1878
1965
|
# **) MIT License
|
|
1879
1966
|
#
|
|
1880
1967
|
# Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved.
|