pygeodesy 24.9.24__py2.py3-none-any.whl → 24.10.10__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/fsums.py CHANGED
@@ -40,14 +40,14 @@ results may differ from Python's C{math.fsum} results.
40
40
  from __future__ import division as _; del _ # PYCHOK semicolon
41
41
 
42
42
  from pygeodesy.basics import isbool, iscomplex, isint, isscalar, \
43
- _signOf, itemsorted, signOf, _xiterable, \
44
- _xiterablen
43
+ _signOf, itemsorted, signOf, _xiterable
45
44
  from pygeodesy.constants import INF, INT0, MANT_DIG, NEG0, NINF, _0_0, \
46
45
  _1_0, _N_1_0, _isfinite, _pos_self, \
47
46
  Float, Int
48
47
  from pygeodesy.errors import _AssertionError, _OverflowError, _TypeError, \
49
- _ValueError, _xError, _xError2, _xkwds_get, \
50
- _xkwds, _xkwds_get1, _xkwds_not, _xkwds_pop
48
+ _ValueError, _xError, _xError2, _xkwds, \
49
+ _xkwds_get, _xkwds_get1, _xkwds_not, \
50
+ _xkwds_pop, _xsError
51
51
  from pygeodesy.internals import _enquote, _passarg
52
52
  from pygeodesy.interns import NN, _arg_, _COMMASPACE_, _DOT_, _from_, \
53
53
  _not_finite_, _SPACE_, _std_, _UNDER_
@@ -64,7 +64,7 @@ from math import fabs, isinf, isnan, \
64
64
  ceil as _ceil, floor as _floor # PYCHOK used! .ltp
65
65
 
66
66
  __all__ = _ALL_LAZY.fsums
67
- __version__ = '24.09.25'
67
+ __version__ = '24.10.09'
68
68
 
