pygeodesy 24.9.24__py2.py3-none-any.whl → 24.9.29__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pygeodesy/fsums.py CHANGED
@@ -47,7 +47,8 @@ from pygeodesy.constants import INF, INT0, MANT_DIG, NEG0, NINF, _0_0, \
47
47
  Float, Int
48
48
  from pygeodesy.errors import _AssertionError, _OverflowError, _TypeError, \
49
49
  _ValueError, _xError, _xError2, _xkwds_get, \
50
- _xkwds, _xkwds_get1, _xkwds_not, _xkwds_pop
50
+ _xkwds, _xkwds_get1, _xkwds_not, _xkwds_pop, \
51
+ _xsError
51
52
  from pygeodesy.internals import _enquote, _passarg
52
53
  from pygeodesy.interns import NN, _arg_, _COMMASPACE_, _DOT_, _from_, \
53
54
  _not_finite_, _SPACE_, _std_, _UNDER_
@@ -64,7 +65,7 @@ from math import fabs, isinf, isnan, \
64
65
  ceil as _ceil, floor as _floor # PYCHOK used! .ltp
65
66
 
66
67
  __all__ = _ALL_LAZY.fsums
67
- __version__ = '24.09.25'
68
+ __version__ = '24.09.29'
68
69
 
69
70
  from pygeodesy.interns import (
70
71
  _PLUS_ as _add_op_, # in .auxilats.auxAngle
@@ -86,12 +87,12 @@ _iadd_op_ = _add_op_ + _fset_op_ # in .auxilats.auxAngle, .fstats
86
87
  _integer_ = 'integer'
87
88
  _isub_op_ = _sub_op_ + _fset_op_ # in .auxilats.auxAngle
88
89
  _le_op_ = _lt_op_ + _fset_op_
89
- _NONFINITES = _getenv('PYGEODESY_FSUM_NONFINITES', NN) == _std_
90
+ _NONFINITEr = _0_0
91
+ _NONFINITES = _getenv('PYGEODESY_FSUM_NONFINITES', NN)
90
92
  _non_zero_ = 'non-zero'
91
93
  _pow_op_ = _mul_op_ * 2 # _DSTAR_
92
94
  _RESIDUAL_0_0 = _getenv('PYGEODESY_FSUM_RESIDUAL', _0_0)
93
95
  _significant_ = 'significant'
94
- _2split3s = _passarg
95
96
  _threshold_ = 'threshold'
96
97
 
97
98
 
@@ -102,15 +103,15 @@ def _2finite(x): # in .fstats
102
103
  else _nfError(x))
103
104
 
104
105
 
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.
106
+ def _2float(index=None, _isfine=_isfinite, **name_x): # in .fmath, .fstats
107
+ '''(INTERNAL) Raise C{TypeError} or C{Overflow-/ValueError} if not finite.
107
108
  '''
108
- n, v = name_value.popitem() # _xkwds_item2(name_value)
109
+ n, x = name_x.popitem() # _xkwds_item2(name_x)
109
110
  try:
110
- f = float(v)
111
- return f if _isfine(f) else _nfError(f)
111
+ f = float(x)
112
+ return f if _isfine(f) else _nfError(x)
112
113
  except Exception as X:
113
- raise _xError(X, Fmt.INDEX(n, index), v)
114
+ raise _xError(X, Fmt.INDEX(n, index), x)
114
115
 
115
116
 
116
117
  def _X_ps(X): # for _2floats only
