pygeodesy 24.9.29__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,15 +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, \
51
- _xsError
48
+ _ValueError, _xError, _xError2, _xkwds, \
49
+ _xkwds_get, _xkwds_get1, _xkwds_not, \
50
+ _xkwds_pop, _xsError
52
51
  from pygeodesy.internals import _enquote, _passarg
53
52
  from pygeodesy.interns import NN, _arg_, _COMMASPACE_, _DOT_, _from_, \
54
53
  _not_finite_, _SPACE_, _std_, _UNDER_
@@ -65,7 +64,7 @@ from math import fabs, isinf, isnan, \
65
64
  ceil as _ceil, floor as _floor # PYCHOK used! .ltp
66
65
 
67
66
  __all__ = _ALL_LAZY.fsums
68
- __version__ = '24.09.29'
67
+ __version__ = '24.10.09'
69
68
 
70
69
  from pygeodesy.interns import (
71
70
  _PLUS_ as _add_op_, # in .auxilats.auxAngle
@@ -78,16 +77,13 @@ from pygeodesy.interns import (
78
77
  _DASH_ as _sub_op_, # in .auxilats.auxAngle
79
78
  _SLASH_ as _truediv_op_
80
79
  )
81
- _eq_op_ = _fset_op_ * 2 # _DEQUAL_
82
80
  _floordiv_op_ = _truediv_op_ * 2 # _DSLASH_
83
81
  _divmod_op_ = _floordiv_op_ + _mod_op_
84
82
  _F2PRODUCT = _getenv('PYGEODESY_FSUM_F2PRODUCT', NN)
85
- _ge_op_ = _gt_op_ + _fset_op_
86
83
  _iadd_op_ = _add_op_ + _fset_op_ # in .auxilats.auxAngle, .fstats
87
84
  _integer_ = 'integer'
88
85
  _isub_op_ = _sub_op_ + _fset_op_ # in .auxilats.auxAngle
89
- _le_op_ = _lt_op_ + _fset_op_
90
- _NONFINITEr = _0_0
86
+ _NONFINITEr = _0_0 # NOT INT0!
91
87
  _NONFINITES = _getenv('PYGEODESY_FSUM_NONFINITES', NN)
92
88
  _non_zero_ = 'non-zero'
93
89
  _pow_op_ = _mul_op_ * 2 # _DSTAR_
@@ -96,10 +92,10 @@ _significant_ = 'significant'
96
92
  _threshold_ = 'threshold'
97
93
 
98
94
 
99
- def _2finite(x): # in .fstats
95
+ def _2finite(x, _isfine=_isfinite): # in .fstats
100
96
  '''(INTERNAL) return C{float(x)} if finite.
101
97
  '''
102
- return (float(x) if _isfinite(x) # and isscalar(x)
98
+ return (float(x) if _isfine(x) # and isscalar(x)
103
99
  else _nfError(x))
104
100
 
105
101
 
@@ -114,28 +110,6 @@ def _2float(index=None, _isfine=_isfinite, **name_x): # in .fmath, .fstats
114
110
  raise _xError(X, Fmt.INDEX(n, index), x)
115
111
 
116
112
 
117
- def _X_ps(X): # for _2floats only
118
- return X._ps
119
-
120
-
121
- def _2floats(xs, origin=0, _X=_X_ps, _x=float, _isfine=_isfinite):
122
- '''(INTERNAL) Yield each B{C{xs}} as a C{float}.
123
- '''
124
- try:
125
- i, x = origin, xs
126
- _FsT = _Fsum_2Tuple_types
127
- for x in _xiterable(xs):
128
- if isinstance(x, _FsT):
129
- for p in _X(x._Fsum):
130
- yield p
131
- else:
132
- f = _x(x)
133
- yield f if _isfine(f) else _nfError(f)
134
- i += 1
135
- except Exception as X:
136
- raise _xsError(X, xs, i, x)
137
-
138
-
139
113
  try: # MCCABE 26
140
114
  from math import fma as _fma
141
115
 
@@ -145,8 +119,9 @@ try: # MCCABE 26
145
119
  # <https://www.TUHH.De/ti3/paper/rump/OgRuOi05.pdf>}
146
120
  for y in ys:
147
121
  f = x * y
148
- yield f
149
- yield _fma(x, y, -f)
122
+ yield f
123
+ if _isfinite(f):
124
+ yield _fma(x, y, -f)
150
125
  for z in zs:
151
126
  yield z
152
127
 
@@ -156,7 +131,7 @@ try: # MCCABE 26
156
131
  except ImportError: # PYCHOK DSPACE! Python 3.12-
157
132
 
158
133
  if _F2PRODUCT and _F2PRODUCT != _std_:
159
- # back to PyGeodesy 24.09.09, with _fmaX
134
+ # backward to PyGeodesy 24.09.09, with _fmaX
160
135
 
161
136
  def _fma(*a_b_c): # PYCHOK no cover
162
137
  # mimick C{math.fma} from Python 3.13+,
@@ -166,12 +141,13 @@ except ImportError: # PYCHOK DSPACE! Python 3.12-
166
141
  n += da * db * nc
167
142
  d = da * db * dc
168
143
  try:
169
- r = float(n / d)
144
+ n, d = _n_d2(n, d)
145
+ r = float(n / d)
170
146
  except OverflowError: # "integer division result too large ..."
171
147
  r = NINF if (_signOf(n, 0) * _signOf(d, 0)) < 0 else INF
172
148
  return r if _isfinite(r) else _fmaX(r, *a_b_c) # "overflow in fma"
173
149
 
174
- def _2n_d(x):
150
+ def _2n_d(x): # PYCHOK no cover
175
151
  try: # int.as_integer_ratio in 3.8+
176
152
  return x.as_integer_ratio()
177
153
  except (AttributeError, OverflowError, TypeError, ValueError):
@@ -188,18 +164,18 @@ except ImportError: # PYCHOK DSPACE! Python 3.12-
188
164
  _2n_d = None # redef
189
165
 
190
166
  def _fmaX(r, *a_b_c): # like Python 3.13+ I{Modules/mathmodule.c}:
191
- # raise a ValueError for a NAN result from non-NAN C{a_b_c}s or
192
- # OverflowError for a non-NAN result from all finite C{a_b_c}s.
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.
193
169
  if isnan(r):
194
170
  def _x(x):
195
171
  return not isnan(x)
196
- else:
172
+ else: # non-NAN non-finite
197
173
  _x = _isfinite
198
174
  if all(map(_x, a_b_c)):
199
175
  raise _nfError(r, unstr(_fma, *a_b_c))
200
176
  return r
201
177
 
202
- def _2products(x, y3s, *zs): # PYCHOK in Fsum._f2mul
178
+ def _2products(x, y3s, *zs): # PYCHOK in _fma, ...
203
179
  # yield(x * y3 for y3 in y3s) + yield(z in zs)
204
180
  # TwoProduct U{Algorithm 3.3
205
181
  # <https://www.TUHH.De/ti3/paper/rump/OgRuOi05.pdf>}
@@ -209,20 +185,16 @@ except ImportError: # PYCHOK DSPACE! Python 3.12-
209
185
  for y, c, d in y3s:
210
186
  y *= x
211
187
  yield y
212
- if False: # no cover
213
- yield b * d - (((y - a * c) - b * c) - a * d)
214
- # = b * d + (a * d - ((y - a * c) - b * c))
215
- # = b * d + (a * d + (b * c - (y - a * c)))
216
- # = b * d + (a * d + (b * c + (a * c - y)))
217
- elif a:
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)))
218
193
  yield a * c - y