69
69
  from pygeodesy.interns import (
70
70
  _PLUS_ as _add_op_, # in .auxilats.auxAngle
@@ -77,90 +77,62 @@ from pygeodesy.interns import (
77
77
  _DASH_ as _sub_op_, # in .auxilats.auxAngle
78
78
  _SLASH_ as _truediv_op_
79
79
  )
80
- _eq_op_ = _fset_op_ * 2 # _DEQUAL_
81
80
  _floordiv_op_ = _truediv_op_ * 2 # _DSLASH_
82
81
  _divmod_op_ = _floordiv_op_ + _mod_op_
83
82
  _F2PRODUCT = _getenv('PYGEODESY_FSUM_F2PRODUCT', NN)
84
- _ge_op_ = _gt_op_ + _fset_op_
85
83
  _iadd_op_ = _add_op_ + _fset_op_ # in .auxilats.auxAngle, .fstats
86
84
  _integer_ = 'integer'
87
85
  _isub_op_ = _sub_op_ + _fset_op_ # in .auxilats.auxAngle
88
- _le_op_ = _lt_op_ + _fset_op_
89
- _NONFINITES = _getenv('PYGEODESY_FSUM_NONFINITES', NN) == _std_
86
+ _NONFINITEr = _0_0 # NOT INT0!
87
+ _NONFINITES = _getenv('PYGEODESY_FSUM_NONFINITES', NN)
90
88
  _non_zero_ = 'non-zero'
91
89
  _pow_op_ = _mul_op_ * 2 # _DSTAR_
92
90
  _RESIDUAL_0_0 = _getenv('PYGEODESY_FSUM_RESIDUAL', _0_0)
93
91
  _significant_ = 'significant'
94
- _2split3s = _passarg
95
92
  _threshold_ = 'threshold'
96
93
 
97
94
 
98
- def _2finite(x): # in .fstats
95
+ def _2finite(x, _isfine=_isfinite): # in .fstats
99
96
  '''(INTERNAL) return C{float(x)} if finite.
100
97
  '''
101
- return (float(x) if _isfinite(x) # and isscalar(x)
98
+ return (float(x) if _isfine(x) # and isscalar(x)
102
99
  else _nfError(x))
103
100
 
104
101
 
105
- def _2float(index=None, _isfine=_isfinite, **name_value): # in .fmath, .fstats
106
- '''(INTERNAL) Raise C{TypeError} or C{ValueError} if not scalar or infinite.
102
+ def _2float(index=None, _isfine=_isfinite, **name_x): # in .fmath, .fstats
103
+ '''(INTERNAL) Raise C{TypeError} or C{Overflow-/ValueError} if not finite.
107
104
  '''
108
- n, v = name_value.popitem() # _xkwds_item2(name_value)
105
+ n, x = name_x.popitem() # _xkwds_item2(name_x)
109
106
  try:
110
- f = float(v)
111
- return f if _isfine(f) else _nfError(f)
107
+ f = float(x)
108
+ return f if _isfine(f) else _nfError(x)
112
109
  except Exception as X:
113
- raise _xError(X, Fmt.INDEX(n, index), v)
110
+ raise _xError(X, Fmt.INDEX(n, index), x)
114
111
 
115
112
 
116
- def _X_ps(X): # for _2floats only
117
- return X._ps
118
-
119
-
120
- def _2floats(xs, origin=0, _X=_X_ps, _x=float, _isfine=_isfinite):
121
- '''(INTERNAL) Yield each B{C{xs}} as a C{float}.
122
- '''
123
- try:
124
- i, x = origin, xs
125
- _FsT = _Fsum_Fsum2Tuple_types
126
- for x in _xiterable(xs):
127
- if isinstance(x, _FsT):
128
- for p in _X(x._Fsum):
129
- yield p
130
- else:
131
- f = _x(x)
132
- yield f if _isfine(f) else _nfError(f)
133
- i += 1
134
- except Exception as X:
135
- raise _xsError(X, xs, i, x)
136
-
137
-
138
- try: # MCCABE 17
113
+ try: # MCCABE 26
139
114
  from math import fma as _fma
140
- except ImportError: # Python 3.12-
141
115
 
142
- if _F2PRODUCT == _std_:
143
- _2FACTOR = pow(2, (MANT_DIG + 1) // 2) + 1
116
+ def _2products(x, ys, *zs):
117
+ # yield(x * y for y in ys) + yield(z in zs)
118
+ # TwoProductFMA U{Algorithm 3.5
119
+ # <https://www.TUHH.De/ti3/paper/rump/OgRuOi05.pdf>}
120
+ for y in ys:
121
+ f = x * y
122
+ yield f
123
+ if _isfinite(f):
124
+ yield _fma(x, y, -f)
125
+ for z in zs:
126
+ yield z
144
127
 
145
- def _fma(a, b, c):
146
- # mimick C{math.fma} from Python 3.13+,
147
- # the same accuracy, but ~13x slower
148
- b3s = _2split3(b),
149
- r = fsumf_(c, *_2products(a, b3s)) # two=True
150
- return r if _isfinite(r) else _fmaX(r, a, b, c)
128
+ # _2split3 = \
129
+ _2split3s = _passarg # in Fsum.is_math_fma
151
130
 
152
- def _2split3(x):
153
- # Split U{Algorithm 3.2
154
- # <https://www.TUHH.De/ti3/paper/rump/OgRuOi05.pdf>}
155
- a = c = x * _2FACTOR
156
- a -= c - x
157
- b = x - a
158
- return x, a, b
131
+ except ImportError: # PYCHOK DSPACE! Python 3.12-
159
132
 
160
- def _2split3s(xs): # overwrites
161
- return tuple(map(_2split3, xs))
133
+ if _F2PRODUCT and _F2PRODUCT != _std_:
134
+ # backward to PyGeodesy 24.09.09, with _fmaX
162
135
 
163
- else:
164
136
  def _fma(*a_b_c): # PYCHOK no cover
165
137
  # mimick C{math.fma} from Python 3.13+,
166
138
  # the same accuracy, but ~14x slower
@@ -169,61 +141,75 @@ except ImportError: # Python 3.12-
169
141
  n += da * db * nc
170
142
  d = da * db * dc
171
143
  try:
172
- r = float(n / d)
144
+ n, d = _n_d2(n, d)
145
+ r = float(n / d)
173
146
  except OverflowError: # "integer division result too large ..."
174
147
  r = NINF if (_signOf(n, 0) * _signOf(d, 0)) < 0 else INF
175
148
  return r if _isfinite(r) else _fmaX(r, *a_b_c) # "overflow in fma"
176
149
 
177
- def _2n_d(x):
150
+ def _2n_d(x): # PYCHOK no cover
178
151
  try: # int.as_integer_ratio in 3.8+
179
152
  return x.as_integer_ratio()
180
153
  except (AttributeError, OverflowError, TypeError, ValueError):
181
154
  return (x if isint(x) else float(x)), 1
155
+ else:
156
+
157
+ def _fma(a, b, c): # PYCHOK redef
158
+ # mimick C{math.fma} from Python 3.13+,
159
+ # the same accuracy, but ~13x slower
160
+ b3s = _2split3(b), # 1-tuple of 3-tuple
161
+ r = _fsum(_2products(a, b3s, c))
162
+ return r if _isfinite(r) else _fmaX(r, a, b, c)
163
+
164
+ _2n_d = None # redef
182
165
 
183
166
  def _fmaX(r, *a_b_c): # like Python 3.13+ I{Modules/mathmodule.c}:
184
- # raise a ValueError for a NAN result from non-NAN C{a_b_c}s or
185
- # OverflowError for a non-NAN result from all finite C{a_b_c}s.
167
+ # raise a ValueError for a NAN result from non-NAN C{a_b_c}s or an
168
+ # OverflowError for a non-NAN non-finite from all finite C{a_b_c}s.
186
169
  if isnan(r):
187
- def _is(x):
170
+ def _x(x):
188
171
  return not isnan(x)
189
- else:
190
- _is = _isfinite
191
- if all(map(_is, a_b_c)):
172
+ else: # non-NAN non-finite
173
+ _x = _isfinite
174
+ if all(map(_x, a_b_c)):
192
175
  raise _nfError(r, unstr(_fma, *a_b_c))
193
176
  return r
194
177
 
195
- if _2split3s is _passarg: # math._fma or _fma(*a_b_c)
196
-
197
- def _2products(x, ys, **unused):
198
- # TwoProductFMA U{Algorithm 3.5
199
- # <https://www.TUHH.De/ti3/paper/rump/OgRuOi05.pdf>}
200
- for y in ys:
201
- f = x * y
202
- yield f
203
- yield _fma(x, y, -f)
204
-
205
- else: # in _std_ _fma(a, b, c)
206
-
207
- def _2products(x, y3s, two=False): # PYCHOK redef
178
+ def _2products(x, y3s, *zs): # PYCHOK in _fma, ...
179
+ # yield(x * y3 for y3 in y3s) + yield(z in zs)
208
180
  # TwoProduct U{Algorithm 3.3
209
181
  # <https://www.TUHH.De/ti3/paper/rump/OgRuOi05.pdf>}
210
- # also in Python 3.13+ C{Modules/marhmodule.c} under
182
+ # also in Python 3.13+ C{Modules/mathmodule.c} under
211
183
  # #ifndef UNRELIABLE_FMA ... #else ... #endif
212
184
  _, a, b = _2split3(x)
213
185
  for y, c, d in y3s:
214
186
  y *= x
215
187
  yield y
216
- if two: # or not a:
217
- yield b * d - (((y - a * c) - b * c) - a * d)
218
- # = b * d + (a * d - ((y - a * c) - b * c))
219
- # = b * d + (a * d + (b * c - (y - a * c)))
220
- # = b * d + (a * d + (b * c + (a * c - y)))
221
- else:
188
+ if _isfinite(y):
189
+ # yield b * d - (((y - a * c) - b * c) - a * d)
190
+ # = b * d + (a * d - ((y - a * c) - b * c))
191
+ # = b * d + (a * d + (b * c - (y - a * c)))
192
+ # = b * d + (a * d + (b * c + (a * c - y)))
222
193
  yield a * c - y
223
194
  yield b * c
224
195
  if d:
225
196
  yield a * d
226
197
  yield b * d
198
+ for z in zs:
199
+ yield z
200
+
201
+ _2FACTOR = pow(2, (MANT_DIG + 1) // 2) + _1_0 # 134217729 if MANT_DIG == 53
202
+
203
+ def _2split3(x):
204
+ # Split U{Algorithm 3.2
205
+ # <https://www.TUHH.De/ti3/paper/rump/OgRuOi05.pdf>}
206
+ a = c = x * _2FACTOR
207
+ a -= c - x
208
+ b = x - a
209
+ return x, a, b
210
+
211
+ def _2split3s(xs): # in Fsum.is_math_fma
212
+ return map(_2split3, xs)
227
213
 
228
214
 
229
215
  def f2product(*two):
@@ -246,18 +232,18 @@ def f2product(*two):
246
232
 
247
233
 
248
234
  def _Fsumf_(*xs): # in .auxLat, .ltp, ...
249
- '''(INTERNAL) An C{Fsum} of I{known scalars}.
235
+ '''(INTERNAL) An C{Fsum(xs)}, all C{scalar}, an L{Fsum} or L{Fsum2Tuple}.
250
236
  '''
251
- return Fsum()._facc_scalar(xs, up=False)
237
+ return Fsum()._facc_scalarf(xs, up=False)
252
238
 
253
239
 
254
240
  def _Fsum1f_(*xs): # in .albers
255
- '''(INTERNAL) An C{Fsum} of I{known scalars}, 1-primed.
241
+ '''(INTERNAL) An C{Fsum(xs)}, all C{scalar}, an L{Fsum} or L{Fsum2Tuple}, 1-primed.
256
242
  '''
257
- return Fsum()._facc_scalar(_1primed(xs), up=False)
243
+ return Fsum()._facc_scalarf(_1primed(xs), origin=-1, up=False)
258
244
 
259
245
 
260
- def _2halfeven(s, r, p):
246
+ def _halfeven(s, r, p):
261
247
  '''(INTERNAL) Round half-even.
262
248
  '''
263
249
  if (p > 0 and r > 0) or \
@@ -275,23 +261,44 @@ def _isFsum(x): # in .fmath
275
261
  return isinstance(x, Fsum)
276
262
 
277
263
 
278
- def _isFsumTuple(x): # in .basics, .constants, .fmath, .fstats
264
+ def _isFsum_2Tuple(x): # in .basics, .constants, .fmath, .fstats
279
265
  '''(INTERNAL) Is C{x} an C{Fsum} or C{Fsum2Tuple} instance?
280
266
  '''
281
- return isinstance(x, _Fsum_Fsum2Tuple_types)
267
+ return isinstance(x, _Fsum_2Tuple_types)
282
268
 
283
269
 
284
270
  def _isOK(unused):
285
- '''(INTERNAL) Helper for C{nonfiniterrors} and C{Fsum.nonfinites}.
271
+ '''(INTERNAL) Helper for C{Fsum._fsum2} and C{Fsum.nonfinites}.
286
272
  '''
287
273
  return True
288
274
 
289
275
 
290
276
  def _isOK_or_finite(x, _isfine=_isfinite):
291
- '''(INTERNAL) Is C{x} finite or is I{non-finite} OK?.
277
+ '''(INTERNAL) Is C{x} finite or is I{non-finite} OK?
292
278
  '''
293
279
  # assert _isfine in (_isOK, _isfinite)
294
- return _isfine(x)
280
+ return _isfine(x) # C{bool}
281
+
282
+
283
+ try:
284
+ from math import gcd as _gcd
285
+
286
+ def _n_d2(n, d):
287
+ '''(INTERNAL) Reduce C{n} and C{d} by C{gcd}.
288
+ '''
289
+ if n and d:
290
+ try:
291
+ c = _gcd(n, d)
292
+ if c > 1:
293
+ n, d = (n // c), (d // c)
294
+ except TypeError: # non-int float
295
+ pass
296
+ return n, d
297
+
298
+ except ImportError: # 3.4-
299
+
300
+ def _n_d2(*n_d): # PYCHOK redef
301
+ return n_d
295
302
 
296
303
 
297
304
  def _nfError(x, *args):
@@ -299,11 +306,18 @@ def _nfError(x, *args):
299
306
  '''
300
307
  E = _NonfiniteError(x)
301
308
  t = Fmt.PARENSPACED(_not_finite_, x)
302
- if args: # in _fma, _2sum
309
+ if args: # in _fmaX, _2sum
303
310
  return E(txt=t, *args)
304
311
  raise E(t, txt=None)
305
312
 
306
313
 
314
+ def _NonfiniteError(x):
315
+ '''(INTERNAL) Return the Error class for C{x}, I{non-finite}.
316
+ '''
317
+ return _OverflowError if isinf(x) else (
318
+ _ValueError if isnan(x) else _AssertionError)
319
+
320
+
307
321
  def nonfiniterrors(*raiser):
308
322
  '''Throw C{OverflowError} and C{ValueError} exceptions for or
309
323
  handle I{non-finite} C{float}s as C{inf}, C{INF}, C{NINF},
@@ -321,14 +335,8 @@ def nonfiniterrors(*raiser):
321
335
  d = Fsum._isfine
322
336
  if raiser and raiser[0] is not None:
323
337
  Fsum._isfine = {} if bool(raiser[0]) else Fsum._nonfinites_isfine_kwds[True]
324
- return _xkwds_get1(d, _isfine=_isfinite) is _isfinite
325
-
326
-
327
- def _NonfiniteError(x):
328
- '''(INTERNAL) Return the Error class for C{x}, I{non-finite}.
329
- '''
330
- return _OverflowError if isinf(x) else (
331
- _ValueError if isnan(x) else _AssertionError)
338
+ return (False if d is Fsum._nonfinites_isfine_kwds[True] else
339
+ _xkwds_get1(d, _isfine=_isfinite) is _isfinite) if d else True
332
340
 
333
341
 
334
342
  def _1primed(xs): # in .fmath
@@ -354,13 +362,13 @@ def _psum(ps, **_isfine): # PYCHOK used!
354
362
  if s:
355
363
  ps[i:] = r, s
356
364
  if i > 0:
357
- s = _2halfeven(s, r, ps[i-1])
365
+ s = _halfeven(s, r, ps[i-1])
358
366
  break # return s
359
367
  s = r # PYCHOK no cover
360
368
  elif not _isfinite(s): # non-finite OK
361
369
  i = 0 # collapse ps
362
370
  if ps:
363
- s += _sum(ps) # _fsum(ps)
371
+ s += sum(ps)
364
372
  ps[i:] = s,
365
373
  return s
366
374
 
@@ -381,14 +389,38 @@ def _Psum_(*ps, **name_f2product_nonfinites_RESIDUAL): # in .fmath
381
389
  return _Psum(ps, **name_f2product_nonfinites_RESIDUAL)
382
390
 
383
391
 
384
- def _2scalar2(other):
392
+ def _residue(other):
393
+ '''(INTERNAL) Return the C{residual} or C{None} for C{scalar}.
394
+ '''
395
+ try:
396
+ r = other.residual
397
+ except AttributeError:
398
+ r = None # float, int, other
399
+ return r
400
+
401
+
402
+ def _s_r(s, r):
403
+ '''(INTERNAL) Return C{(s, r)}, I{ordered}.
404
+ '''
405
+ if _isfinite(s):
406
+ if r:
407
+ if fabs(s) < fabs(r):
408
+ s, r = r, (s or INT0)
409
+ else:
410
+ r = INT0
411
+ else:
412
+ r = _NONFINITEr
413
+ return s, r
414
+
415
+
416
+ def _2s_r(other):
385
417
  '''(INTERNAL) Return 2-tuple C{(other, r)} with C{other} as C{int},
386
- C{float} or C{as-is} and C{r} the residual of C{as-is}.
418
+ C{float} or C{as-is} and C{r} the residual of C{as-is} or 0.
387
419
  '''
388
- if _isFsumTuple(other):
420
+ if _isFsum_2Tuple(other):
389
421
  s, r = other._fint2
390
422
  if r:
391
- s, r = other._fprs2
423
+ s, r = other._nfprs2
392
424
  if r: # PYCHOK no cover
393
425
  s = other # L{Fsum} as-is
394
426
  else:
@@ -399,17 +431,6 @@ def _2scalar2(other):
399
431
  return s, r
400
432
 
401
433
 
402
- def _s_r(s, r):
403
- '''(INTERNAL) Return C{(s, r)}, I{ordered}.
404
- '''
405
- if r and _isfinite(s):
406
- if fabs(s) < fabs(r):
407
- s, r = r, (s or INT0)
408
- else:
409
- r = INT0
410
- return s, r
411
-
412
-
413
434
  def _strcomplex(s, *args):
414
435
  '''(INTERNAL) C{Complex} 2- or 3-arg C{pow} error as C{str}.
415
436
  '''
@@ -447,9 +468,9 @@ def _2sum(a, b, _isfine=_isfinite): # in .testFmath
447
468
  else:
448
469
  r = (a - s) + b
449
470
  elif _isfine(s):
450
- r = 0
471
+ r = _NONFINITEr
451
472
  else: # non-finite and not OK
452
- t = unstr(_2sum, a, b)
473
+ t = unstr(_2sum, a, b)
453
474
  raise _nfError(s, t)
454
475
  return s, r
455
476
 
@@ -477,10 +498,10 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
477
498
  i.e. any C{type} having method C{__float__}.
478
499
 
479
500
  @note: Handling of I{non-finites} as C{inf}, C{INF}, C{NINF}, C{nan} and C{NAN} is
480
- determined globally by function L{nonfiniterrors<fsums.nonfiniterrors>} and
481
- by method L{nonfinites<Fsum.nonfinites>} for individual C{Fsum} instances,
482
- overruling the global setting. By default and for backward compatibility,
483
- I{non-finites} raise exceptions.
501
+ determined by function L{nonfiniterrors<fsums.nonfiniterrors>} for the default
502
+ and by method L{nonfinites<Fsum.nonfinites>} for individual C{Fsum} instances,
503
+ overruling the default. For backward compatibility, I{non-finites} raise
504
+ exceptions by default.
484
505
 
485
506
  @see: U{Hettinger<https://GitHub.com/ActiveState/code/tree/master/recipes/Python/
486
507
  393090_Binary_floating_point_summatiaccurate_full/recipe-393090.py>},
@@ -496,10 +517,10 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
496
517
  C{PYGEODESY_FSUM_NONFINITES} and C{PYGEODESY_FSUM_RESIDUAL}.
497
518
  '''
498
519
  _f2product = _sys_version_info2 > (3, 12) or bool(_F2PRODUCT)
499
- _isfine = {} # == _isfinite
520
+ _isfine = {} # == _isfinite, see nonfiniterrors()
500
521
  _n = 0
501
522
  # _ps = [] # partial sums
502
- # _ps_max = 0 # max(Fsum._ps_max, len(Fsum._ps))
523
+ # _ps_max = 0 # max(Fsum._ps_max, len(Fsum._ps)) # 41
503
524
  _RESIDUAL = _threshold(_RESIDUAL_0_0)
504
525
 
505
526
  def __init__(self, *xs, **name_f2product_nonfinites_RESIDUAL):
@@ -537,14 +558,22 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
537
558
  @see: Methods L{Fsum.fadd_} and L{Fsum.fadd}.
538
559
  '''
539
560
  f = self._copy_2(self.__add__)
540
- return f._fadd(other, _add_op_)
561
+ return f._fadd(other)
541
562
 
542
563
  def __bool__(self): # PYCHOK Python 3+
543
564
  '''Return C{bool(B{self})}, C{True} iff C{residual} is zero.
544
565
  '''
545
- s, r = self._fprs2
566
+ s, r = self._nfprs2
546
567
  return bool(s or r) and s != -r # == self != 0
547
568
 
569
+ def __call__(self, other, **up): # in .fmath
570
+ '''Reset this C{Fsum} to C{other}, default C{B{up}=True}.
571
+ '''
572
+ self._ps[:] = 0, # clear for errors
573
+ self._fset(other, op=_fset_op_, **up)
574
+ return self
575
+
576
+
548
577
  def __ceil__(self): # PYCHOK not special in Python 2-
549
578
  '''Return this instance' C{math.ceil} as C{int} or C{float}.
550
579
 
@@ -586,7 +615,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
586
615
  '''Return C{(B{self} == B{other})} as C{bool} where B{C{other}}
587
616
  is C{scalar}, an other L{Fsum} or L{Fsum2Tuple}.
588
617
  '''
589
- return self._cmp_0(other, _eq_op_) == 0
618
+ return self._cmp_0(other, _fset_op_ + _fset_op_) == 0
590
619
 
591
620
  def __float__(self):
592
621
  '''Return this instance' current, precision running sum as C{float}.
@@ -623,7 +652,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
623
652
  def __ge__(self, other):
624
653
  '''Return C{(B{self} >= B{other})}, see C{__eq__}.
625
654
  '''
626
- return self._cmp_0(other, _ge_op_) >= 0
655
+ return self._cmp_0(other, _gt_op_ + _fset_op_) >= 0
627
656
 
628
657
  def __gt__(self, other):
629
658
  '''Return C{(B{self} > B{other})}, see C{__eq__}.
@@ -651,7 +680,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
651
680
  @see: Methods L{Fsum.fadd_} and L{Fsum.fadd}.
652
681
  '''
653
682
  try:
654
- return self._fadd(other, _iadd_op_)
683
+ return self._fadd(other, op=_iadd_op_)
655
684
  except TypeError:
656
685
  pass
657
686
  _xiterable(other)
@@ -811,7 +840,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
811
840
  def __le__(self, other):
812
841
  '''Return C{(B{self} <= B{other})}, see C{__eq__}.
813
842
  '''
814
- return self._cmp_0(other, _le_op_) <= 0
843
+ return self._cmp_0(other, _lt_op_ + _fset_op_) <= 0
815
844
 
816
845
  def __len__(self):
817
846
  '''Return the number of values accumulated (C{int}).
@@ -873,7 +902,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
873
902
  @see: Method L{Fsum.__iadd__}.
874
903
  '''
875
904
  f = self._copy_2r(other, self.__radd__)
876
- return f._fadd(self, _add_op_)
905
+ return f._fadd(self)
877
906
 
878
907
  def __rdivmod__(self, other):
879
908
  '''Return C{divmod(B{other}, B{self})} as 2-tuple
@@ -1007,9 +1036,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1007
1036
  '''
1008
1037
  n, r = self._fint2
1009
1038
  if r:
1010
- i, d = float(r).as_integer_ratio()
1011
- n *= d
1012
- n += i
1039
+ i, d = float(r).as_integer_ratio()
1040
+ n, d = _n_d2(n * d + i, d)
1013
1041
  else: # PYCHOK no cover
1014
1042
  d = 1
1015
1043
  return n, d
@@ -1019,7 +1047,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1019
1047
  '''Get this instance I{as-is} (L{Fsum} with C{non-zero residual},
1020
1048
  C{scalar} or I{non-finite}).
1021
1049
  '''
1022
- s, r = self._fprs2
1050
+ s, r = self._nfprs2
1023
1051
  return self if r else s
1024
1052
 
1025
1053
  @property_RO
@@ -1043,7 +1071,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1043
1071
  def _cmp_0(self, other, op):
1044
1072
  '''(INTERNAL) Return C{scalar(self - B{other})} for 0-comparison.
1045
1073
  '''
1046
- if _isFsumTuple(other):
1074
+ if _isFsum_2Tuple(other):
1047
1075
  s = self._ps_1sum(*other._ps)
1048
1076
  elif self._scalar(other, op):
1049
1077
  s = self._ps_1sum(other)
@@ -1066,6 +1094,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1066
1094
  f._n = 1
1067
1095
  # assert f._f2product == self._f2product
1068
1096
  # assert f._Fsum is f
1097
+ # assert f._isfine is self._isfine
1098
+ # assert f._RESIDUAL is self._RESIDUAL
1069
1099
  return f
1070
1100
 
1071
1101
  def _copy_2(self, which, name=NN):
@@ -1078,6 +1108,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1078
1108
  # assert f._n == self._n
1079
1109
  # assert f._f2product == self._f2product
1080
1110
  # assert f._Fsum is f
1111
+ # assert f._isfine is self._isfine
1112
+ # assert f._RESIDUAL is self._RESIDUAL
1081
1113
  return f
1082
1114
 
1083
1115
  def _copy_2r(self, other, which):
@@ -1091,7 +1123,9 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1091
1123
  def _Error(self, op, other, Error, **txt_cause):
1092
1124
  '''(INTERNAL) Format an B{C{Error}} for C{{self} B{op} B{other}}.
1093
1125
  '''
1094
- return Error(_SPACE_(self.as_iscalar, op, other), **txt_cause)
1126
+ # self.as_iscalar causes RecursionError for ._fprs2 errors
1127
+ s = _Psum(self._ps, nonfinites=True, name=self.name)
1128
+ return Error(_SPACE_(s.as_iscalar, op, other), **txt_cause)
1095
1129
 
1096
1130
  def _ErrorX(self, X, op, other, *mod):
1097
1131
  '''(INTERNAL) Format the caught exception C{X}.
@@ -1105,25 +1139,27 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1105
1139
  '''(INTERNAL) Format the caught exception C{X}.
1106
1140
  '''
1107
1141
  E, t = _xError2(X)
1108
- u = unstr(self.named3, *xs[:3], _ELLIPSIS=len(xs) > 3, **kwds)
1142
+ u = unstr(self.named3, *xs, _ELLIPSIS=4, **kwds)
1109
1143
  return E(u, txt=t, cause=X)
1110
1144
 
1111
- def _facc(self, xs, up=True, **origin_X_x):
1112
- '''(INTERNAL) Accumulate more C{scalars} or L{Fsum}s.
1145
+ def _facc(self, xs, up=True, **_X_x_origin):
1146
+ '''(INTERNAL) Accumulate more C{scalar}s or L{Fsum}s.
1113
1147
  '''
1114
1148
  if xs:
1115
- kwds = _xkwds(self._isfine, **origin_X_x)
1116
- _xs = _2floats(xs, **kwds) # PYCHOK yield
1149
+ kwds = self._isfine
1150
+ if _X_x_origin:
1151
+ kwds = _xkwds(_X_x_origin, **kwds)
1152
+ fs = _xs(xs, **kwds) # PYCHOK yield
1117
1153
  ps = self._ps
1118
- ps[:] = self._ps_acc(list(ps), _xs, up=up)
1154
+ ps[:] = self._ps_acc(list(ps), fs, up=up)
1119
1155
  return self
1120
1156
 
1121
1157
  def _facc_args(self, xs, **up):
1122
1158
  '''(INTERNAL) Accumulate 0, 1 or more C{xs}, all positional
1123
1159
  arguments in the caller of this method.
1124
1160
  '''
1125
- return self._facc(xs, origin=1, **up) if len(xs) != 1 else \
1126
- self._fadd(xs[0], _add_op_, **up)
1161
+ return self._fadd(xs[0], **up) if len(xs) == 1 else \
1162
+ self._facc(xs, **up) # origin=1?
1127
1163
 
1128
1164
  def _facc_neg(self, xs, **up_origin):
1129
1165
  '''(INTERNAL) Accumulate more C{xs}, negated.
@@ -1141,7 +1177,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1141
1177
  '''
1142
1178
  def _Pow4(p):
1143
1179
  r = 0
1144
- if _isFsumTuple(p):
1180
+ if _isFsum_2Tuple(p):
1145
1181
  s, r = p._fprs2
1146
1182
  if r:
1147
1183
  m = Fsum._pow
@@ -1158,7 +1194,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1158
1194
  _Pow, p, s, r = _Pow4(power)
1159
1195
  if p: # and xs:
1160
1196
  op = which.__name__
1161
- _FsT = _Fsum_Fsum2Tuple_types
1197
+ _FsT = _Fsum_2Tuple_types
1162
1198
  _pow = self._pow_2_3
1163
1199
 
1164
1200
  def _P(X):
@@ -1172,24 +1208,32 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1172
1208
  f *= _pow(x, r, power, op, **raiser_RESIDUAL)
1173
1209
  return f
1174
1210
 
1175
- f = self._facc(xs, origin=1, _X=_P, _x=_p)
1211
+ f = self._facc(xs, _X=_P, _x=_p) # origin=1?
1176
1212
  else:
1177
1213
  f = self._facc_scalar_(float(len(xs))) # x**0 == 1
1178
1214
  return f
1179
1215
 
1180
1216
  def _facc_scalar(self, xs, **up):
1181
- '''(INTERNAL) Accumulate all C{xs}, known to be scalar.
1217
+ '''(INTERNAL) Accumulate all C{xs}, each C{scalar}.
1182
1218
  '''
1183
1219
  if xs:
1184
- _ = self._ps_acc(self._ps, xs, **up)
1220
+ ps = self._ps
1221
+ ps[:] = self._ps_acc(list(ps), xs, **up)
1185
1222
  return self
1186
1223
 
1187
1224
  def _facc_scalar_(self, *xs, **up):
1188
- '''(INTERNAL) Accumulate all positional C{xs}, known to be scalar.
1225
+ '''(INTERNAL) Accumulate all positional C{xs}, each C{scalar}.
1189
1226
  '''
1190
- if xs:
1191
- _ = self._ps_acc(self._ps, xs, **up)
1192
- return self
1227
+ return self._facc_scalar(xs, **up)
1228
+
1229
+ def _facc_scalarf(self, xs, up=True, **origin_which):
1230
+ '''(INTERNAL) Accumulate all C{xs}, each C{scalar}, an L{Fsum} or
1231
+ L{Fsum2Tuple}, like function C{_xsum}.
1232
+ '''
1233
+ _C = self.__class__
1234
+ fs = _xs(xs, **_x_isfine(self.nonfinitesOK, _Cdot=_C,
1235
+ **origin_which)) # PYCHOK yield
1236
+ return self._facc_scalar(fs, up=up)
1193
1237
 
1194
1238
  # def _facc_up(self, up=True):
1195
1239
  # '''(INTERNAL) Update the C{partials}, by removing
@@ -1208,8 +1252,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1208
1252
  def fadd(self, xs=()):
1209
1253
  '''Add an iterable's items to this instance.
1210
1254
 
1211
- @arg xs: Iterable of items to add (each C{scalar}
1212
- or an L{Fsum} or L{Fsum2Tuple} instance).
1255
+ @arg xs: Iterable of items to add (each C{scalar},
1256
+ an L{Fsum} or L{Fsum2Tuple}).
1213
1257
 
1214
1258
  @return: This instance (L{Fsum}).
1215
1259
 
@@ -1219,7 +1263,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1219
1263
 
1220
1264
  @raise ValueError: Invalid or I{non-finite} B{C{xs}} value.
1221
1265
  '''
1222
- if _isFsumTuple(xs):
1266
+ if _isFsum_2Tuple(xs):
1223
1267
  self._facc_scalar(xs._ps)
1224
1268
  elif isscalar(xs): # for backward compatibility # PYCHOK no cover
1225
1269
  x = _2float(x=xs, **self._isfine)
@@ -1231,26 +1275,20 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1231
1275
  def fadd_(self, *xs):
1232
1276
  '''Add all positional items to this instance.
1233
1277
 
1234
- @arg xs: Values to add (each C{scalar} or an L{Fsum}
1235
- or L{Fsum2Tuple} instance), all positional.
1278
+ @arg xs: Values to add (each C{scalar}, an L{Fsum}
1279
+ or L{Fsum2Tuple}), all positional.
1236
1280
 
1237
1281
  @see: Method L{Fsum.fadd} for further details.
1238
1282
  '''
1239
1283
  return self._facc_args(xs)
1240
1284
 
1241
- def _fadd(self, other, op, **up): # in .fmath.Fhorner
1285
+ def _fadd(self, other, op=_add_op_, **up):
1242
1286
  '''(INTERNAL) Apply C{B{self} += B{other}}.
1243
1287
  '''
1244
- if _isFsumTuple(other):
1245
- if self._ps:
1246
- self._facc_scalar(other._ps, **up)
1247
- else:
1248
- self._fset(other, op=op, **up)
1288
+ if _isFsum_2Tuple(other):
1289
+ self._facc_scalar(other._ps, **up)
1249
1290
  elif self._scalar(other, op):
1250
- if self._ps:
1251
- self._facc_scalar_(other, **up)
1252
- else:
1253
- self._fset(other, op=op, **up)
1291
+ self._facc_scalar_(other, **up)
1254
1292
  return self
1255
1293
 
1256
1294
  fcopy = copy # for backward compatibility
@@ -1276,25 +1314,27 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1276
1314
  # raise self._Error(op, other, _AssertionError, txt__=signOf)
1277
1315
  return DivMod2Tuple(q, self) # q is C{int} in Python 3+, but C{float} in Python 2-
1278
1316
 
1279
- def _fhorner(self, x, cs, op, incx=True): # in .fmath
1317
+ def _fhorner(self, x, cs, where, incx=True): # in .fmath
1280
1318
  '''(INTERNAL) Add an L{Fhorner} evaluation of polynomial
1281
1319
  C{sum(cs[i] * B{x}**i for i=0..len(cs)-1) if B{incx}
1282
1320
  else sum(... i=len(cs)-1..0)}.
1283
1321
  '''
1284
- if _xiterablen(cs):
1285
- H = self._Fsum_as(name__=self._fhorner)
1286
- if _isFsumTuple(x):
1287
- _mul = H._mul_Fsum
1288
- else:
1289
- _mul = H._mul_scalar
1290
- x = _2float(x=x, **self._isfine)
1291
- if len(cs) > 1 and x:
1322
+ # assert _xiterablen(cs)
1323
+ try:
1324
+ n = len(cs)
1325
+ H = self._Fsum_as(name__=self._fhorner)
1326
+ _m = H._mul_Fsum if _isFsum_2Tuple(x) else \
1327
+ H._mul_scalar
1328
+ if _2finite(x, **self._isfine) and n > 1:
1292
1329
  for c in (reversed(cs) if incx else cs):
1293
- H._fset_ps(_mul(x, op))
1294
- H._fadd(c, op, up=False)
1330
+ H._fset(_m(x, _mul_op_), up=False)
1331
+ H._fadd(c, up=False)
1295
1332
  else: # x == 0
1296
- H = cs[0] if cs else _0_0
1297
- self._fadd(H, op)
1333
+ H = cs[0] if n else 0
1334
+ self._fadd(H)
1335
+ except Exception as X:
1336
+ t = unstr(where, x, *cs, _ELLIPSIS=4, incx=incx)
1337
+ raise self._ErrorX(X, _add_op_, t)
1298
1338
  return self
1299
1339
 
1300
1340
  def _finite(self, other, op=None):
@@ -1346,36 +1386,28 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1346
1386
  def _fint2(self): # see ._fset
1347
1387
  '''(INTERNAL) Get 2-tuple (C{int}, I{integer} residual).
1348
1388
  '''
1349
- s, _ = self._fprs2
1350
- try:
1389
+ s, r = self._nfprs2
1390
+ if _isfinite(s):
1351
1391
  i = int(s)
1352
1392
  r = (self._ps_1sum(i) if len(self._ps) > 1 else
1353
1393
  float(s - i)) or INT0
1354
- except (OverflowError, ValueError) as X:
1355
- r = 0 # INF, NAN, NINF
1356
- i = self._fintX(X, sum(self._ps))
1394
+ else: # INF, NAN, NINF
1395
+ i = float(s)
1396
+ # r = _NONFINITEr
1357
1397
  return i, r # Fsum2Tuple?
1358
1398
 
1359
1399
  @_fint2.setter_ # PYCHOK setter_UNDERscore!
1360
1400
  def _fint2(self, s): # in _fset
1361
1401
  '''(INTERNAL) Replace the C{_fint2} value.
1362
1402
  '''
1363
- try:
1403
+ if _isfinite(s):
1364
1404
  i = int(s)
1365
1405
  r = (s - i) or INT0
1366
- except (OverflowError, ValueError) as X:
1367
- r = 0 # INF, NAN, NINF
1368
- i = self._fintX(X, float(s))
1406
+ else: # INF, NAN, NINF
1407
+ i = float(s)
1408
+ r = _NONFINITEr
1369
1409
  return i, r # like _fint2.getter
1370
1410
 
1371
- def _fintX(self, X, i): # PYCHOK X
1372
- '''(INTERNAL) Handle I{non-finite} C{int}.
1373
- '''
1374
- # "cannot convert float infinity to integer"
1375
- return i # ignore such Overflow-/ValueErrors
1376
- # op = int.__name__
1377
- # return self._nonfiniteX(X, op, i)
1378
-
1379
1411
  @deprecated_property_RO
1380
1412
  def float_int(self): # PYCHOK no cover
1381
1413
  '''DEPRECATED, use method C{Fsum.int_float}.'''
@@ -1406,31 +1438,35 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1406
1438
  q = self._ftruediv(other, op, **raiser_RESIDUAL) # == self
1407
1439
  return self._fset(q.floor) # floor(q)
1408
1440
 
1409
- def fma(self, other1, other2, raiser=False): # in .fmath.fma
1441
+ def fma(self, other1, other2, **nonfinites): # in .fmath.fma
1410
1442
  '''Fused-multiply-add C{self *= B{other1}; self += B{other2}}.
1411
1443
 
1412
1444
  @arg other1: Multiplier (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
1413
1445
  @arg other2: Addend (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
1414
- @kwarg raiser: If C{True}, throw an exception, otherwise pass
1415
- the I{non-finite} result (C{bool}).
1416
-
1417
- @note: Uses C{math.fma} in Python 3.13+, provided C{self},
1418
- B{C{other1}} and B{C{other2}} are all C{scalar}.
1446
+ @kwarg nonfinites: Use C{B{nonfinites}=True} or C{False}, to
1447
+ override L{nonfinites<Fsum.nonfinites>} and
1448
+ L{nonfiniterrors} default (C{bool}).
1419
1449
  '''
1420
- f, r = self._fprs2
1421
- if r == 0 and isscalar(other1, both=True) \
1422
- and isscalar(other2, both=True):
1423
- try:
1424
- f = _fma(f, other1, other2)
1425
- except (OverflowError, TypeError, ValueError) as X: # from math.fma
1426
- op = self.fma.__name__ # INF, NAN, NINF
1427
- f = self._mul_reduce(op, f, other1)
1428
- f = _sum(self._ps_other(op, f, other2))
1429
- if raiser:
1430
- f = self._nonfiniteX(X, op, f)
1431
- else:
1432
- f = self._f2mul(self.fma, other1, raiser=raiser)
1433
- f += other2
1450
+ op = self.fma.__name__
1451
+ _fs = self._ps_other
1452
+ try:
1453
+ s, r = self._fprs2
1454
+ if r:
1455
+ f = self._f2mul(self.fma, other1, **nonfinites)
1456
+ f += other2
1457
+ elif _residue(other1) or _residue(other2):
1458
+ fs = _2split3s(_fs(op, other1))
1459
+ fs = _2products(s, fs, *_fs(op, other2))
1460
+ f = _Psum(self._ps_acc([], fs, up=False), name=op)
1461
+ else:
1462
+ f = _fma(s, other1, other2)
1463
+ f = _2finite(f, **self._isfine)
1464
+ except TypeError as X:
1465
+ raise self._ErrorX(X, op, (other1, other2))
1466
+ except (OverflowError, ValueError) as X: # from math.fma
1467
+ f = self._mul_reduce(s, other1) # INF, NAN, NINF
1468
+ f += sum(_fs(op, other2))
1469
+ f = self._nonfiniteX(X, op, f, **nonfinites)
1434
1470
  return self._fset(f)
1435
1471
 
1436
1472
  fmul = __imul__
@@ -1438,11 +1474,11 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1438
1474
  def _fmul(self, other, op):
1439
1475
  '''(INTERNAL) Apply C{B{self} *= B{other}}.
1440
1476
  '''
1441
- if _isFsumTuple(other):
1477
+ if _isFsum_2Tuple(other):
1442
1478
  if len(self._ps) != 1:
1443
1479
  f = self._mul_Fsum(other, op)
1444
1480
  elif len(other._ps) != 1: # and len(self._ps) == 1
1445
- f = self._ps_mul(op, *other._ps)
1481
+ f = self._ps_mul(op, *other._ps) if other._ps else _0_0
1446
1482
  elif self._f2product: # len(other._ps) == 1
1447
1483
  f = self._mul_scalar(other._ps[0], op)
1448
1484
  else: # len(other._ps) == len(self._ps) == 1
@@ -1457,39 +1493,41 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1457
1493
  '''DEPRECATED on 2024.09.13, use method L{f2mul_<Fsum.f2mul_>}.'''
1458
1494
  return self._fset(self.f2mul_(*others, **raiser))
1459
1495
 
1460
- def f2mul_(self, *others, **raiser): # in .fmath.f2mul
1496
+ def f2mul_(self, *others, **nonfinites): # in .fmath.f2mul
1461
1497
  '''Return C{B{self} * B{other} * B{other} ...} for all B{C{others}} using cascaded,
1462
1498
  accurate multiplication like with L{f2product<Fsum.f2product>} set to C{True}.
1463
1499
 
1464
1500
  @arg others: Multipliers (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}), all
1465
1501
  positional.
1466
- @kwarg raiser: Keyword argument C{B{raiser}=False}, if C{True}, throw an exception,
1467
- otherwise pass the I{non-finite} result (C{bool}).
1502
+ @kwarg nonfinites: Use C{B{nonfinites}=True} or C{False}, to override both
1503
+ L{nonfinites<Fsum.nonfinites>} and the L{nonfiniterrors}
1504
+ default (C{bool}).
1468
1505
 
1469
1506
  @return: The cascaded I{TwoProduct} (L{Fsum} or C{float}).
1470
1507
 
1471
1508
  @see: U{Equations 2.3<https://www.TUHH.De/ti3/paper/rump/OzOgRuOi06.pdf>}
1472
1509
  '''
1473
- return self._f2mul(self.f2mul_, *others, **raiser)
1510
+ return self._f2mul(self.f2mul_, *others, **nonfinites)
1474
1511
 
1475
- def _f2mul(self, where, *others, **raiser):
1512
+ def _f2mul(self, where, *others, **nonfinites_raiser):
1476
1513
  '''(INTERNAL) See methods C{fma} and C{f2mul_}.
1477
1514
  '''
1478
- f = self._copy_2(where)
1479
- if others:
1515
+ f = self._copy_2(where)
1516
+ ps = f._ps
1517
+ if ps and others:
1480
1518
  op = where.__name__
1481
- ps = f._ps
1482
- if ps:
1483
- try:
1484
- for p in self._ps_other(op, *others):
1519
+ try:
1520
+ for other in others: # to pinpoint errors
1521
+ for p in self._ps_other(op, other):
1485
1522
  pfs = _2products(p, _2split3s(ps))
1486
1523
  ps[:] = f._ps_acc([], pfs, up=False)
1487
- f._update()
1488
- except (OverflowError, TypeError, ValueError) as X:
1489
- r = self._mul_reduce(op, _sum(ps), *others) # INF, NAN, NINF
1490
- if _xkwds_get1(raiser, raiser=False):
1491
- r = self._nonfiniteX(X, op, r)
1492
- f._fset(r)
1524
+ f._update()
1525
+ except TypeError as X:
1526
+ raise self._ErrorX(X, op, other)
1527
+ except (OverflowError, ValueError) as X:
1528
+ r = self._mul_reduce(sum(ps), other) # INF, NAN, NINF
1529
+ r = self._nonfiniteX(X, op, r, **nonfinites_raiser)
1530
+ f._fset(r)
1493
1531
  return f
1494
1532
 
1495
1533
  def fover(self, over, **raiser_RESIDUAL):
@@ -1520,7 +1558,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1520
1558
  elif self.is_integer():
1521
1559
  # return an exact C{int} for C{int}**C{int}
1522
1560
  i, _ = self._fint2 # assert _ == 0
1523
- x, r = _2scalar2(other) # C{int}, C{float} or other
1561
+ x, r = _2s_r(other) # C{int}, C{float} or other
1524
1562
  f = self._Fsum_as(i)._pow_Fsum(other, op, **raiser_RESIDUAL) if r else \
1525
1563
  self._pow_2_3(i, x, other, op, **raiser_RESIDUAL)
1526
1564
  else: # mod[0] is None, power(self, other)
@@ -1531,8 +1569,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1531
1569
 
1532
1570
  def f2product(self, *two):
1533
1571
  '''Get and set accurate I{TwoProduct} multiplication for this
1534
- L{Fsum}, I{overriding the global setting} from function
1535
- L{f2product<fsums.f2product>}.
1572
+ L{Fsum}, overriding the L{f2product} default.
1536
1573
 
1537
1574
  @arg two: If omitted, leave the override unchanged, if C{True},
1538
1575
  turn I{TwoProduct} on, if C{False} off, if C{None}e
@@ -1564,7 +1601,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1564
1601
  s, _ = self._fprs2
1565
1602
  return s # ._fprs2.fsum
1566
1603
 
1567
- @_fprs.setter_ # PYCHOK setter_underscore!
1604
+ @_fprs.setter_ # PYCHOK setter_UNDERscore!
1568
1605
  def _fprs(self, s):
1569
1606
  '''(INTERNAL) Replace the C{_fprs} value.
1570
1607
  '''
@@ -1576,30 +1613,37 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1576
1613
  running sum and residual (L{Fsum2Tuple}).
1577
1614
  '''
1578
1615
  ps = self._ps
1616
+ n = len(ps)
1579
1617
  try:
1580
- n = len(ps) - 2
1581
- if n > 0: # len(ps) > 2
1618
+ if n > 2:
1582
1619
  s = _psum(ps, **self._isfine)
1583
- n = len(ps) - 2
1584
- if n > 0:
1620
+ if not _isfinite(s):
1621
+ ps[:] = s, # collapse ps
1622
+ return Fsum2Tuple(s, _NONFINITEr)
1623
+ n = len(ps)
1624
+ # Fsum._ps_max = max(Fsum._ps_max, n)
1625
+ if n > 2:
1585
1626
  r = self._ps_1sum(s)
1586
1627
  return Fsum2Tuple(*_s_r(s, r))
1587
- if n == 0: # len(ps) == 2
1628
+ if n > 1: # len(ps) == 2
1588
1629
  s, r = _s_r(*_2sum(*ps, **self._isfine))
1589
1630
  ps[:] = (r, s) if r else (s,)
1590
1631
  elif ps: # len(ps) == 1
1591
- s, r = ps[0], INT0
1632
+ s = ps[0]
1633
+ r = INT0 if _isfinite(s) else _NONFINITEr
1592
1634
  else: # len(ps) == 0
1593
- s, r = _0_0, INT0
1635
+ s = _0_0
1636
+ r = INT0 if _isfinite(s) else _NONFINITEr
1594
1637
  ps[:] = s,
1595
1638
  except (OverflowError, ValueError) as X:
1596
- op = _sum.__name__ # INF, NAN, NINF
1597
- s = self._nonfiniteX(X, op, _sum(self._ps))
1598
- r = _0_0
1639
+ op = _fset_op_ # INF, NAN, NINF
1640
+ ps[:] = sum(ps), # collapse ps
1641
+ s = self._nonfiniteX(X, op, ps[0])
1642
+ r = _NONFINITEr
1599
1643
  # assert self._ps is ps
1600
1644
  return Fsum2Tuple(s, r)
1601
1645
 
1602
- @_fprs2.setter_ # PYCHOK setter_underscore!
1646
+ @_fprs2.setter_ # PYCHOK setter_UNDERscore!
1603
1647
  def _fprs2(self, s_r):
1604
1648
  '''(INTERNAL) Replace the C{_fprs2} value.
1605
1649
  '''
@@ -1616,15 +1660,18 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1616
1660
 
1617
1661
  @see: Method L{Fsum.fadd} for further details.
1618
1662
  '''
1619
- return self._fset(xs[0], op=_fset_op_) if len(xs) == 1 else \
1620
- self._fset(_0_0)._facc_args(xs)
1663
+ f = (xs[0] if xs else _0_0) if len(xs) < 2 else \
1664
+ Fsum(*xs, nonfinites=self.nonfinites()) # self._Fsum_as(*xs)
1665
+ return self._fset(f, op=_fset_op_)
1621
1666
 
1622
1667
  def _fset(self, other, n=0, up=True, **op):
1623
1668
  '''(INTERNAL) Overwrite this instance with an other or a C{scalar}.
1624
1669
  '''
1625
1670
  if other is self:
1626
1671
  pass # from ._fmul, ._ftruediv and ._pow_0_1
1627
- elif _isFsumTuple(other):
1672
+ elif _isFsum_2Tuple(other):
1673
+ if op: # and not self.nonfinitesOK:
1674
+ self._finite(other._fprs, **op)
1628
1675
  self._ps[:] = other._ps
1629
1676
  self._n = n or other._n
1630
1677
  if up: # use or zap the C{Property_RO} values
@@ -1647,11 +1694,6 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1647
1694
  raise self._Error(op, other, _TypeError)
1648
1695
  return self
1649
1696
 
1650
- def _fset_ps(self, other): # in .fmath._Fsum__init__
1651
- '''(INTERNAL) Set partials from a known C{other}.
1652
- '''
1653
- return self._fset(other, up=False)
1654
-
1655
1697
  def fsub(self, xs=()):
1656
1698
  '''Subtract an iterable's items from this instance.
1657
1699
 
@@ -1664,13 +1706,13 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1664
1706
 
1665
1707
  @see: Method L{Fsum.fadd_} for further details.
1666
1708
  '''
1667
- return self._facc_neg(xs, origin=1) if len(xs) != 1 else \
1668
- self._fsub(xs[0], _sub_op_)
1709
+ return self._fsub(xs[0], _sub_op_) if len(xs) == 1 else \
1710
+ self._facc_neg(xs) # origin=1?
1669
1711
 
1670
1712
  def _fsub(self, other, op):
1671
1713
  '''(INTERNAL) Apply C{B{self} -= B{other}}.
1672
1714
  '''
1673
- if _isFsumTuple(other):
1715
+ if _isFsum_2Tuple(other):
1674
1716
  if other is self: # or other._fprs2 == self._fprs2:
1675
1717
  self._fset(_0_0, n=len(self) * 2)
1676
1718
  elif other._ps:
@@ -1680,11 +1722,11 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1680
1722
  return self
1681
1723
 
1682
1724
  def fsum(self, xs=()):
1683
- '''Add an iterable's items, summate and return the
1684
- current precision running sum.
1725
+ '''Add an iterable's items, summate and return the current
1726
+ precision running sum.
1685
1727
 
1686
- @arg xs: Iterable of items to add (each item C{scalar}
1687
- or an L{Fsum} or L{Fsum2Tuple} instance).
1728
+ @arg xs: Iterable of items to add (each item C{scalar},
1729
+ an L{Fsum} or L{Fsum2Tuple}).
1688
1730
 
1689
1731
  @return: Precision running sum (C{float} or C{int}).
1690
1732
 
@@ -1695,11 +1737,11 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1695
1737
  return self._facc(xs)._fprs
1696
1738
 
1697
1739
  def fsum_(self, *xs):
1698
- '''Add any positional items, summate and return the
1699
- current precision running sum.
1740
+ '''Add any positional items, summate and return the current
1741
+ precision running sum.
1700
1742
 
1701
- @arg xs: Items to add (each C{scalar} or an L{Fsum}
1702
- or L{Fsum2Tuple} instance), all positional.
1743
+ @arg xs: Items to add (each C{scalar}, an L{Fsum} or
1744
+ L{Fsum2Tuple}), all positional.
1703
1745
 
1704
1746
  @return: Precision running sum (C{float} or C{int}).
1705
1747
 
@@ -1723,10 +1765,10 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1723
1765
 
1724
1766
  @return: Precision running sum (L{Fsum2Tuple}).
1725
1767
  '''
1726
- return Fsum2Tuple(self._facc_args(xs)._fprs2, **name)
1768
+ return Fsum2Tuple(self._facc_args(xs)._nfprs2, **name)
1727
1769
 
1728
1770
  @property_RO
1729
- def _Fsum(self): # like L{Fsum2Tuple._Fsum}, for C{_2floats}, .fstats
1771
+ def _Fsum(self): # like L{Fsum2Tuple._Fsum}, in .fstats
1730
1772
  return self # NOT @Property_RO, see .copy and ._copy_2
1731
1773
 
1732
1774
  def _Fsum_as(self, *xs, **name_f2product_nonfinites_RESIDUAL):
@@ -1740,17 +1782,17 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1740
1782
  RESIDUAL =self.RESIDUAL())
1741
1783
  if name_f2product_nonfinites_RESIDUAL: # overwrites
1742
1784
  kwds.update(name_f2product_nonfinites_RESIDUAL)
1743
- F = Fsum(**kwds)
1744
- # assert all(v == self.__dict__[n] for n, v in F.__dict__.items())
1745
- return F._fset(xs[0]) if len(xs) == 1 else (
1746
- F._facc(xs, up=False) if xs else F)
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)
1747
1789
 