@@ -122,7 +123,7 @@ def _2floats(xs, origin=0, _X=_X_ps, _x=float, _isfine=_isfinite):
122
123
  '''
123
124
  try:
124
125
  i, x = origin, xs
125
- _FsT = _Fsum_Fsum2Tuple_types
126
+ _FsT = _Fsum_2Tuple_types
126
127
  for x in _xiterable(xs):
127
128
  if isinstance(x, _FsT):
128
129
  for p in _X(x._Fsum):
@@ -135,32 +136,28 @@ def _2floats(xs, origin=0, _X=_X_ps, _x=float, _isfine=_isfinite):
135
136
  raise _xsError(X, xs, i, x)
136
137
 
137
138
 
138
- try: # MCCABE 17
139
+ try: # MCCABE 26
139
140
  from math import fma as _fma
140
- except ImportError: # Python 3.12-
141
141
 
142
- if _F2PRODUCT == _std_:
143
- _2FACTOR = pow(2, (MANT_DIG + 1) // 2) + 1
142
+ def _2products(x, ys, *zs):
143
+ # yield(x * y for y in ys) + yield(z in zs)
144
+ # TwoProductFMA U{Algorithm 3.5
145
+ # <https://www.TUHH.De/ti3/paper/rump/OgRuOi05.pdf>}
146
+ for y in ys:
147
+ f = x * y
148
+ yield f
149
+ yield _fma(x, y, -f)
150
+ for z in zs:
151
+ yield z
144
152
 
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)
153
+ # _2split3 = \
154
+ _2split3s = _passarg # in Fsum.is_math_fma
151
155
 
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
156
+ except ImportError: # PYCHOK DSPACE! Python 3.12-
159
157
 
160
- def _2split3s(xs): # overwrites
161
- return tuple(map(_2split3, xs))
158
+ if _F2PRODUCT and _F2PRODUCT != _std_:
159
+ # back to PyGeodesy 24.09.09, with _fmaX
162
160
 
163
- else:
164
161
  def _fma(*a_b_c): # PYCHOK no cover
165
162
  # mimick C{math.fma} from Python 3.13+,
166
163
  # the same accuracy, but ~14x slower
@@ -179,51 +176,68 @@ except ImportError: # Python 3.12-
179
176
  return x.as_integer_ratio()
180
177
  except (AttributeError, OverflowError, TypeError, ValueError):
181
178
  return (x if isint(x) else float(x)), 1
179
+ else:
180
+
181
+ def _fma(a, b, c): # PYCHOK redef
182
+ # mimick C{math.fma} from Python 3.13+,
183
+ # the same accuracy, but ~13x slower
184
+ b3s = _2split3(b), # 1-tuple of 3-tuple
185
+ r = _fsum(_2products(a, b3s, c))
186
+ return r if _isfinite(r) else _fmaX(r, a, b, c)
187
+
188
+ _2n_d = None # redef
182
189
 
183
190
  def _fmaX(r, *a_b_c): # like Python 3.13+ I{Modules/mathmodule.c}:
184
191
  # raise a ValueError for a NAN result from non-NAN C{a_b_c}s or
185
192
  # OverflowError for a non-NAN result from all finite C{a_b_c}s.
186
193
  if isnan(r):
187
- def _is(x):
194
+ def _x(x):
188
195
  return not isnan(x)
189
196
  else:
190
- _is = _isfinite
191
- if all(map(_is, a_b_c)):
197
+ _x = _isfinite
198
+ if all(map(_x, a_b_c)):
192
199
  raise _nfError(r, unstr(_fma, *a_b_c))
193
200
  return r
194
201
 
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
202
+ def _2products(x, y3s, *zs): # PYCHOK in Fsum._f2mul
203
+ # yield(x * y3 for y3 in y3s) + yield(z in zs)
208
204
  # TwoProduct U{Algorithm 3.3
209
205
  # <https://www.TUHH.De/ti3/paper/rump/OgRuOi05.pdf>}
210
- # also in Python 3.13+ C{Modules/marhmodule.c} under
206
+ # also in Python 3.13+ C{Modules/mathmodule.c} under
211
207
  # #ifndef UNRELIABLE_FMA ... #else ... #endif
212
208
  _, a, b = _2split3(x)
213
209
  for y, c, d in y3s:
214
210
  y *= x
215
211
  yield y
216
- if two: # or not a:
212
+ if False: # no cover
217
213
  yield b * d - (((y - a * c) - b * c) - a * d)
218
214
  # = b * d + (a * d - ((y - a * c) - b * c))
219
215
  # = b * d + (a * d + (b * c - (y - a * c)))
220
216
  # = b * d + (a * d + (b * c + (a * c - y)))
221
- else:
217
+ elif a:
222
218
  yield a * c - y
223
219
  yield b * c
224
220
  if d:
225
221
  yield a * d
226
222
  yield b * d
223
+ else:
224
+ yield b * c - y
225
+ yield b * d
226
+ for z in zs:
227
+ yield z
228
+
229
+ _2FACTOR = pow(2, (MANT_DIG + 1) // 2) + _1_0 # 134217729 if MANT_DIG == 53
230
+
231
+ def _2split3(x):
232
+ # Split U{Algorithm 3.2
233
+ # <https://www.TUHH.De/ti3/paper/rump/OgRuOi05.pdf>}
234
+ a = c = x * _2FACTOR
235
+ a -= c - x
236
+ b = x - a
237
+ return x, a, b
238
+
239
+ def _2split3s(xs): # in Fsum.is_math_fma
240
+ return map(_2split3, xs)
227
241
 
228
242
 
229
243
  def f2product(*two):
@@ -246,15 +260,15 @@ def f2product(*two):
246
260
 
247
261
 
248
262
  def _Fsumf_(*xs): # in .auxLat, .ltp, ...
249
- '''(INTERNAL) An C{Fsum} of I{known scalars}.
263
+ '''(INTERNAL) An C{Fsum(xs)}, all C{scalar}, an L{Fsum} or L{Fsum2Tuple}.
250
264
  '''
251
- return Fsum()._facc_scalar(xs, up=False)
265
+ return Fsum()._facc_scalarf(xs, up=False)
252
266
 
253
267
 
254
268
  def _Fsum1f_(*xs): # in .albers
255
- '''(INTERNAL) An C{Fsum} of I{known scalars}, 1-primed.
269
+ '''(INTERNAL) An C{Fsum(xs)}, all C{scalar}, an L{Fsum} or L{Fsum2Tuple}, 1-primed.
256
270
  '''
257
- return Fsum()._facc_scalar(_1primed(xs), up=False)
271
+ return Fsum()._facc_scalarf(_1primed(xs), up=False)
258
272
 
259
273
 
260
274
  def _2halfeven(s, r, p):
@@ -275,14 +289,14 @@ def _isFsum(x): # in .fmath
275
289
  return isinstance(x, Fsum)
276
290
 
277
291
 
278
- def _isFsumTuple(x): # in .basics, .constants, .fmath, .fstats
292
+ def _isFsum_2Tuple(x): # in .basics, .constants, .fmath, .fstats
279
293
  '''(INTERNAL) Is C{x} an C{Fsum} or C{Fsum2Tuple} instance?
280
294
  '''
281
- return isinstance(x, _Fsum_Fsum2Tuple_types)
295
+ return isinstance(x, _Fsum_2Tuple_types)
282
296
 
283
297
 
284
298
  def _isOK(unused):
285
- '''(INTERNAL) Helper for C{nonfiniterrors} and C{Fsum.nonfinites}.
299
+ '''(INTERNAL) Helper for C{Fsum._fsum2} and C{Fsum.nonfinites}.
286
300
  '''
287
301
  return True
288
302
 
@@ -294,12 +308,21 @@ def _isOK_or_finite(x, _isfine=_isfinite):
294
308
  return _isfine(x)
295
309
 
296
310
 
311
+ def _ixError(X, xs, i, x, origin=0, which=None):
312
+ '''(INTERNAL) Error for C{xs} or C{x}, item C{xs[i]}.
313
+ '''
314
+ t = _xsError(X, xs, i + origin, x)
315
+ if which:
316
+ t = _COMMASPACE_(unstr(which, _Cdot=Fsum), t)
317
+ return _xError(X, t, txt=None)
318
+
319
+
297
320
  def _nfError(x, *args):