219
194
  yield b * c
220
195
  if d:
221
196
  yield a * d
222
197
  yield b * d
223
- else:
224
- yield b * c - y
225
- yield b * d
226
198
  for z in zs:
227
199
  yield z
228
200
 
@@ -268,10 +240,10 @@ def _Fsumf_(*xs): # in .auxLat, .ltp, ...
268
240
  def _Fsum1f_(*xs): # in .albers
269
241
  '''(INTERNAL) An C{Fsum(xs)}, all C{scalar}, an L{Fsum} or L{Fsum2Tuple}, 1-primed.
270
242
  '''
271
- return Fsum()._facc_scalarf(_1primed(xs), up=False)
243
+ return Fsum()._facc_scalarf(_1primed(xs), origin=-1, up=False)
272
244
 
273
245
 
274
- def _2halfeven(s, r, p):
246
+ def _halfeven(s, r, p):
275
247
  '''(INTERNAL) Round half-even.
276
248
  '''
277
249
  if (p > 0 and r > 0) or \
@@ -302,19 +274,31 @@ def _isOK(unused):
302
274
 
303
275
 
304
276
  def _isOK_or_finite(x, _isfine=_isfinite):
305
- '''(INTERNAL) Is C{x} finite or is I{non-finite} OK?.
277
+ '''(INTERNAL) Is C{x} finite or is I{non-finite} OK?
306
278
  '''
307
279
  # assert _isfine in (_isOK, _isfinite)
308
- return _isfine(x)
280
+ return _isfine(x) # C{bool}
309
281
 
310
282
 
311
- def _ixError(X, xs, i, x, origin=0, which=None):
312
- '''(INTERNAL) Error for C{xs} or C{x}, item C{xs[i]}.
313
- '''
314
- t = _xsError(X, xs, i + origin, x)
315
- if which:
316
- t = _COMMASPACE_(unstr(which, _Cdot=Fsum), t)
317
- return _xError(X, t, txt=None)
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
318
302
 
319
303
 
320
304
  def _nfError(x, *args):
@@ -327,6 +311,13 @@ def _nfError(x, *args):
327
311
  raise E(t, txt=None)
328
312
 
329
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
+
330
321
  def nonfiniterrors(*raiser):
331
322
  '''Throw C{OverflowError} and C{ValueError} exceptions for or
332
323
  handle I{non-finite} C{float}s as C{inf}, C{INF}, C{NINF},
@@ -344,14 +335,8 @@ def nonfiniterrors(*raiser):
344
335
  d = Fsum._isfine
345
336
  if raiser and raiser[0] is not None:
346
337
  Fsum._isfine = {} if bool(raiser[0]) else Fsum._nonfinites_isfine_kwds[True]
347
- return _xkwds_get1(d, _isfine=_isfinite) is _isfinite
348
-
349
-
350
- def _NonfiniteError(x):
351
- '''(INTERNAL) Return the Error class for C{x}, I{non-finite}.
352
- '''
353
- return _OverflowError if isinf(x) else (
354
- _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
355
340
 
356
341
 
357
342
  def _1primed(xs): # in .fmath
@@ -377,7 +362,7 @@ def _psum(ps, **_isfine): # PYCHOK used!
377
362
  if s:
378
363
  ps[i:] = r, s
379
364
  if i > 0:
380
- s = _2halfeven(s, r, ps[i-1])
365
+ s = _halfeven(s, r, ps[i-1])
381
366
  break # return s
382
367
  s = r # PYCHOK no cover
383
368
  elif not _isfinite(s): # non-finite OK
@@ -404,14 +389,38 @@ def _Psum_(*ps, **name_f2product_nonfinites_RESIDUAL): # in .fmath
404
389
  return _Psum(ps, **name_f2product_nonfinites_RESIDUAL)
405
390
 
406
391
 
407
- 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):
408
417
  '''(INTERNAL) Return 2-tuple C{(other, r)} with C{other} as C{int},
409
- 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.
410
419
  '''
411
420
  if _isFsum_2Tuple(other):
412
421
  s, r = other._fint2
413
422
  if r:
414
- s, r = other._fprs2
423
+ s, r = other._nfprs2
415
424
  if r: # PYCHOK no cover
416
425
  s = other # L{Fsum} as-is
417
426
  else:
@@ -422,17 +431,6 @@ def _2scalar2(other):
422
431
  return s, r
423
432
 
424
433
 