1748
1790
  def fsum2(self, xs=(), **name):
1749
1791
  '''Add an iterable's items, summate and return the
1750
1792
  current precision running sum I{and} the C{residual}.
1751
1793
 
1752
- @arg xs: Iterable of items to add (each item C{scalar}
1753
- or an L{Fsum} or L{Fsum2Tuple} instance).
1794
+ @arg xs: Iterable of items to add (each item C{scalar},
1795
+ an L{Fsum} or L{Fsum2Tuple}).
1754
1796
  @kwarg name: Optional C{B{name}=NN} (C{str}).
1755
1797
 
1756
1798
  @return: L{Fsum2Tuple}C{(fsum, residual)} with C{fsum} the
@@ -1768,8 +1810,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1768
1810
  '''Add any positional items, summate and return the current
1769
1811
  precision running sum and the I{differential}.
1770
1812
 
1771
- @arg xs: Values to add (each C{scalar} or an L{Fsum} or
1772
- L{Fsum2Tuple} instance), all positional.
1813
+ @arg xs: Values to add (each C{scalar}, an L{Fsum} or
1814
+ L{Fsum2Tuple}), all positional.
1773
1815
 
1774
1816
  @return: 2Tuple C{(fsum, delta)} with the current, precision
1775
1817
  running C{fsum} like method L{Fsum.fsum} and C{delta},