298
321
  '''(INTERNAL) Throw a C{not-finite} exception.
299
322
  '''
300
323
  E = _NonfiniteError(x)
301
324
  t = Fmt.PARENSPACED(_not_finite_, x)
302
- if args: # in _fma, _2sum
325
+ if args: # in _fmaX, _2sum
303
326
  return E(txt=t, *args)
304
327
  raise E(t, txt=None)
305
328
 
@@ -360,7 +383,7 @@ def _psum(ps, **_isfine): # PYCHOK used!
360
383
  elif not _isfinite(s): # non-finite OK
361
384
  i = 0 # collapse ps
362
385
  if ps:
363
- s += _sum(ps) # _fsum(ps)
386
+ s += sum(ps)
364
387
  ps[i:] = s,
365
388
  return s
366
389
 
@@ -385,7 +408,7 @@ def _2scalar2(other):
385
408
  '''(INTERNAL) Return 2-tuple C{(other, r)} with C{other} as C{int},
386
409
  C{float} or C{as-is} and C{r} the residual of C{as-is}.
387
410
  '''
388
- if _isFsumTuple(other):
411
+ if _isFsum_2Tuple(other):
389
412
  s, r = other._fint2
390
413
  if r:
391
414
  s, r = other._fprs2
@@ -447,9 +470,9 @@ def _2sum(a, b, _isfine=_isfinite): # in .testFmath
447
470
  else:
448
471
  r = (a - s) + b
449
472
  elif _isfine(s):
450
- r = 0
473
+ r = _NONFINITEr
451
474
  else: # non-finite and not OK
452
- t = unstr(_2sum, a, b)
475
+ t = unstr(_2sum, a, b)
453
476
  raise _nfError(s, t)
454
477
  return s, r
455
478
 
@@ -477,10 +500,10 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
477
500
  i.e. any C{type} having method C{__float__}.
478
501
 
479
502
  @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.
503
+ determined by function L{nonfiniterrors<fsums.nonfiniterrors>} for the default
504
+ and by method L{nonfinites<Fsum.nonfinites>} for individual C{Fsum} instances,
505
+ overruling the default. For backward compatibility, I{non-finites} raise
506
+ exceptions by default.
484
507
 
485
508
  @see: U{Hettinger<https://GitHub.com/ActiveState/code/tree/master/recipes/Python/
486
509
  393090_Binary_floating_point_summatiaccurate_full/recipe-393090.py>},
@@ -499,7 +522,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
499
522
  _isfine = {} # == _isfinite
500
523
  _n = 0
501
524
  # _ps = [] # partial sums
502
- # _ps_max = 0 # max(Fsum._ps_max, len(Fsum._ps))
525
+ # _ps_max = 0 # max(Fsum._ps_max, len(Fsum._ps)) # 41
503
526
  _RESIDUAL = _threshold(_RESIDUAL_0_0)
504
527
 
505
528
  def __init__(self, *xs, **name_f2product_nonfinites_RESIDUAL):
@@ -1043,7 +1066,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1043
1066
  def _cmp_0(self, other, op):
1044
1067
  '''(INTERNAL) Return C{scalar(self - B{other})} for 0-comparison.
1045
1068
  '''
1046
- if _isFsumTuple(other):
1069
+ if _isFsum_2Tuple(other):
1047
1070
  s = self._ps_1sum(*other._ps)
1048
1071
  elif self._scalar(other, op):
1049
1072
  s = self._ps_1sum(other)
@@ -1091,7 +1114,9 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1091
1114
  def _Error(self, op, other, Error, **txt_cause):
1092
1115
  '''(INTERNAL) Format an B{C{Error}} for C{{self} B{op} B{other}}.
1093
1116
  '''
1094
- return Error(_SPACE_(self.as_iscalar, op, other), **txt_cause)
1117
+ # self.as_iscalar causes RecursionError for ._fprs2 errors
1118
+ s = _Psum(self._ps, nonfinites=True, name=self.name)
1119
+ return Error(_SPACE_(s.as_iscalar, op, other), **txt_cause)
1095
1120
 
1096
1121
  def _ErrorX(self, X, op, other, *mod):
1097
1122
  '''(INTERNAL) Format the caught exception C{X}.
@@ -1113,9 +1138,9 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1113
1138
  '''
1114
1139
  if xs:
1115
1140
  kwds = _xkwds(self._isfine, **origin_X_x)
1116
- _xs = _2floats(xs, **kwds) # PYCHOK yield
1141
+ fs = _2floats(xs, **kwds) # PYCHOK yield
1117
1142
  ps = self._ps
1118
- ps[:] = self._ps_acc(list(ps), _xs, up=up)
1143
+ ps[:] = self._ps_acc(list(ps), fs, up=up)
1119
1144
  return self
1120
1145
 
1121
1146
  def _facc_args(self, xs, **up):
@@ -1141,7 +1166,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1141
1166
  '''
1142
1167
  def _Pow4(p):
1143
1168
  r = 0
1144
- if _isFsumTuple(p):
1169
+ if _isFsum_2Tuple(p):
1145
1170
  s, r = p._fprs2
1146
1171
  if r:
1147
1172
  m = Fsum._pow
@@ -1158,7 +1183,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1158
1183
  _Pow, p, s, r = _Pow4(power)
1159
1184
  if p: # and xs:
1160
1185
  op = which.__name__
1161
- _FsT = _Fsum_Fsum2Tuple_types
1186
+ _FsT = _Fsum_2Tuple_types
1162
1187
  _pow = self._pow_2_3
1163
1188
 
1164
1189
  def _P(X):
@@ -1178,18 +1203,27 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1178
1203
  return f
1179
1204
 
1180
1205
  def _facc_scalar(self, xs, **up):
1181
- '''(INTERNAL) Accumulate all C{xs}, known to be scalar.
1206
+ '''(INTERNAL) Accumulate all C{xs}, each C{scalar}.
1182
1207
  '''