425
- def _s_r(s, r):
426
- '''(INTERNAL) Return C{(s, r)}, I{ordered}.
427
- '''
428
- if r and _isfinite(s):
429
- if fabs(s) < fabs(r):
430
- s, r = r, (s or INT0)
431
- else:
432
- r = INT0
433
- return s, r
434
-
435
-
436
434
  def _strcomplex(s, *args):
437
435
  '''(INTERNAL) C{Complex} 2- or 3-arg C{pow} error as C{str}.
438
436
  '''
@@ -519,7 +517,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
519
517
  C{PYGEODESY_FSUM_NONFINITES} and C{PYGEODESY_FSUM_RESIDUAL}.
520
518
  '''
521
519
  _f2product = _sys_version_info2 > (3, 12) or bool(_F2PRODUCT)
522
- _isfine = {} # == _isfinite
520
+ _isfine = {} # == _isfinite, see nonfiniterrors()
523
521
  _n = 0
524
522
  # _ps = [] # partial sums
525
523
  # _ps_max = 0 # max(Fsum._ps_max, len(Fsum._ps)) # 41
@@ -560,14 +558,22 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
560
558
  @see: Methods L{Fsum.fadd_} and L{Fsum.fadd}.
561
559
  '''
562
560
  f = self._copy_2(self.__add__)
563
- return f._fadd(other, _add_op_)
561
+ return f._fadd(other)
564
562
 
565
563
  def __bool__(self): # PYCHOK Python 3+
566
564
  '''Return C{bool(B{self})}, C{True} iff C{residual} is zero.
567
565
  '''
568
- s, r = self._fprs2
566
+ s, r = self._nfprs2
569
567
  return bool(s or r) and s != -r # == self != 0
570
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
+
571
577
  def __ceil__(self): # PYCHOK not special in Python 2-
572
578
  '''Return this instance' C{math.ceil} as C{int} or C{float}.
573
579
 
@@ -609,7 +615,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
609
615
  '''Return C{(B{self} == B{other})} as C{bool} where B{C{other}}
610
616
  is C{scalar}, an other L{Fsum} or L{Fsum2Tuple}.
611
617
  '''
612
- return self._cmp_0(other, _eq_op_) == 0
618
+ return self._cmp_0(other, _fset_op_ + _fset_op_) == 0
613
619
 
614
620
  def __float__(self):
615
621
  '''Return this instance' current, precision running sum as C{float}.
@@ -646,7 +652,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
646
652
  def __ge__(self, other):
647
653
  '''Return C{(B{self} >= B{other})}, see C{__eq__}.
648
654
  '''
649
- return self._cmp_0(other, _ge_op_) >= 0
655
+ return self._cmp_0(other, _gt_op_ + _fset_op_) >= 0
650
656
 
651
657
  def __gt__(self, other):
652
658
  '''Return C{(B{self} > B{other})}, see C{__eq__}.
@@ -674,7 +680,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
674
680
  @see: Methods L{Fsum.fadd_} and L{Fsum.fadd}.
675
681
  '''
676
682
  try:
677
- return self._fadd(other, _iadd_op_)
683
+ return self._fadd(other, op=_iadd_op_)
678
684
  except TypeError:
679
685
  pass
680
686
  _xiterable(other)
@@ -834,7 +840,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
834
840
  def __le__(self, other):
835
841
  '''Return C{(B{self} <= B{other})}, see C{__eq__}.
836
842
  '''
837
- return self._cmp_0(other, _le_op_) <= 0
843
+ return self._cmp_0(other, _lt_op_ + _fset_op_) <= 0
838
844
 
839
845
  def __len__(self):
840
846
  '''Return the number of values accumulated (C{int}).
@@ -896,7 +902,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
896
902
  @see: Method L{Fsum.__iadd__}.
897
903
  '''
898
904
  f = self._copy_2r(other, self.__radd__)
899
- return f._fadd(self, _add_op_)
905
+ return f._fadd(self)
900
906
 
901
907
  def __rdivmod__(self, other):
902
908
  '''Return C{divmod(B{other}, B{self})} as 2-tuple
@@ -1030,9 +1036,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1030
1036
  '''
1031
1037
  n, r = self._fint2
1032
1038
  if r:
1033
- i, d = float(r).as_integer_ratio()
1034
- n *= d
1035
- n += i
1039
+ i, d = float(r).as_integer_ratio()
1040
+ n, d = _n_d2(n * d + i, d)
1036
1041
  else: # PYCHOK no cover
1037
1042
  d = 1
1038
1043
  return n, d
@@ -1042,7 +1047,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1042
1047
  '''Get this instance I{as-is} (L{Fsum} with C{non-zero residual},
1043
1048
  C{scalar} or I{non-finite}).
1044
1049
  '''
1045
- s, r = self._fprs2
1050
+ s, r = self._nfprs2
1046
1051
  return self if r else s
1047
1052
 
1048
1053
  @property_RO
@@ -1089,6 +1094,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1089
1094
  f._n = 1
1090
1095
  # assert f._f2product == self._f2product
1091
1096
  # assert f._Fsum is f
1097
+ # assert f._isfine is self._isfine
1098
+ # assert f._RESIDUAL is self._RESIDUAL
1092
1099
  return f
1093
1100
 
1094
1101
  def _copy_2(self, which, name=NN):
@@ -1101,6 +1108,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1101
1108
  # assert f._n == self._n
1102
1109
  # assert f._f2product == self._f2product
1103
1110
  # assert f._Fsum is f
1111
+ # assert f._isfine is self._isfine
1112
+ # assert f._RESIDUAL is self._RESIDUAL
1104
1113
  return f
1105
1114
 
1106
1115
  def _copy_2r(self, other, which):
@@ -1130,15 +1139,17 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1130
1139
  '''(INTERNAL) Format the caught exception C{X}.
1131
1140
  '''
1132
1141
  E, t = _xError2(X)
1133
- u = unstr(self.named3, *xs[:3], _ELLIPSIS=len(xs) > 3, **kwds)
1142
+ u = unstr(self.named3, *xs, _ELLIPSIS=4, **kwds)
1134
1143
  return E(u, txt=t, cause=X)