@@ -1779,33 +1821,36 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1779
1821
  '''
1780
1822
  return self._fsum2(xs, self._facc_args)
1781
1823
 
1782
- def _fsum2(self, xs, _facc, **origin):
1824
+ def _fsum2(self, xs, _facc, **facc_kwds):
1783
1825
  '''(INTERNAL) Helper for L{Fsum.fsum2_} and L{Fsum.fsum2f_}.
1784
1826
  '''
1785
1827
  p, q = self._fprs2
1786
1828
  if xs:
1787
- s, r = _facc(xs, **origin)._fprs2
1829
+ s, r = _facc(xs, **facc_kwds)._fprs2
1788
1830
  if _isfinite(s): # _fsum(_1primed((s, -p, r, -q))
1789
1831
  d, r = _2sum(s - p, r - q, _isfine=_isOK)
1790
1832
  r, _ = _s_r(d, r)
1791
- return s, (r if _isfinite(r) else _0_0)
1833
+ return s, (r if _isfinite(r) else _NONFINITEr)
1792
1834
  else:
1793
1835
  return p, _0_0
1794
1836
 
1795
1837
  def fsumf_(self, *xs):
1796
- '''Like method L{Fsum.fsum_} iff I{all} C{B{xs}} are I{known to be scalar}.
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}.
1797
1840
  '''
1798
- return self._facc_scalar(xs)._fprs
1841
+ return self._facc_scalarf(xs, which=self.fsumf_)._fprs # origin=1?
1799
1842
 
1800
1843
  def Fsumf_(self, *xs):
1801
- '''Like method L{Fsum.Fsum_} iff I{all} C{B{xs}} are I{known to be scalar}.
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}.
1802
1846
  '''
1803
- return self._facc_scalar(xs)._copy_2(self.Fsumf_)
1847
+ return self._facc_scalarf(xs, which=self.Fsumf_)._copy_2(self.Fsumf_) # origin=1?
1804
1848
 
1805
1849
  def fsum2f_(self, *xs):
1806
- '''Like method L{Fsum.fsum2_} iff I{all} C{B{xs}} are I{known to be scalar}.
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}.
1807
1852
  '''
1808
- return self._fsum2(xs, self._facc_scalar, origin=1)
1853
+ return self._fsum2(xs, self._facc_scalarf, which=self.fsum2f_) # origin=1?
1809
1854
 
1810
1855
  # ftruediv = __itruediv__ # for naming consistency?
1811
1856
 
@@ -1813,7 +1858,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1813
1858
  '''(INTERNAL) Apply C{B{self} /= B{other}}.