1183
1208
  if xs:
1184
1209
  _ = self._ps_acc(self._ps, xs, **up)
1185
1210
  return self
1186
1211
 
1187
1212
  def _facc_scalar_(self, *xs, **up):
1188
- '''(INTERNAL) Accumulate all positional C{xs}, known to be scalar.
1213
+ '''(INTERNAL) Accumulate all positional C{xs}, each C{scalar}.
1189
1214
  '''
1190
- if xs:
1191
- _ = self._ps_acc(self._ps, xs, **up)
1192
- return self
1215
+ return self._facc_scalar(xs, **up)
1216
+
1217
+ def _facc_scalarf(self, xs, **origin_which):
1218
+ '''(INTERNAL) Accumulate all C{xs}, each C{scalar}, an L{Fsum} or
1219
+ L{Fsum2Tuple}, like function C{_xsum}.
1220
+ '''
1221
+ i_x = [0, xs]
1222
+ try:
1223
+ nf = self.nonfinitesOK
1224
+ return self._facc_scalar(_xs(xs, i_x, nf))
1225
+ except (OverflowError, TypeError, ValueError) as X:
1226
+ raise _ixError(X, xs, *i_x, **origin_which)
1193
1227
 
1194
1228
  # def _facc_up(self, up=True):
1195
1229
  # '''(INTERNAL) Update the C{partials}, by removing
@@ -1219,7 +1253,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1219
1253
 
1220
1254
  @raise ValueError: Invalid or I{non-finite} B{C{xs}} value.
1221
1255
  '''
1222
- if _isFsumTuple(xs):
1256
+ if _isFsum_2Tuple(xs):
1223
1257
  self._facc_scalar(xs._ps)
1224
1258
  elif isscalar(xs): # for backward compatibility # PYCHOK no cover
1225
1259
  x = _2float(x=xs, **self._isfine)
@@ -1241,7 +1275,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1241
1275
  def _fadd(self, other, op, **up): # in .fmath.Fhorner
1242
1276
  '''(INTERNAL) Apply C{B{self} += B{other}}.
1243
1277
  '''
1244
- if _isFsumTuple(other):
1278
+ if _isFsum_2Tuple(other):
1245
1279
  if self._ps:
1246
1280
  self._facc_scalar(other._ps, **up)
1247
1281
  else:
@@ -1283,7 +1317,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1283
1317
  '''
1284
1318
  if _xiterablen(cs):
1285
1319
  H = self._Fsum_as(name__=self._fhorner)
1286
- if _isFsumTuple(x):
1320
+ if _isFsum_2Tuple(x):
1287
1321
  _mul = H._mul_Fsum
1288
1322
  else:
1289
1323
  _mul = H._mul_scalar
@@ -1352,8 +1386,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1352
1386
  r = (self._ps_1sum(i) if len(self._ps) > 1 else
1353
1387
  float(s - i)) or INT0
1354
1388
  except (OverflowError, ValueError) as X:
1355
- r = 0 # INF, NAN, NINF
1356
- i = self._fintX(X, sum(self._ps))
1389
+ r = _NONFINITEr # INF, NAN, NINF
1390
+ i = self._fintX(X, sum(self._ps))
1357
1391
  return i, r # Fsum2Tuple?
1358
1392
 
1359
1393
  @_fint2.setter_ # PYCHOK setter_UNDERscore!
@@ -1364,8 +1398,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1364
1398
  i = int(s)
1365
1399
  r = (s - i) or INT0
1366
1400
  except (OverflowError, ValueError) as X:
1367
- r = 0 # INF, NAN, NINF
1368
- i = self._fintX(X, float(s))
1401
+ r = _NONFINITEr # INF, NAN, NINF
1402
+ i = self._fintX(X, float(s))
1369
1403
  return i, r # like _fint2.getter
1370
1404
 
1371
1405
  def _fintX(self, X, i): # PYCHOK X
@@ -1406,31 +1440,32 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1406
1440
  q = self._ftruediv(other, op, **raiser_RESIDUAL) # == self
1407
1441
  return self._fset(q.floor) # floor(q)
1408
1442
 
1409
- def fma(self, other1, other2, raiser=False): # in .fmath.fma
1443
+ def fma(self, other1, other2, **nonfinites): # in .fmath.fma
1410
1444
  '''Fused-multiply-add C{self *= B{other1}; self += B{other2}}.
1411
1445
 
1412
1446
  @arg other1: Multiplier (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
1413
1447
  @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}.
1448
+ @kwarg nonfinites: Use C{B{nonfinites}=True} or C{False}, to
1449
+ override L{nonfinites<Fsum.nonfinites>} and
1450
+ L{nonfiniterrors} default (C{bool}).
1419
1451
  '''
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
1452
+ op = self.fma.__name__
1453
+ _fs = self._ps_other
1454
+ try:
1455
+ s, r = self._fprs2
1456
+ if r:
1457
+ f = self._f2mul(self.fma, other1, **nonfinites)
1458
+ f += other2
1459
+ else:
1460
+ fs = _2split3s(_fs(op, other1))
1461
+ fs = _2products(s, fs, *_fs(op, other2))
1462
+ f = _Psum(self._ps_acc([], fs, up=False), name=op)
1463
+ except TypeError as X:
1464
+ raise self._ErrorX(X, op, (other1, other2))
1465
+ except (OverflowError, ValueError) as X: # from math.fma
1466
+ f = self._mul_reduce(op, s, other1) # INF, NAN, NINF
1467
+ f = sum(_fs(op, f, other2))
1468
+ f = self._nonfiniteX(X, op, f, **nonfinites)
1434
1469
  return self._fset(f)