1135
1144
 
1136
- def _facc(self, xs, up=True, **origin_X_x):
1137
- '''(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.
1138
1147
  '''
1139
1148
  if xs:
1140
- kwds = _xkwds(self._isfine, **origin_X_x)
1141
- fs = _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
1142
1153
  ps = self._ps
1143
1154
  ps[:] = self._ps_acc(list(ps), fs, up=up)
1144
1155
  return self
@@ -1147,8 +1158,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1147
1158
  '''(INTERNAL) Accumulate 0, 1 or more C{xs}, all positional
1148
1159
  arguments in the caller of this method.
1149
1160
  '''
1150
- return self._facc(xs, origin=1, **up) if len(xs) != 1 else \
1151
- 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?
1152
1163
 
1153
1164
  def _facc_neg(self, xs, **up_origin):
1154
1165
  '''(INTERNAL) Accumulate more C{xs}, negated.
@@ -1197,7 +1208,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1197
1208
  f *= _pow(x, r, power, op, **raiser_RESIDUAL)
1198
1209
  return f
1199
1210
 
1200
- f = self._facc(xs, origin=1, _X=_P, _x=_p)
1211
+ f = self._facc(xs, _X=_P, _x=_p) # origin=1?
1201
1212
  else:
1202
1213
  f = self._facc_scalar_(float(len(xs))) # x**0 == 1
1203
1214
  return f
@@ -1206,7 +1217,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1206
1217
  '''(INTERNAL) Accumulate all C{xs}, each C{scalar}.
1207
1218
  '''
1208
1219
  if xs:
1209
- _ = self._ps_acc(self._ps, xs, **up)
1220
+ ps = self._ps
1221
+ ps[:] = self._ps_acc(list(ps), xs, **up)
1210
1222
  return self
1211
1223
 
1212
1224
  def _facc_scalar_(self, *xs, **up):
@@ -1214,16 +1226,14 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1214
1226
  '''
1215
1227
  return self._facc_scalar(xs, **up)
1216
1228
 
1217
- def _facc_scalarf(self, xs, **origin_which):
1229
+ def _facc_scalarf(self, xs, up=True, **origin_which):
1218
1230
  '''(INTERNAL) Accumulate all C{xs}, each C{scalar}, an L{Fsum} or
1219
1231
  L{Fsum2Tuple}, like function C{_xsum}.
1220
1232
  '''
1221
- i_x = [0, xs]
1222
- try:
1223
- nf = self.nonfinitesOK
1224
- return self._facc_scalar(_xs(xs, i_x, nf))
1225
- except (OverflowError, TypeError, ValueError) as X:
1226
- raise _ixError(X, xs, *i_x, **origin_which)
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)
1227
1237
 
1228
1238
  # def _facc_up(self, up=True):
1229
1239
  # '''(INTERNAL) Update the C{partials}, by removing
@@ -1242,8 +1252,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1242
1252
  def fadd(self, xs=()):
1243
1253
  '''Add an iterable's items to this instance.
1244
1254
 
1245
- @arg xs: Iterable of items to add (each C{scalar}
1246
- 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}).
1247
1257
 
1248
1258
  @return: This instance (L{Fsum}).
1249
1259
 
@@ -1265,26 +1275,20 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1265
1275
  def fadd_(self, *xs):
1266
1276
  '''Add all positional items to this instance.
1267
1277
 
1268
- @arg xs: Values to add (each C{scalar} or an L{Fsum}
1269
- or L{Fsum2Tuple} instance), all positional.
1278
+ @arg xs: Values to add (each C{scalar}, an L{Fsum}
1279
+ or L{Fsum2Tuple}), all positional.
1270
1280
 
1271
1281
  @see: Method L{Fsum.fadd} for further details.
1272
1282
  '''
1273
1283
  return self._facc_args(xs)
1274
1284
 
1275
- def _fadd(self, other, op, **up): # in .fmath.Fhorner
1285
+ def _fadd(self, other, op=_add_op_, **up):
1276
1286
  '''(INTERNAL) Apply C{B{self} += B{other}}.
1277
1287
  '''
1278
1288
  if _isFsum_2Tuple(other):
1279
- if self._ps:
1280
- self._facc_scalar(other._ps, **up)
1281
- else:
1282
- self._fset(other, op=op, **up)
1289
+ self._facc_scalar(other._ps, **up)
1283
1290
  elif self._scalar(other, op):
1284
- if self._ps:
1285
- self._facc_scalar_(other, **up)
1286
- else:
1287
- self._fset(other, op=op, **up)
1291
+ self._facc_scalar_(other, **up)
1288
1292
  return self
1289
1293
 
1290
1294
  fcopy = copy # for backward compatibility
@@ -1310,25 +1314,27 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1310
1314
  # raise self._Error(op, other, _AssertionError, txt__=signOf)
1311
1315
  return DivMod2Tuple(q, self) # q is C{int} in Python 3+, but C{float} in Python 2-
1312
1316
 
1313
- def _fhorner(self, x, cs, op, incx=True): # in .fmath
1317
+ def _fhorner(self, x, cs, where, incx=True): # in .fmath
1314
1318
  '''(INTERNAL) Add an L{Fhorner} evaluation of polynomial
1315
1319
  C{sum(cs[i] * B{x}**i for i=0..len(cs)-1) if B{incx}
1316
1320
  else sum(... i=len(cs)-1..0)}.
1317
1321
  '''
1318
- if _xiterablen(cs):
1319
- H = self._Fsum_as(name__=self._fhorner)
1320
- if _isFsum_2Tuple(x):
1321
- _mul = H._mul_Fsum
1322
- else:
1323
- _mul = H._mul_scalar
1324
- x = _2float(x=x, **self._isfine)
1325
- 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:
1326
1329
  for c in (reversed(cs) if incx else cs):
1327
- H._fset_ps(_mul(x, op))
1328
- H._fadd(c, op, up=False)
1330
+ H._fset(_m(x, _mul_op_), up=False)
1331
+ H._fadd(c, up=False)
1329
1332
  else: # x == 0
1330
- H = cs[0] if cs else _0_0
1331
- 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)
1332
1338
  return self
1333
1339
 
1334
1340
  def _finite(self, other, op=None):
@@ -1380,36 +1386,28 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1380
1386
  def _fint2(self): # see ._fset
1381
1387
  '''(INTERNAL) Get 2-tuple (C{int}, I{integer} residual).