1814
1859
  '''
1815
1860
  n = _1_0
1816
- if _isFsumTuple(other):
1861
+ if _isFsum_2Tuple(other):
1817
1862
  if other is self or self == other:
1818
1863
  return self._fset(n, n=len(self))
1819
1864
  d, r = other._fprs2
@@ -1846,9 +1891,9 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1846
1891
  L{ResidualError}s (C{bool}) and C{B{RESIDUAL}=scalar}
1847
1892
  to override the current L{RESIDUAL<Fsum.RESIDUAL>}.
1848
1893
 
1849
- @return: This C{integer} sum if this instance C{is_integer},
1850
- otherwise return the C{float} sum if the residual is
1851
- zero or not significant.
1894
+ @return: This C{int} sum if this instance C{is_integer} and
1895
+ I{finite}, otherwise the C{float} sum if the residual
1896
+ is zero or not significant.
1852
1897
 
1853
1898
  @raise ResidualError: Non-zero, significant residual or invalid
1854
1899
  B{C{RESIDUAL}}.
@@ -1878,7 +1923,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1878
1923
 
1879
1924
  @see: Function L{isfinite<pygeodesy.isfinite>}.
1880
1925
  '''
1881
- return _isfinite(_sum(self._ps)) # _sum(self)
1926
+ return _isfinite(sum(self._ps)) # == sum(self)
1882
1927
 