1435
1470
 
1436
1471
  fmul = __imul__
@@ -1438,11 +1473,11 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1438
1473
  def _fmul(self, other, op):
1439
1474
  '''(INTERNAL) Apply C{B{self} *= B{other}}.
1440
1475
  '''
1441
- if _isFsumTuple(other):
1476
+ if _isFsum_2Tuple(other):
1442
1477
  if len(self._ps) != 1:
1443
1478
  f = self._mul_Fsum(other, op)
1444
1479
  elif len(other._ps) != 1: # and len(self._ps) == 1
1445
- f = self._ps_mul(op, *other._ps)
1480
+ f = self._ps_mul(op, *other._ps) if other._ps else _0_0
1446
1481
  elif self._f2product: # len(other._ps) == 1
1447
1482
  f = self._mul_scalar(other._ps[0], op)
1448
1483
  else: # len(other._ps) == len(self._ps) == 1
@@ -1457,39 +1492,41 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1457
1492
  '''DEPRECATED on 2024.09.13, use method L{f2mul_<Fsum.f2mul_>}.'''
1458
1493
  return self._fset(self.f2mul_(*others, **raiser))
1459
1494
 
1460
- def f2mul_(self, *others, **raiser): # in .fmath.f2mul
1495
+ def f2mul_(self, *others, **nonfinites): # in .fmath.f2mul
1461
1496
  '''Return C{B{self} * B{other} * B{other} ...} for all B{C{others}} using cascaded,
1462
1497
  accurate multiplication like with L{f2product<Fsum.f2product>} set to C{True}.
1463
1498
 
1464
1499
  @arg others: Multipliers (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}), all
1465
1500
  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}).
1501
+ @kwarg nonfinites: Use C{B{nonfinites}=True} or C{False}, to override both
1502
+ L{nonfinites<Fsum.nonfinites>} and the L{nonfiniterrors}
1503
+ default (C{bool}).
1468
1504
 
1469
1505
  @return: The cascaded I{TwoProduct} (L{Fsum} or C{float}).
1470
1506
 
1471
1507
  @see: U{Equations 2.3<https://www.TUHH.De/ti3/paper/rump/OzOgRuOi06.pdf>}
1472
1508
  '''
1473
- return self._f2mul(self.f2mul_, *others, **raiser)
1509
+ return self._f2mul(self.f2mul_, *others, **nonfinites)
1474
1510
 
1475
- def _f2mul(self, where, *others, **raiser):
1511
+ def _f2mul(self, where, *others, **nonfinites_raiser):
1476
1512
  '''(INTERNAL) See methods C{fma} and C{f2mul_}.
1477
1513
  '''
1478
- f = self._copy_2(where)
1479
- if others:
1514
+ f = self._copy_2(where)
1515
+ ps = f._ps
1516
+ if ps and others:
1480
1517
  op = where.__name__
1481
- ps = f._ps
1482
- if ps:
1483
- try:
1484
- for p in self._ps_other(op, *others):
1518
+ try:
1519
+ for other in others: # to pinpoint errors
1520
+ for p in self._ps_other(op, other):
1485
1521
  pfs = _2products(p, _2split3s(ps))
1486
1522
  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)
1523
+ f._update()
1524
+ except TypeError as X:
1525
+ raise self._ErrorX(X, op, other)
1526
+ except (OverflowError, ValueError) as X:
1527
+ r = self._mul_reduce(op, sum(ps), other) # INF, NAN, NINF
1528
+ r = self._nonfiniteX(X, op, r, **nonfinites_raiser)
1529
+ f._fset(r)
1493
1530
  return f
1494
1531
 
1495
1532
  def fover(self, over, **raiser_RESIDUAL):
@@ -1531,8 +1568,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1531
1568
 
1532
1569
  def f2product(self, *two):
1533
1570
  '''Get and set accurate I{TwoProduct} multiplication for this
1534
- L{Fsum}, I{overriding the global setting} from function
1535
- L{f2product<fsums.f2product>}.
1571
+ L{Fsum}, overriding the L{f2product} default.
1536
1572
 
1537
1573
  @arg two: If omitted, leave the override unchanged, if C{True},
1538
1574
  turn I{TwoProduct} on, if C{False} off, if C{None}e
@@ -1564,7 +1600,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1564
1600
  s, _ = self._fprs2
1565
1601
  return s # ._fprs2.fsum
1566
1602
 
1567
- @_fprs.setter_ # PYCHOK setter_underscore!
1603
+ @_fprs.setter_ # PYCHOK setter_UNDERscore!
1568
1604
  def _fprs(self, s):
1569
1605
  '''(INTERNAL) Replace the C{_fprs} value.
1570
1606
  '''
@@ -1576,30 +1612,36 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1576
1612
  running sum and residual (L{Fsum2Tuple}).
1577
1613
  '''
1578
1614
  ps = self._ps
1615
+ n = len(ps)
1579
1616
  try:
1580
- n = len(ps) - 2
1581
- if n > 0: # len(ps) > 2
1617
+ if n > 2:
1582
1618
  s = _psum(ps, **self._isfine)
1583
- n = len(ps) - 2
1584
- if n > 0:
1619
+ if not _isfinite(s):
1620
+ ps[:] = s, # collapse ps
1621
+ return Fsum2Tuple(s, _NONFINITEr)
1622
+ n = len(ps)
1623
+ # Fsum._ps_max = max(Fsum._ps_max, n)
1624
+ if n > 2:
1585
1625
  r = self._ps_1sum(s)
1586
1626
  return Fsum2Tuple(*_s_r(s, r))
1587
- if n == 0: # len(ps) == 2
1627
+ if n > 1: # len(ps) == 2
1588
1628
  s, r = _s_r(*_2sum(*ps, **self._isfine))
1589
1629
  ps[:] = (r, s) if r else (s,)
1590
1630
  elif ps: # len(ps) == 1