1382
1388
  '''
1383
- s, _ = self._fprs2
1384
- try:
1389
+ s, r = self._nfprs2
1390
+ if _isfinite(s):
1385
1391
  i = int(s)
1386
1392
  r = (self._ps_1sum(i) if len(self._ps) > 1 else
1387
1393
  float(s - i)) or INT0
1388
- except (OverflowError, ValueError) as X:
1389
- r = _NONFINITEr # INF, NAN, NINF
1390
- i = self._fintX(X, sum(self._ps))
1394
+ else: # INF, NAN, NINF
1395
+ i = float(s)
1396
+ # r = _NONFINITEr
1391
1397
  return i, r # Fsum2Tuple?
1392
1398
 
1393
1399
  @_fint2.setter_ # PYCHOK setter_UNDERscore!
1394
1400
  def _fint2(self, s): # in _fset
1395
1401
  '''(INTERNAL) Replace the C{_fint2} value.
1396
1402
  '''
1397
- try:
1403
+ if _isfinite(s):
1398
1404
  i = int(s)
1399
1405
  r = (s - i) or INT0
1400
- except (OverflowError, ValueError) as X:
1401
- r = _NONFINITEr # INF, NAN, NINF
1402
- i = self._fintX(X, float(s))
1406
+ else: # INF, NAN, NINF
1407
+ i = float(s)
1408
+ r = _NONFINITEr
1403
1409
  return i, r # like _fint2.getter
1404
1410
 
1405
- def _fintX(self, X, i): # PYCHOK X
1406
- '''(INTERNAL) Handle I{non-finite} C{int}.
1407
- '''
1408
- # "cannot convert float infinity to integer"
1409
- return i # ignore such Overflow-/ValueErrors
1410
- # op = int.__name__
1411
- # return self._nonfiniteX(X, op, i)
1412
-
1413
1411
  @deprecated_property_RO
1414
1412
  def float_int(self): # PYCHOK no cover
1415
1413
  '''DEPRECATED, use method C{Fsum.int_float}.'''
@@ -1456,16 +1454,19 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1456
1454
  if r:
1457
1455
  f = self._f2mul(self.fma, other1, **nonfinites)
1458
1456
  f += other2
1459
- else:
1457
+ elif _residue(other1) or _residue(other2):
1460
1458
  fs = _2split3s(_fs(op, other1))
1461
1459
  fs = _2products(s, fs, *_fs(op, other2))
1462
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)
1463
1464
  except TypeError as X:
1464
1465
  raise self._ErrorX(X, op, (other1, other2))
1465
1466
  except (OverflowError, ValueError) as X: # from math.fma
1466
- f = self._mul_reduce(op, s, other1) # INF, NAN, NINF
1467
- f = sum(_fs(op, f, other2))
1468
- f = self._nonfiniteX(X, op, f, **nonfinites)
1467
+ f = self._mul_reduce(s, other1) # INF, NAN, NINF
1468
+ f += sum(_fs(op, other2))
1469
+ f = self._nonfiniteX(X, op, f, **nonfinites)
1469
1470
  return self._fset(f)
1470
1471
 
1471
1472
  fmul = __imul__
@@ -1524,7 +1525,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1524
1525
  except TypeError as X:
1525
1526
  raise self._ErrorX(X, op, other)
1526
1527
  except (OverflowError, ValueError) as X:
1527
- r = self._mul_reduce(op, sum(ps), other) # INF, NAN, NINF
1528
+ r = self._mul_reduce(sum(ps), other) # INF, NAN, NINF
1528
1529
  r = self._nonfiniteX(X, op, r, **nonfinites_raiser)
1529
1530
  f._fset(r)
1530
1531
  return f
@@ -1557,7 +1558,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1557
1558
  elif self.is_integer():
1558
1559
  # return an exact C{int} for C{int}**C{int}
1559
1560
  i, _ = self._fint2 # assert _ == 0
1560
- x, r = _2scalar2(other) # C{int}, C{float} or other
1561
+ x, r = _2s_r(other) # C{int}, C{float} or other
1561
1562
  f = self._Fsum_as(i)._pow_Fsum(other, op, **raiser_RESIDUAL) if r else \
1562
1563
  self._pow_2_3(i, x, other, op, **raiser_RESIDUAL)
1563
1564
  else: # mod[0] is None, power(self, other)
@@ -1631,10 +1632,11 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1631
1632
  s = ps[0]
1632
1633
  r = INT0 if _isfinite(s) else _NONFINITEr
1633
1634
  else: # len(ps) == 0
1634
- s, r = _0_0, INT0
1635
+ s = _0_0
1636
+ r = INT0 if _isfinite(s) else _NONFINITEr
1635
1637
  ps[:] = s,
1636
1638
  except (OverflowError, ValueError) as X:
1637
- op = sum.__name__ # INF, NAN, NINF
1639
+ op = _fset_op_ # INF, NAN, NINF
1638
1640
  ps[:] = sum(ps), # collapse ps
1639
1641
  s = self._nonfiniteX(X, op, ps[0])
1640
1642
  r = _NONFINITEr
@@ -1658,8 +1660,9 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1658
1660
 
1659
1661
  @see: Method L{Fsum.fadd} for further details.
1660
1662
  '''
1661
- f = self._Fsum_as(*xs)
1662
- return self._fset(f, up=False, op=_fset_op_)
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_)
1663
1666
 
1664
1667
  def _fset(self, other, n=0, up=True, **op):