1883
1928
  def is_integer(self):
1884
1929
  '''Is this instance' running sum C{integer}? (C{bool}).
@@ -1895,7 +1940,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1895
1940
  an C{fma} implementation as C{math.fma} or C{None}, a previous
1896
1941
  C{PyGeodesy} implementation.
1897
1942
  '''
1898
- return (_fma.__module__ is fabs.__module__ or None) if _2split3s is _passarg else False
1943
+ return (_2split3s is _passarg) or (False if _2n_d is None else None)
1899
1944
 
1900
1945
  def is_math_fsum(self):
1901
1946
  '''Are the summation functions L{fsum}, L{fsum_}, L{fsumf_}, L{fsum1},
@@ -1907,48 +1952,52 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1907
1952
  return _sum is _fsum # _fsum.__module__ is fabs.__module__
1908
1953
 
1909
1954
  def is_scalar(self, **raiser_RESIDUAL):
1910
- '''Is this instance' running sum C{scalar} without residual or with
1955
+ '''Is this instance' running sum C{scalar} with C{0} residual or with
1911
1956
  a residual I{ratio} not exceeding the RESIDUAL threshold?
1912
1957
 
1913
1958
  @kwarg raiser_RESIDUAL: Use C{B{raiser}=False} to ignore
1914
1959
  L{ResidualError}s (C{bool}) and C{B{RESIDUAL}=scalar}
1915
1960
  to override the current L{RESIDUAL<Fsum.RESIDUAL>}.
1916
1961
 
1917
- @return: C{True} if this instance' non-zero residual C{ratio} exceeds
1918
- the L{RESIDUAL<Fsum.RESIDUAL>} threshold (C{bool}).
1962
+ @return: C{True} if this instance' residual is C{0} or C{insignificant},
1963
+ i.e. its residual C{ratio} doesn't exceed the L{RESIDUAL
1964
+ <Fsum.RESIDUAL>} threshold (C{bool}).
1919
1965
 
1920
1966
  @raise ResidualError: Non-zero, significant residual or invalid
1921
1967
  B{C{RESIDUAL}}.
1922
1968
 
1923
- @see: Method L{Fsum.RESIDUAL}, L{Fsum.is_integer} and property
1969
+ @see: Methods L{Fsum.RESIDUAL} and L{Fsum.is_integer} and property
1924
1970
  L{Fsum.as_iscalar}.
1925
1971
  '''
1926
1972
  s, r = self._fprs2
1927
1973
  return False if r and self._raiser(r, s, **raiser_RESIDUAL) else True
1928
1974
 