1591
- s, r = ps[0], INT0
1631
+ s = ps[0]
1632
+ r = INT0 if _isfinite(s) else _NONFINITEr
1592
1633
  else: # len(ps) == 0
1593
1634
  s, r = _0_0, INT0
1594
1635
  ps[:] = s,
1595
1636
  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
1637
+ op = sum.__name__ # INF, NAN, NINF
1638
+ ps[:] = sum(ps), # collapse ps
1639
+ s = self._nonfiniteX(X, op, ps[0])
1640
+ r = _NONFINITEr
1599
1641
  # assert self._ps is ps
1600
1642
  return Fsum2Tuple(s, r)
1601
1643
 
1602
- @_fprs2.setter_ # PYCHOK setter_underscore!
1644
+ @_fprs2.setter_ # PYCHOK setter_UNDERscore!
1603
1645
  def _fprs2(self, s_r):
1604
1646
  '''(INTERNAL) Replace the C{_fprs2} value.
1605
1647
  '''
@@ -1616,15 +1658,15 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1616
1658
 
1617
1659
  @see: Method L{Fsum.fadd} for further details.
1618
1660
  '''
1619
- return self._fset(xs[0], op=_fset_op_) if len(xs) == 1 else \
1620
- self._fset(_0_0)._facc_args(xs)
1661
+ f = self._Fsum_as(*xs)
1662
+ return self._fset(f, up=False, op=_fset_op_)
1621
1663
 
1622
1664
  def _fset(self, other, n=0, up=True, **op):
1623
1665
  '''(INTERNAL) Overwrite this instance with an other or a C{scalar}.
1624
1666
  '''
1625
1667
  if other is self:
1626
1668
  pass # from ._fmul, ._ftruediv and ._pow_0_1
1627
- elif _isFsumTuple(other):
1669
+ elif _isFsum_2Tuple(other):
1628
1670
  self._ps[:] = other._ps
1629
1671
  self._n = n or other._n
1630
1672
  if up: # use or zap the C{Property_RO} values
@@ -1670,7 +1712,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
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,8 +1722,8 @@ 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
1728
  @arg xs: Iterable of items to add (each item C{scalar}
1687
1729
  or an L{Fsum} or L{Fsum2Tuple} instance).
@@ -1695,8 +1737,8 @@ 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
1743
  @arg xs: Items to add (each C{scalar} or an L{Fsum}
1702
1744
  or L{Fsum2Tuple} instance), all positional.
@@ -1742,7 +1784,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1742
1784
  kwds.update(name_f2product_nonfinites_RESIDUAL)
1743
1785
  F = Fsum(**kwds)
1744
1786
  # assert all(v == self.__dict__[n] for n, v in F.__dict__.items())
1745
- return F._fset(xs[0]) if len(xs) == 1 else (
1787
+ return F._fset(xs[0], op=_fset_op_) if len(xs) == 1 else (
1746
1788
  F._facc(xs, up=False) if xs else F)
1747
1789
 
1748
1790
  def fsum2(self, xs=(), **name):
@@ -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, origin=1, which=self.fsumf_)._fprs
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, origin=1, which=self.Fsumf_)._copy_2(self.Fsumf_)
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, origin=1, which=self.fsum2f_)
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,8 @@ 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}, otherwise
1895
+ the C{float} sum if the residual is zero or not significant.
1852
1896
 
1853
1897
  @raise ResidualError: Non-zero, significant residual or invalid
1854
1898
  B{C{RESIDUAL}}.
@@ -1878,7 +1922,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1878
1922
 
1879
1923
  @see: Function L{isfinite<pygeodesy.isfinite>}.
1880
1924
  '''
1881
- return _isfinite(_sum(self._ps)) # _sum(self)
1925
+ return _isfinite(sum(self._ps)) # == sum(self)
1882
1926
 
1883
1927
  def is_integer(self):
1884
1928
  '''Is this instance' running sum C{integer}? (C{bool}).
@@ -1895,7 +1939,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1895
1939
  an C{fma} implementation as C{math.fma} or C{None}, a previous
1896
1940
  C{PyGeodesy} implementation.
1897
1941
  '''
1898
- return (_fma.__module__ is fabs.__module__ or None) if _2split3s is _passarg else False
1942
+ return (_2split3s is _passarg) or (False if _2n_d is None else None)
1899
1943
 
1900
1944
  def is_math_fsum(self):
1901
1945
  '''Are the summation functions L{fsum}, L{fsum_}, L{fsumf_}, L{fsum1},
@@ -1929,7 +1973,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1929
1973
  def _mul_Fsum(self, other, op=_mul_op_): # in .fmath.Fhorner
1930
1974
  '''(INTERNAL) Return C{B{self} * B{other}} as L{Fsum} or C{0}.
1931
1975
  '''
1932
- # assert _isFsumTuple(other)
1976
+ # assert _isFsum_2Tuple(other)
1933
1977
  if self._ps and other._ps:
1934
1978
  f = self._ps_mul(op, *other._ps) # NO .as_iscalar!
1935
1979
  else:
@@ -1970,8 +2014,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1970
2014
  def nonfinites(self, *OK):
1971
2015
  '''Handle I{non-finite} C{float}s as C{inf}, C{INF}, C{NINF}, C{nan}
1972
2016
  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>}.
2017
+ C{ValueError} exceptions, overriding the L{nonfiniterrors} default.
1975
2018
 
1976
2019
  @arg OK: If omitted, leave the override unchanged, if C{True},
1977
2020
  I{non-finites} are C{OK}, if C{False} throw exceptions
@@ -1981,14 +2024,16 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1981
2024
 
1982
2025
  @see: Function L{nonfiniterrors<fsums.nonfiniterrors>}.
1983
2026
 