1665
1668
  '''(INTERNAL) Overwrite this instance with an other or a C{scalar}.
@@ -1667,6 +1670,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1667
1670
  if other is self:
1668
1671
  pass # from ._fmul, ._ftruediv and ._pow_0_1
1669
1672
  elif _isFsum_2Tuple(other):
1673
+ if op: # and not self.nonfinitesOK:
1674
+ self._finite(other._fprs, **op)
1670
1675
  self._ps[:] = other._ps
1671
1676
  self._n = n or other._n
1672
1677
  if up: # use or zap the C{Property_RO} values
@@ -1689,11 +1694,6 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1689
1694
  raise self._Error(op, other, _TypeError)
1690
1695
  return self
1691
1696
 
1692
- def _fset_ps(self, other): # in .fmath._Fsum__init__
1693
- '''(INTERNAL) Set partials from a known C{other}.
1694
- '''
1695
- return self._fset(other, up=False)
1696
-
1697
1697
  def fsub(self, xs=()):
1698
1698
  '''Subtract an iterable's items from this instance.
1699
1699
 
@@ -1706,8 +1706,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1706
1706
 
1707
1707
  @see: Method L{Fsum.fadd_} for further details.
1708
1708
  '''
1709
- return self._facc_neg(xs, origin=1) if len(xs) != 1 else \
1710
- 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?
1711
1711
 
1712
1712
  def _fsub(self, other, op):
1713
1713
  '''(INTERNAL) Apply C{B{self} -= B{other}}.
@@ -1725,8 +1725,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1725
1725
  '''Add an iterable's items, summate and return the current
1726
1726
  precision running sum.
1727
1727
 
1728
- @arg xs: Iterable of items to add (each item C{scalar}
1729
- 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}).
1730
1730
 
1731
1731
  @return: Precision running sum (C{float} or C{int}).
1732
1732
 
@@ -1740,8 +1740,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1740
1740
  '''Add any positional items, summate and return the current
1741
1741
  precision running sum.
1742
1742
 
1743
- @arg xs: Items to add (each C{scalar} or an L{Fsum}
1744
- or L{Fsum2Tuple} instance), all positional.
1743
+ @arg xs: Items to add (each C{scalar}, an L{Fsum} or
1744
+ L{Fsum2Tuple}), all positional.
1745
1745
 
1746
1746
  @return: Precision running sum (C{float} or C{int}).
1747
1747
 
@@ -1765,10 +1765,10 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1765
1765
 
1766
1766
  @return: Precision running sum (L{Fsum2Tuple}).
1767
1767
  '''
1768
- return Fsum2Tuple(self._facc_args(xs)._fprs2, **name)
1768
+ return Fsum2Tuple(self._facc_args(xs)._nfprs2, **name)
1769
1769
 
1770
1770
  @property_RO
1771
- def _Fsum(self): # like L{Fsum2Tuple._Fsum}, for C{_2floats}, .fstats
1771
+ def _Fsum(self): # like L{Fsum2Tuple._Fsum}, in .fstats
1772
1772
  return self # NOT @Property_RO, see .copy and ._copy_2
1773
1773
 
1774
1774
  def _Fsum_as(self, *xs, **name_f2product_nonfinites_RESIDUAL):
@@ -1782,17 +1782,17 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1782
1782
  RESIDUAL =self.RESIDUAL())
1783
1783
  if name_f2product_nonfinites_RESIDUAL: # overwrites
1784
1784
  kwds.update(name_f2product_nonfinites_RESIDUAL)
1785
- F = Fsum(**kwds)
1786
- # assert all(v == self.__dict__[n] for n, v in F.__dict__.items())
1787
- return F._fset(xs[0], op=_fset_op_) if len(xs) == 1 else (
1788
- F._facc(xs, up=False) if xs else F)
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)
1789
1789
 
1790
1790
  def fsum2(self, xs=(), **name):
1791
1791
  '''Add an iterable's items, summate and return the
1792
1792
  current precision running sum I{and} the C{residual}.
1793
1793
 
1794
- @arg xs: Iterable of items to add (each item C{scalar}
1795
- 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}).
1796
1796
  @kwarg name: Optional C{B{name}=NN} (C{str}).
1797
1797
 
1798
1798
  @return: L{Fsum2Tuple}C{(fsum, residual)} with C{fsum} the
@@ -1810,8 +1810,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1810
1810
  '''Add any positional items, summate and return the current
1811
1811
  precision running sum and the I{differential}.
1812
1812
 
1813
- @arg xs: Values to add (each C{scalar} or an L{Fsum} or
1814
- L{Fsum2Tuple} instance), all positional.
1813
+ @arg xs: Values to add (each C{scalar}, an L{Fsum} or
1814
+ L{Fsum2Tuple}), all positional.
1815
1815
 
1816
1816
  @return: 2Tuple C{(fsum, delta)} with the current, precision
1817
1817
  running C{fsum} like method L{Fsum.fsum} and C{delta},
@@ -1838,19 +1838,19 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1838
1838
  '''Like method L{Fsum.fsum_} iff I{all} C{B{xs}}, each I{known to be}
1839
1839
  C{scalar}, an L{Fsum} or L{Fsum2Tuple}.
1840
1840
  '''
1841
- return self._facc_scalarf(xs, origin=1, which=self.fsumf_)._fprs
1841
+ return self._facc_scalarf(xs, which=self.fsumf_)._fprs # origin=1?
1842
1842
 
1843
1843
  def Fsumf_(self, *xs):
1844
1844
  '''Like method L{Fsum.Fsum_} iff I{all} C{B{xs}}, each I{known to be}
1845
1845
  C{scalar}, an L{Fsum} or L{Fsum2Tuple}.
1846
1846
  '''
1847
- return self._facc_scalarf(xs, origin=1, which=self.Fsumf_)._copy_2(self.Fsumf_)
1847
+ return self._facc_scalarf(xs, which=self.Fsumf_)._copy_2(self.Fsumf_) # origin=1?
1848
1848
 
1849
1849
  def fsum2f_(self, *xs):
1850
1850
  '''Like method L{Fsum.fsum2_} iff I{all} C{B{xs}}, each I{known to be}
1851
1851
  C{scalar}, an L{Fsum} or L{Fsum2Tuple}.