1929
- def _mul_Fsum(self, other, op=_mul_op_): # in .fmath.Fhorner
1975
+ def _mul_Fsum(self, other, op):
1930
1976
  '''(INTERNAL) Return C{B{self} * B{other}} as L{Fsum} or C{0}.
1931
1977
  '''
1932
- # assert _isFsumTuple(other)
1978
+ # assert _isFsum_2Tuple(other)
1933
1979
  if self._ps and other._ps:
1934
- f = self._ps_mul(op, *other._ps) # NO .as_iscalar!
1980
+ try:
1981
+ f = self._ps_mul(op, *other._ps) # NO .as_iscalar!
1982
+ except Exception as X:
1983
+ raise self._ErrorX(X, op, other)
1935
1984
  else:
1936
1985
  f = _0_0
1937
1986
  return f
1938
1987
 
1939
- def _mul_reduce(self, op, start, *others):
1940
- '''(INTERNAL) Like fmath.freduce(_operator.mul, ...)
1941
- for I{non-finite} C{start} and/or C{others}.
1988
+ def _mul_reduce(self, *others):
1989
+ '''(INTERNAL) Like fmath.fprod for I{non-finite} C{other}s.
1942
1990
  '''
1943
- for p in self._ps_other(op, *others):
1944
- start *= p
1945
- return start
1991
+ r = _1_0
1992
+ for f in others:
1993
+ r *= sum(f._ps) if _isFsum_2Tuple(f) else float(f)
1994
+ return r
1946
1995
 
1947
- def _mul_scalar(self, factor, op): # in .fmath.Fhorner
1996
+ def _mul_scalar(self, factor, op):
1948
1997
  '''(INTERNAL) Return C{B{self} * scalar B{factor}} as L{Fsum}, C{0.0} or C{self}.
1949
1998
  '''
1950
1999
  # assert isscalar(factor)
1951
- if self._ps and self._finite(factor, op):
2000
+ if self._ps and self._finite(factor, op=op):
1952
2001
  f = self if factor == _1_0 else (
1953
2002
  self._neg if factor == _N_1_0 else
1954
2003
  self._ps_mul(op, factor).as_iscalar)
@@ -1967,11 +2016,20 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1967
2016
  '''
1968
2017
  return _Psum(self._ps_neg) if self._ps else NEG0
1969
2018
 
2019
+ @property_RO
2020
+ def _nfprs2(self):
2021
+ '''(INTERNAL) Handle I{non-finite} C{_fprs2}.
2022
+ '''
2023
+ try: # to handle nonfiniterrors, etc.
2024
+ t = self._fprs2
2025
+ except (OverflowError, ValueError):
2026
+ t = Fsum2Tuple(sum(self._ps), _NONFINITEr)
2027
+ return t
2028
+
1970
2029
  def nonfinites(self, *OK):
1971
2030
  '''Handle I{non-finite} C{float}s as C{inf}, C{INF}, C{NINF}, C{nan}
1972
2031
  and C{NAN} for this L{Fsum} or throw C{OverflowError} respectively
1973
- C{ValueError} exceptions, I{overriding the global setting} from
1974
- function L{nonfiniterrors<fsums.nonfiniterrors>}.
2032
+ C{ValueError} exceptions, overriding the L{nonfiniterrors} default.
1975
2033
 
1976
2034
  @arg OK: If omitted, leave the override unchanged, if C{True},
1977
2035
  I{non-finites} are C{OK}, if C{False} throw exceptions
@@ -1981,14 +2039,16 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1981
2039
 
1982
2040
  @see: Function L{nonfiniterrors<fsums.nonfiniterrors>}.
1983
2041
 
1984
- @note: Use C{f.nonfinites() or not nonfiniterrors()} to determine
1985
- whether L{Fsum} C{f} handles I{non-finites}.
2042
+ @note: Use property L{nonfinitesOK<Fsum.nonfinitesOK>} to determine
2043
+ whether I{non-finites} are C{OK} for this L{Fsum} and by the
2044
+ L{nonfiniterrors} default.
1986
2045
  '''
1987
2046
  _ks = Fsum._nonfinites_isfine_kwds
1988
2047
  if OK: # delattrof(self, _isfine=None)
1989
2048
  k = _xkwds_pop(self.__dict__, _isfine=None)
1990
2049
  if OK[0] is not None:
1991
2050
  self._isfine = _ks[bool(OK[0])]
2051
+ self._update()
1992
2052
  else: # getattrof(self, _isfine=None)
1993
2053
  k = _xkwds_get(self.__dict__, _isfine=None)
1994
2054
  # dict(map(reversed, _ks.items())).get(k, None)
@@ -1999,10 +2059,21 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1999
2059
  _nonfinites_isfine_kwds = {True: dict(_isfine=_isOK),
2000
2060
  False: dict(_isfine=_isfinite)}
2001
2061
 
2002
- def _nonfiniteX(self, X, op, f):
2062
+ @property_RO
2063
+ def nonfinitesOK(self):
2064
+ '''Are I{non-finites} C{OK} for this L{Fsum} or by default? (C{bool}).
2065
+ '''
2066
+ # nf = self.nonfinites()
2067
+ # if nf is None:
2068
+ # nf = not nonfiniterrors()
2069
+ return _isOK_or_finite(INF, **self._isfine)
2070
+
2071
+ def _nonfiniteX(self, X, op, f, nonfinites=None, raiser=None):
2003
2072
  '''(INTERNAL) Handle a I{non-finite} exception.
2004
2073
  '''
2005
- if not _isOK_or_finite(f, **self._isfine):
2074
+ if nonfinites is None:
2075
+ nonfinites = _isOK_or_finite(f, **self._isfine) if raiser is None else (not raiser)
2076
+ if not nonfinites:
2006
2077
  raise self._ErrorX(X, op, f)
2007
2078
  return f
2008
2079
 
@@ -2063,10 +2134,10 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2063
2134
  def _pow(self, other, unused, op, **raiser_RESIDUAL):
2064
2135
  '''Return C{B{self} ** B{other}}.
2065
2136
  '''
2066
- if _isFsumTuple(other):
2137
+ if _isFsum_2Tuple(other):
2067
2138
  f = self._pow_Fsum(other, op, **raiser_RESIDUAL)
2068
2139
  elif self._scalar(other, op):
2069
- x = self._finite(other, op)
2140
+ x = self._finite(other, op=op)
2070
2141
  f = self._pow_scalar(x, other, op, **raiser_RESIDUAL)
2071
2142
  else:
2072
2143
  f = self._pow_0_1(0, other)
@@ -2084,7 +2155,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2084
2155
 
2085
2156
  if mod: # b, x, mod all C{int}, unless C{mod} is C{None}
2086
2157
  m = mod[0]
2087
- # assert _isFsumTuple(b)
2158
+ # assert _isFsum_2Tuple(b)
2088
2159
 
2089
2160
  def _s(s, r):
2090
2161
  R = self._raiser(r, s, **raiser_RESIDUAL)
@@ -2093,7 +2164,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2093
2164
  return s
2094
2165
 
2095
2166
  b = _s(*(b._fprs2 if m is None else b._fint2))
2096
- x = _s(*_2scalar2(x))
2167
+ x = _s(*_2s_r(x))
2097
2168
 
2098
2169
  try:
2099
2170
  # 0**INF == 0.0, 1**INF == 1.0, -1**2.3 == -(1**2.3)
@@ -2101,14 +2172,15 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2101
2172
  if iscomplex(s):
2102
2173
  # neg**frac == complex in Python 3+, but ValueError in 2-
2103
2174
  raise ValueError(_strcomplex(s, b, x, *mod))
2104
- return self._finite(s)
2175
+ _ = _2finite(s, **self._isfine) # ignore float
2176
+ return s
2105
2177
  except Exception as X:
2106
2178
  raise self._ErrorX(X, op, other, *mod)
2107
2179
 
2108
2180
  def _pow_Fsum(self, other, op, **raiser_RESIDUAL):
2109
- '''(INTERNAL) Return C{B{self} **= B{other}} for C{_isFsumTuple(other)}.
2181
+ '''(INTERNAL) Return C{B{self} **= B{other}} for C{_isFsum_2Tuple(other)}.
2110
2182
  '''
2111
- # assert _isFsumTuple(other)
2183
+ # assert _isFsum_2Tuple(other)
2112
2184
  x, r = other._fprs2
2113
2185
  f = self._pow_scalar(x, other, op, **raiser_RESIDUAL)
2114
2186
  if f and r:
@@ -2202,13 +2274,12 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2202
2274
  n += 1
2203
2275
  if n:
2204
2276
  self._n += n
2205
- # if _fi: # collapse ps if non-finite
2206
- # x = _sum(ps)
2207
- # if not _isfinite(x):
2208
- # ps[:] = x,
2209
2277
  # Fsum._ps_max = max(Fsum._ps_max, len(ps))
2210
2278
  if up:
2211
2279
  self._update()
2280
+ # x = sum(ps)
2281
+ # if not _isOK_or_finite(x, **fi):
2282
+ # ps[:] = x, # collapse ps
2212
2283
  return ps
2213
2284
 
2214
2285
  def _ps_mul(self, op, *factors):
@@ -2219,19 +2290,21 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2219
2290
  if len(ps) < len(fs):
2220
2291
  ps, fs = fs, ps
2221
2292
  if self._f2product:
2222
- ps = _2split3s(ps)
2223
- _fps = _2products
2293
+ fs, p = _2split3s(fs), fs
2294
+ if len(ps) > 1 and fs is not p:
2295
+ fs = tuple(fs) # several ps
2296
+ _pfs = _2products
2224
2297
  else:
2225
- def _fps(f, ps):
2226
- return (f * p for p in ps)
2298
+ def _pfs(p, fs):
2299
+ return (p * f for f in fs)
2227
2300
 
2228
- for f in fs:
2229
- for p in _fps(f, ps):
2230
- yield p if _isfine(p) else self._finite(p, op)
2301
+ for p in ps:
2302
+ for f in _pfs(p, fs):
2303
+ yield f if _isfine(f) else _nfError(f)
2231
2304
 
2232
- F = self._Fsum_as(name=op) # assert F._ps is not self._ps
2233
- _s = _psfs(self._ps, factors, **self._isfine)
2234
- return F._facc_scalar(_s, up=False)
2305
+ fs = _psfs(self._ps, factors, **self._isfine)
2306
+ f = _Psum(self._ps_acc([], fs, up=False), name=op)
2307
+ return f
2235
2308
 
2236
2309
  @property_RO
2237
2310
  def _ps_neg(self):
@@ -2240,15 +2313,14 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2240
2313
  for p in self._ps:
2241
2314
  yield -p
2242
2315
 
2243
- def _ps_other(self, op, *others):
2244
- '''(INTERNAL) Yield all C{other}s as C{scalar}.
2316
+ def _ps_other(self, op, other):
2317
+ '''(INTERNAL) Yield C{other} as C{scalar}s.
2245
2318
  '''