1984
- @note: Use C{f.nonfinites() or not nonfiniterrors()} to determine
1985
- whether L{Fsum} C{f} handles I{non-finites}.
2027
+ @note: Use property L{nonfinitesOK<Fsum.nonfinitesOK>} to determine
2028
+ whether I{non-finites} are C{OK} for this L{Fsum} and by the
2029
+ L{nonfiniterrors} default.
1986
2030
  '''
1987
2031
  _ks = Fsum._nonfinites_isfine_kwds
1988
2032
  if OK: # delattrof(self, _isfine=None)
1989
2033
  k = _xkwds_pop(self.__dict__, _isfine=None)
1990
2034
  if OK[0] is not None:
1991
2035
  self._isfine = _ks[bool(OK[0])]
2036
+ self._update()
1992
2037
  else: # getattrof(self, _isfine=None)
1993
2038
  k = _xkwds_get(self.__dict__, _isfine=None)
1994
2039
  # dict(map(reversed, _ks.items())).get(k, None)
@@ -1999,10 +2044,21 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1999
2044
  _nonfinites_isfine_kwds = {True: dict(_isfine=_isOK),
2000
2045
  False: dict(_isfine=_isfinite)}
2001
2046
 
2002
- def _nonfiniteX(self, X, op, f):
2047
+ @property_RO
2048
+ def nonfinitesOK(self):
2049
+ '''Are I{non-finites} C{OK} for this L{Fsum} or by default? (C{bool}).
2050
+ '''
2051
+ nf = self.nonfinites()
2052
+ if nf is None:
2053
+ nf = not nonfiniterrors()
2054
+ return nf
2055
+
2056
+ def _nonfiniteX(self, X, op, f, nonfinites=None, raiser=None):
2003
2057
  '''(INTERNAL) Handle a I{non-finite} exception.
2004
2058
  '''
2005
- if not _isOK_or_finite(f, **self._isfine):
2059
+ if nonfinites is None:
2060
+ nonfinites = _isOK_or_finite(f, **self._isfine) if raiser is None else (not raiser)
2061
+ if not nonfinites:
2006
2062
  raise self._ErrorX(X, op, f)
2007
2063
  return f
2008
2064
 
@@ -2063,7 +2119,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2063
2119
  def _pow(self, other, unused, op, **raiser_RESIDUAL):
2064
2120
  '''Return C{B{self} ** B{other}}.
2065
2121
  '''
2066
- if _isFsumTuple(other):
2122
+ if _isFsum_2Tuple(other):
2067
2123
  f = self._pow_Fsum(other, op, **raiser_RESIDUAL)
2068
2124
  elif self._scalar(other, op):
2069
2125
  x = self._finite(other, op)
@@ -2084,7 +2140,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2084
2140
 
2085
2141
  if mod: # b, x, mod all C{int}, unless C{mod} is C{None}
2086
2142
  m = mod[0]
2087
- # assert _isFsumTuple(b)
2143
+ # assert _isFsum_2Tuple(b)
2088
2144
 
2089
2145
  def _s(s, r):
2090
2146
  R = self._raiser(r, s, **raiser_RESIDUAL)
@@ -2106,9 +2162,9 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2106
2162
  raise self._ErrorX(X, op, other, *mod)
2107
2163
 
2108
2164
  def _pow_Fsum(self, other, op, **raiser_RESIDUAL):
2109
- '''(INTERNAL) Return C{B{self} **= B{other}} for C{_isFsumTuple(other)}.
2165
+ '''(INTERNAL) Return C{B{self} **= B{other}} for C{_isFsum_2Tuple(other)}.
2110
2166
  '''
2111
- # assert _isFsumTuple(other)
2167
+ # assert _isFsum_2Tuple(other)
2112
2168
  x, r = other._fprs2
2113
2169
  f = self._pow_scalar(x, other, op, **raiser_RESIDUAL)
2114
2170
  if f and r:
@@ -2203,7 +2259,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2203
2259
  if n:
2204
2260
  self._n += n
2205
2261
  # if _fi: # collapse ps if non-finite
2206
- # x = _sum(ps)
2262
+ # x = sum(ps)
2207
2263
  # if not _isfinite(x):
2208
2264
  # ps[:] = x,
2209
2265
  # Fsum._ps_max = max(Fsum._ps_max, len(ps))
@@ -2219,19 +2275,21 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2219
2275
  if len(ps) < len(fs):
2220
2276
  ps, fs = fs, ps
2221
2277
  if self._f2product:
2222
- ps = _2split3s(ps)
2223
- _fps = _2products
2278
+ fs, p = _2split3s(fs), fs
2279
+ if len(ps) > 1 and fs is not p:
2280
+ fs = tuple(fs) # several ps
2281
+ _pfs = _2products
2224
2282
  else:
2225
- def _fps(f, ps):
2226
- return (f * p for p in ps)
2283
+ def _pfs(p, fs):
2284
+ return (p * f for f in fs)
2227
2285
 
2228
- for f in fs:
2229
- for p in _fps(f, ps):
2230
- yield p if _isfine(p) else self._finite(p, op)
2286
+ for p in ps:
2287
+ for f in _pfs(p, fs):
2288
+ yield f if _isfine(f) else self._finite(f, op)
2231
2289
 
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)
2290
+ fs = _psfs(self._ps, factors, **self._isfine)
2291
+ f = _Psum(self._ps_acc([], fs, up=False), name=op)
2292
+ return f
2235
2293
 
2236
2294
  @property_RO
2237
2295
  def _ps_neg(self):
@@ -2244,7 +2302,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2244
2302
  '''(INTERNAL) Yield all C{other}s as C{scalar}.
2245
2303
  '''
2246
2304
  for other in others:
2247
- if _isFsumTuple(other):
2305
+ if _isFsum_2Tuple(other):
2248
2306
  for p in other._ps:
2249
2307
  yield p
2250
2308
  else:
@@ -2345,7 +2403,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2345
2403
  def root(self, root, **raiser_RESIDUAL):
2346
2404
  '''Return C{B{self}**(1 / B{root})} as L{Fsum}.
2347
2405
 
2348
- @arg root: The order (C{scalar}, L{Fsum} or L{Fsum2Tuple}), non-zero.
2406
+ @arg root: Non-zero order (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
2349
2407
  @kwarg raiser_RESIDUAL: Use C{B{raiser}=False} to ignore any
2350
2408
  L{ResidualError}s (C{bool}) or C{B{RESIDUAL}=scalar}
2351
2409
  to override the current L{RESIDUAL<Fsum.RESIDUAL>}.
@@ -2362,7 +2420,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2362
2420
  return f._fpow(x, f.name, **raiser_RESIDUAL) # == pow(f, x)
2363
2421
 
2364
2422
  def _scalar(self, other, op, **txt):
2365
- '''(INTERNAL) Return scalar C{other}.
2423
+ '''(INTERNAL) Return scalar C{other} or throw a C{TypeError}.
2366
2424
  '''
2367
2425
  if isscalar(other):
2368
2426
  return other
@@ -2371,8 +2429,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2371
2429
  def signOf(self, res=True):
2372
2430
  '''Determine the sign of this instance.
2373
2431
 
2374
- @kwarg res: If C{True}, consider, otherwise ignore
2375
- the residual (C{bool}).
2432
+ @kwarg res: If C{True}, consider the residual,
2433
+ otherwise ignore the latter (C{bool}).
2376
2434
 
2377
2435
  @return: The sign (C{int}, -1, 0 or +1).
2378
2436
  '''
@@ -2427,7 +2485,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2427
2485
 
2428
2486
  _ROs = _allPropertiesOf_n(3, Fsum, Property_RO) # PYCHOK see Fsum._update
2429
2487
 
2430
- if _NONFINITES: # PYCHOK no cover
2488
+ if _NONFINITES == _std_: # PYCHOK no cover
2431
2489
  _ = nonfiniterrors(False)
2432
2490
 
2433
2491
 
@@ -2574,7 +2632,7 @@ class Fsum2Tuple(_NamedTuple): # in .fstats
2574
2632
  '''
2575
2633
  return Fmt.PAREN(fstr(self, fmt=fmt, strepr=str, force=False, **prec_sep))
2576
2634
 
2577
- _Fsum_Fsum2Tuple_types = Fsum, Fsum2Tuple # PYCHOK lines
2635
+ _Fsum_2Tuple_types = Fsum, Fsum2Tuple # PYCHOK lines
2578
2636
 
2579
2637
 
2580
2638
  class ResidualError(_ValueError):
@@ -2603,7 +2661,7 @@ except ImportError:
2603
2661
  def _fsum(xs):
2604
2662
  '''(INTERNAL) Precision summation, Python 2.5-.
2605
2663
  '''
2606
- F = Fsum(name=_fsum.name, nonfinites=True)
2664
+ F = Fsum(name=_fsum.name, f2product=False, nonfinites=True)
2607
2665
  return float(F._facc(xs, up=False))
2608
2666
 
2609
2667
 
@@ -2613,8 +2671,7 @@ def fsum(xs, nonfinites=None, **floats):
2613
2671
  @arg xs: Iterable of items to add (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
2614
2672
  @kwarg nonfinites: Use C{B{nonfinites}=True} if I{non-finites} are C{OK}, if
2615
2673
  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}).
2674
+ C{None}, L{nonfiniterrors} applies (C{bool} or C{None}).
2618
2675
  @kwarg floats: DEPRECATED keyword argument C{B{floats}=False} (C{bool}), use
2619
2676
  keyword argument C{B{nonfinites}=False} instead.
2620
2677
 
@@ -2685,43 +2742,34 @@ def fsum1f_(*xs):
2685
2742
  return _xsum(fsum1f_, xs, nonfinites=True, primed=1) if xs else _0_0
2686
2743
 
2687
2744
 
2688
- def _xs(xs, _x, i_x):
2745
+ def _xs(xs, i_x, nfOK): # in Fsum._facc_scalarf
2689
2746
  '''(INTERNAL) Yield all C{xs} as C{scalar}.
2690
2747
  '''
2748
+ _x = _passarg if nfOK else _2finite
2691
2749
  for i, x in enumerate(xs):
2692
2750
  i_x[:] = i, x
2693
- if _isFsumTuple(x):
2751
+ if _isFsum_2Tuple(x):
2694
2752
  for p in map(_x, x._ps):
2695
2753
  yield p
2696
2754
  else:
2697
2755
  yield _x(x)
2698
2756
 
2699
2757
 
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))
2706
-
2707
-
2708
2758
  def _xsum(which, xs, nonfinites=None, origin=0, primed=0, **floats):
2709
2759
  '''(INTERNAL) Precision summation of C{xs} with conditions.
2710
2760
  '''
2711
2761
  i_x = [0, xs]
2712
2762
  try:
2713
- if nonfinites is None:
2714
- nonfinites = not nonfiniterrors()
2715
- elif floats:
2763
+ if floats: # for backward compatibility
2716
2764
  nonfinites = _xkwds_get1(floats, floats=nonfinites)
2717
- fs = _xs(xs, (_passarg if nonfinites else _2finite), i_x)
2765
+ elif nonfinites is None:
2766
+ nonfinites = not nonfiniterrors()
2767
+ fs = _xs(xs, i_x, nonfinites)
2718
2768
  return _fsum(_1primed(fs) if primed else fs)
2719
2769
  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)
2724
- raise _xError(X, t, txt=None)
2770
+ origin -= 1 if primed else 0
2771
+ i_x += [origin, which]
2772
+ raise _ixError(X, xs, *i_x)
2725
2773
 
2726
2774
 
2727
2775
  # delete all decorators, etc.