1852
1852
  '''
1853
- return self._fsum2(xs, self._facc_scalarf, origin=1, which=self.fsum2f_)
1853
+ return self._fsum2(xs, self._facc_scalarf, which=self.fsum2f_) # origin=1?
1854
1854
 
1855
1855
  # ftruediv = __itruediv__ # for naming consistency?
1856
1856
 
@@ -1891,8 +1891,9 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1891
1891
  L{ResidualError}s (C{bool}) and C{B{RESIDUAL}=scalar}
1892
1892
  to override the current L{RESIDUAL<Fsum.RESIDUAL>}.
1893
1893
 
1894
- @return: This C{int} sum if this instance C{is_integer}, otherwise
1895
- the C{float} sum if the residual is zero or not significant.
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.
1896
1897
 
1897
1898
  @raise ResidualError: Non-zero, significant residual or invalid
1898
1899
  B{C{RESIDUAL}}.
@@ -1951,48 +1952,52 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1951
1952
  return _sum is _fsum # _fsum.__module__ is fabs.__module__
1952
1953
 
1953
1954
  def is_scalar(self, **raiser_RESIDUAL):
1954
- '''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
1955
1956
  a residual I{ratio} not exceeding the RESIDUAL threshold?
1956
1957
 
1957
1958
  @kwarg raiser_RESIDUAL: Use C{B{raiser}=False} to ignore
1958
1959
  L{ResidualError}s (C{bool}) and C{B{RESIDUAL}=scalar}
1959
1960
  to override the current L{RESIDUAL<Fsum.RESIDUAL>}.
1960
1961
 
1961
- @return: C{True} if this instance' non-zero residual C{ratio} exceeds
1962
- 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}).
1963
1965
 
1964
1966
  @raise ResidualError: Non-zero, significant residual or invalid
1965
1967
  B{C{RESIDUAL}}.
1966
1968
 
1967
- @see: Method L{Fsum.RESIDUAL}, L{Fsum.is_integer} and property
1969
+ @see: Methods L{Fsum.RESIDUAL} and L{Fsum.is_integer} and property
1968
1970
  L{Fsum.as_iscalar}.
1969
1971
  '''
1970
1972
  s, r = self._fprs2
1971
1973
  return False if r and self._raiser(r, s, **raiser_RESIDUAL) else True
1972
1974
 
1973
- def _mul_Fsum(self, other, op=_mul_op_): # in .fmath.Fhorner
1975
+ def _mul_Fsum(self, other, op):
1974
1976
  '''(INTERNAL) Return C{B{self} * B{other}} as L{Fsum} or C{0}.
1975
1977
  '''
1976
1978
  # assert _isFsum_2Tuple(other)
1977
1979
  if self._ps and other._ps:
1978
- 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)
1979
1984
  else:
1980
1985
  f = _0_0
1981
1986
  return f
1982
1987
 
1983
- def _mul_reduce(self, op, start, *others):
1984
- '''(INTERNAL) Like fmath.freduce(_operator.mul, ...)
1985
- for I{non-finite} C{start} and/or C{others}.
1988
+ def _mul_reduce(self, *others):
1989
+ '''(INTERNAL) Like fmath.fprod for I{non-finite} C{other}s.
1986
1990
  '''
1987
- for p in self._ps_other(op, *others):
1988
- start *= p
1989
- 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
1990
1995
 
1991
- def _mul_scalar(self, factor, op): # in .fmath.Fhorner
1996
+ def _mul_scalar(self, factor, op):
1992
1997
  '''(INTERNAL) Return C{B{self} * scalar B{factor}} as L{Fsum}, C{0.0} or C{self}.
1993
1998
  '''
1994
1999
  # assert isscalar(factor)
1995
- if self._ps and self._finite(factor, op):
2000
+ if self._ps and self._finite(factor, op=op):
1996
2001
  f = self if factor == _1_0 else (
1997
2002
  self._neg if factor == _N_1_0 else
1998
2003
  self._ps_mul(op, factor).as_iscalar)
@@ -2011,6 +2016,16 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2011
2016
  '''
2012
2017
  return _Psum(self._ps_neg) if self._ps else NEG0
2013
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
+
2014
2029
  def nonfinites(self, *OK):
2015
2030
  '''Handle I{non-finite} C{float}s as C{inf}, C{INF}, C{NINF}, C{nan}
2016
2031
  and C{NAN} for this L{Fsum} or throw C{OverflowError} respectively
@@ -2048,10 +2063,10 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2048
2063
  def nonfinitesOK(self):
2049
2064
  '''Are I{non-finites} C{OK} for this L{Fsum} or by default? (C{bool}).
2050
2065
  '''
2051
- nf = self.nonfinites()
2052
- if nf is None:
2053
- nf = not nonfiniterrors()
2054
- return nf
2066
+ # nf = self.nonfinites()
2067
+ # if nf is None:
2068
+ # nf = not nonfiniterrors()
2069
+ return _isOK_or_finite(INF, **self._isfine)
2055
2070
 
2056
2071
  def _nonfiniteX(self, X, op, f, nonfinites=None, raiser=None):