2246
- for other in others:
2247
- if _isFsumTuple(other):
2248
- for p in other._ps:
2249
- yield p
2250
- else:
2251
- yield self._scalar(other, op)
2319
+ if _isFsum_2Tuple(other):
2320
+ for p in other._ps:
2321
+ yield p
2322
+ else:
2323
+ yield self._scalar(other, op)
2252
2324
 
2253
2325
  def _ps_1sum(self, *less):
2254
2326
  '''(INTERNAL) Return the partials sum, 1-primed C{less} some scalars.
@@ -2345,7 +2417,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2345
2417
  def root(self, root, **raiser_RESIDUAL):
2346
2418
  '''Return C{B{self}**(1 / B{root})} as L{Fsum}.
2347
2419
 
2348
- @arg root: The order (C{scalar}, L{Fsum} or L{Fsum2Tuple}), non-zero.
2420
+ @arg root: Non-zero order (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
2349
2421
  @kwarg raiser_RESIDUAL: Use C{B{raiser}=False} to ignore any
2350
2422
  L{ResidualError}s (C{bool}) or C{B{RESIDUAL}=scalar}
2351
2423
  to override the current L{RESIDUAL<Fsum.RESIDUAL>}.
@@ -2362,7 +2434,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2362
2434
  return f._fpow(x, f.name, **raiser_RESIDUAL) # == pow(f, x)
2363
2435
 
2364
2436
  def _scalar(self, other, op, **txt):
2365
- '''(INTERNAL) Return scalar C{other}.
2437
+ '''(INTERNAL) Return scalar C{other} or throw a C{TypeError}.
2366
2438
  '''
2367
2439
  if isscalar(other):
2368
2440
  return other
@@ -2371,12 +2443,12 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2371
2443
  def signOf(self, res=True):
2372
2444
  '''Determine the sign of this instance.
2373
2445
 
2374
- @kwarg res: If C{True}, consider, otherwise ignore
2375
- the residual (C{bool}).
2446
+ @kwarg res: If C{True}, consider the residual,
2447
+ otherwise ignore the latter (C{bool}).
2376
2448
 
2377
2449
  @return: The sign (C{int}, -1, 0 or +1).
2378
2450
  '''
2379
- s, r = self._fprs2
2451
+ s, r = self._nfprs2
2380
2452
  r = (-r) if res else 0
2381
2453
  return _signOf(s, r)
2382
2454
 
@@ -2404,7 +2476,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2404
2476
  if lenc:
2405
2477
  p = Fmt.SQUARE(p, len(self))
2406
2478
  n = _enquote(self.name, white=_UNDER_)
2407
- t = self._fprs2.toStr(**prec_sep_fmt)
2479
+ t = self._nfprs2.toStr(**prec_sep_fmt)
2408
2480
  return NN(p, _SPACE_, n, t)
2409
2481
 
2410
2482
  def _truediv(self, other, op, **raiser_RESIDUAL):
@@ -2427,7 +2499,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2427
2499
 
2428
2500
  _ROs = _allPropertiesOf_n(3, Fsum, Property_RO) # PYCHOK see Fsum._update
2429
2501
 
2430
- if _NONFINITES: # PYCHOK no cover
2502
+ if _NONFINITES == _std_: # PYCHOK no cover
2431
2503
  _ = nonfiniterrors(False)
2432
2504
 
2433
2505
 
@@ -2574,7 +2646,7 @@ class Fsum2Tuple(_NamedTuple): # in .fstats
2574
2646
  '''
2575
2647
  return Fmt.PAREN(fstr(self, fmt=fmt, strepr=str, force=False, **prec_sep))
2576
2648
 
2577
- _Fsum_Fsum2Tuple_types = Fsum, Fsum2Tuple # PYCHOK lines
2649
+ _Fsum_2Tuple_types = Fsum, Fsum2Tuple # PYCHOK lines
2578
2650
 
2579
2651
 
2580
2652
  class ResidualError(_ValueError):
@@ -2603,7 +2675,7 @@ except ImportError:
2603
2675
  def _fsum(xs):
2604
2676
  '''(INTERNAL) Precision summation, Python 2.5-.
2605
2677
  '''
2606
- F = Fsum(name=_fsum.name, nonfinites=True)
2678
+ F = Fsum(name=_fsum.name, f2product=False, nonfinites=True)
2607
2679
  return float(F._facc(xs, up=False))
2608
2680
 
2609
2681
 
@@ -2613,8 +2685,7 @@ def fsum(xs, nonfinites=None, **floats):
2613
2685
  @arg xs: Iterable of items to add (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
2614
2686
  @kwarg nonfinites: Use C{B{nonfinites}=True} if I{non-finites} are C{OK}, if
2615
2687
  C{False} I{non-finites} raise an Overflow-/ValueError or if
2616
- C{None}, apply C{B{nonfinites}=not }L{nonfiniterrors()}
2617
- (C{bool} or C{None}).
2688
+ C{None}, L{nonfiniterrors} applies (C{bool} or C{None}).
2618
2689
  @kwarg floats: DEPRECATED keyword argument C{B{floats}=False} (C{bool}), use
2619
2690
  keyword argument C{B{nonfinites}=False} instead.
2620
2691
 
@@ -2640,7 +2711,7 @@ def fsum_(*xs, **nonfinites):
2640
2711
 
2641
2712
  @see: Function L{fsum<fsums.fsum>} for further details.
2642
2713
  '''
2643
- return _xsum(fsum_, xs, origin=1, **nonfinites) if xs else _0_0
2714
+ return _xsum(fsum_, xs, **nonfinites) if xs else _0_0 # origin=1?
2644
2715
 
2645
2716
 
2646
2717
  def fsumf_(*xs):
@@ -2651,7 +2722,7 @@ def fsumf_(*xs):
2651
2722
 
2652
2723
  @see: Function L{fsum_<fsums.fsum_>} for further details.
2653
2724
  '''
2654
- return _xsum(fsumf_, xs, nonfinites=True, origin=1) if xs else _0_0
2725
+ return _xsum(fsumf_, xs, nonfinites=True) if xs else _0_0 # origin=1?
2655
2726
 
2656
2727
 
2657
2728
  def fsum1(xs, **nonfinites):
@@ -2673,7 +2744,7 @@ def fsum1_(*xs, **nonfinites):
2673
2744
 
2674
2745
  @see: Function L{fsum_<fsums.fsum_>} for further details.
2675
2746
  '''
2676
- return _xsum(fsum1_, xs, origin=1, primed=1, **nonfinites) if xs else _0_0
2747
+ return _xsum(fsum1_, xs, primed=1, **nonfinites) if xs else _0_0 # origin=1?
2677
2748
 
2678
2749
 
2679
2750
  def fsum1f_(*xs):
@@ -2685,45 +2756,50 @@ def fsum1f_(*xs):
2685
2756
  return _xsum(fsum1f_, xs, nonfinites=True, primed=1) if xs else _0_0
2686
2757
 
2687
2758
 
2688
- def _xs(xs, _x, i_x):
2689
- '''(INTERNAL) Yield all C{xs} as C{scalar}.
2690
- '''
2691
- for i, x in enumerate(xs):
2692
- i_x[:] = i, x
2693
- if _isFsumTuple(x):
2694
- for p in map(_x, x._ps):
2695
- yield p
2696
- else:
2697
- yield _x(x)
2759
+ def _x_isfine(nfOK, **kwds): # get the C{_x} and C{_isfine} handlers.
2760
+ _x_kwds = dict(_x= (_passarg if nfOK else _2finite),
2761
+ _isfine=(_isOK if nfOK else _isfinite)) # PYCHOK kwds
2762
+ _x_kwds.update(kwds)
2763
+ return _x_kwds
2698
2764
 
2699
2765
 
2700
- def _xsError(X, xs, i, x, *n): # in _2floats, ._fstats
2701
- '''(INTERNAL) Error for C{xs} or C{x}, item C{xs[i]}.
2702
- '''
2703
- return ((_xError(X, n[0], xs) if n else
2704
- _xError(X, xs=xs)) if x is xs else
2705
- _xError(X, Fmt.INDEX(xs=i), x))
2766
+ def _X_ps(X): # default C{_X} handler
2767
+ return X._ps # lambda X: X._ps
2706
2768
 
2707
2769
 
2708
- def _xsum(which, xs, nonfinites=None, origin=0, primed=0, **floats):
2709
- '''(INTERNAL) Precision summation of C{xs} with conditions.
2770
+ def _xs(xs, _X=_X_ps, _x=float, _isfine=_isfinite, # defaults for Fsum._facc
2771
+ origin=0, which=None, **_Cdot):
2772
+ '''(INTERNAL) Yield each C{xs} item as 1 or more C{float}s.
2710
2773
  '''
2711
- i_x = [0, xs]
2774
+ i, x = 0, xs
2712
2775
  try:
2713
- if nonfinites is None:
2714
- nonfinites = not nonfiniterrors()
2715
- elif floats:
2716
- nonfinites = _xkwds_get1(floats, floats=nonfinites)
2717
- fs = _xs(xs, (_passarg if nonfinites else _2finite), i_x)
2718
- return _fsum(_1primed(fs) if primed else fs)
2776
+ for i, x in enumerate(_xiterable(xs)):
2777
+ if isinstance(x, _Fsum_2Tuple_types):
2778
+ for p in _X(x):
2779
+ yield p if _isfine(p) else _nfError(p)
2780
+ else:
2781
+ f = _x(x)
2782
+ yield f if _isfine(f) else _nfError(f)
2783
+
2719
2784
  except (OverflowError, TypeError, ValueError) as X:
2720
- i, x = i_x
2721
- i += origin - (1 if primed else 0)
2722
- t = _xsError(X, xs, i, x)
2723
- t = _COMMASPACE_(unstr(which), t)
2785
+ t = _xsError(X, xs, i + origin, x)
2786
+ if which: # prefix invokation
2787
+ w = unstr(which, *xs, _ELLIPSIS=4, **_Cdot)
2788
+ t = _COMMASPACE_(w, t)
2724
2789
  raise _xError(X, t, txt=None)
2725
2790
 
2726
2791
 
2792
+ def _xsum(which, xs, nonfinites=None, primed=0, **floats): # origin=0
2793
+ '''(INTERNAL) Precision summation of C{xs} with conditions.
2794
+ '''
2795
+ if floats: # for backward compatibility
2796
+ nonfinites = _xkwds_get1(floats, floats=nonfinites)
2797
+ elif nonfinites is None:
2798
+ nonfinites = not nonfiniterrors()
2799
+ fs = _xs(xs, **_x_isfine(nonfinites, which=which))
2800
+ return _fsum(_1primed(fs) if primed else fs)
2801
+
2802
+
2727
2803
  # delete all decorators, etc.
2728
2804
  del _allPropertiesOf_n, deprecated_method, deprecated_property_RO, \
2729
2805
  Property, Property_RO, property_RO, _ALL_LAZY, _F2PRODUCT, \