2057
2072
  '''(INTERNAL) Handle a I{non-finite} exception.
@@ -2122,7 +2137,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2122
2137
  if _isFsum_2Tuple(other):
2123
2138
  f = self._pow_Fsum(other, op, **raiser_RESIDUAL)
2124
2139
  elif self._scalar(other, op):
2125
- x = self._finite(other, op)
2140
+ x = self._finite(other, op=op)
2126
2141
  f = self._pow_scalar(x, other, op, **raiser_RESIDUAL)
2127
2142
  else:
2128
2143
  f = self._pow_0_1(0, other)
@@ -2149,7 +2164,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2149
2164
  return s
2150
2165
 
2151
2166
  b = _s(*(b._fprs2 if m is None else b._fint2))
2152
- x = _s(*_2scalar2(x))
2167
+ x = _s(*_2s_r(x))
2153
2168
 
2154
2169
  try:
2155
2170
  # 0**INF == 0.0, 1**INF == 1.0, -1**2.3 == -(1**2.3)
@@ -2157,7 +2172,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2157
2172
  if iscomplex(s):
2158
2173
  # neg**frac == complex in Python 3+, but ValueError in 2-
2159
2174
  raise ValueError(_strcomplex(s, b, x, *mod))
2160
- return self._finite(s)
2175
+ _ = _2finite(s, **self._isfine) # ignore float
2176
+ return s
2161
2177
  except Exception as X:
2162
2178
  raise self._ErrorX(X, op, other, *mod)
2163
2179
 
@@ -2258,13 +2274,12 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2258
2274
  n += 1
2259
2275
  if n:
2260
2276
  self._n += n
2261
- # if _fi: # collapse ps if non-finite
2262
- # x = sum(ps)
2263
- # if not _isfinite(x):
2264
- # ps[:] = x,
2265
2277
  # Fsum._ps_max = max(Fsum._ps_max, len(ps))
2266
2278
  if up:
2267
2279
  self._update()
2280
+ # x = sum(ps)
2281
+ # if not _isOK_or_finite(x, **fi):
2282
+ # ps[:] = x, # collapse ps
2268
2283
  return ps
2269
2284
 
2270
2285
  def _ps_mul(self, op, *factors):
@@ -2285,7 +2300,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2285
2300
 
2286
2301
  for p in ps:
2287
2302
  for f in _pfs(p, fs):
2288
- yield f if _isfine(f) else self._finite(f, op)
2303
+ yield f if _isfine(f) else _nfError(f)
2289
2304
 
2290
2305
  fs = _psfs(self._ps, factors, **self._isfine)
2291
2306
  f = _Psum(self._ps_acc([], fs, up=False), name=op)
@@ -2298,15 +2313,14 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2298
2313
  for p in self._ps:
2299
2314
  yield -p
2300
2315
 
2301
- def _ps_other(self, op, *others):
2302
- '''(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.
2303
2318
  '''
2304
- for other in others:
2305
- if _isFsum_2Tuple(other):
2306
- for p in other._ps:
2307
- yield p
2308
- else:
2309
- 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)
2310
2324
 
2311
2325
  def _ps_1sum(self, *less):
2312
2326
  '''(INTERNAL) Return the partials sum, 1-primed C{less} some scalars.
@@ -2434,7 +2448,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2434
2448
 
2435
2449
  @return: The sign (C{int}, -1, 0 or +1).
2436
2450
  '''
2437
- s, r = self._fprs2
2451
+ s, r = self._nfprs2
2438
2452
  r = (-r) if res else 0
2439
2453
  return _signOf(s, r)
2440
2454
 
@@ -2462,7 +2476,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2462
2476
  if lenc:
2463
2477
  p = Fmt.SQUARE(p, len(self))
2464
2478
  n = _enquote(self.name, white=_UNDER_)
2465
- t = self._fprs2.toStr(**prec_sep_fmt)
2479
+ t = self._nfprs2.toStr(**prec_sep_fmt)
2466
2480
  return NN(p, _SPACE_, n, t)
2467
2481
 
2468
2482
  def _truediv(self, other, op, **raiser_RESIDUAL):
@@ -2697,7 +2711,7 @@ def fsum_(*xs, **nonfinites):
2697
2711
 
2698
2712
  @see: Function L{fsum<fsums.fsum>} for further details.
2699
2713
  '''
2700
- 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?
2701
2715
 
2702
2716
 
2703
2717
  def fsumf_(*xs):
@@ -2708,7 +2722,7 @@ def fsumf_(*xs):
2708
2722
 
2709
2723
  @see: Function L{fsum_<fsums.fsum_>} for further details.
2710
2724
  '''
2711
- 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?
2712
2726
 
2713
2727
 
2714
2728
  def fsum1(xs, **nonfinites):
@@ -2730,7 +2744,7 @@ def fsum1_(*xs, **nonfinites):
2730
2744
 
2731
2745
  @see: Function L{fsum_<fsums.fsum_>} for further details.
2732
2746
  '''
2733
- 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?
2734
2748
 
2735
2749
 
2736
2750
  def fsum1f_(*xs):
@@ -2742,34 +2756,48 @@ def fsum1f_(*xs):
2742
2756
  return _xsum(fsum1f_, xs, nonfinites=True, primed=1) if xs else _0_0
2743
2757
 
2744
2758
 
2745
- def _xs(xs, i_x, nfOK): # in Fsum._facc_scalarf
2746
- '''(INTERNAL) Yield all C{xs} as C{scalar}.
2747
- '''
2748
- _x = _passarg if nfOK else _2finite
2749
- for i, x in enumerate(xs):
2750
- i_x[:] = i, x
2751
- if _isFsum_2Tuple(x):
2752
- for p in map(_x, x._ps):
2753
- yield p
2754
- else:
2755
- yield _x(x)
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
2756
2764
 
2757
2765
 
2758
- def _xsum(which, xs, nonfinites=None, origin=0, primed=0, **floats):
2759
- '''(INTERNAL) Precision summation of C{xs} with conditions.
2766
+ def _X_ps(X): # default C{_X} handler
2767
+ return X._ps # lambda X: X._ps
2768
+
2769
+
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.
2760
2773
  '''
2761
- i_x = [0, xs]
2774
+ i, x = 0, xs
2762
2775
  try:
2763
- if floats: # for backward compatibility
2764
- nonfinites = _xkwds_get1(floats, floats=nonfinites)
2765
- elif nonfinites is None:
2766
- nonfinites = not nonfiniterrors()
2767
- fs = _xs(xs, i_x, nonfinites)
2768
- return _fsum(_1primed(fs) if primed else fs)
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
+
2769
2784
  except (OverflowError, TypeError, ValueError) as X:
2770
- origin -= 1 if primed else 0
2771
- i_x += [origin, which]
2772
- raise _ixError(X, xs, *i_x)
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)
2789
+ raise _xError(X, t, txt=None)
2790
+
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)
2773
2801
 
2774
2802
 
2775
2803
  # delete all decorators, etc.