pygeodesy 24.4.24__py2.py3-none-any.whl → 24.5.6__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
@@ -14,62 +14,66 @@ L{Fsum.__rpow__} return a (very long) C{int} if invoked with optional argument
14
14
  C{mod} set to C{None}. The C{residual} of an C{integer} L{Fsum} may be between
15
15
  C{-1.0} and C{+1.0}, including C{INT0} if considered to be I{exact}.
16
16
 
17
- Set env variable C{PYGEODESY_FSUM_PARTIALS} to string C{"fsum"}) for summation
18
- of L{Fsum} partials by Python function C{math.fsum}.
19
-
20
17
  Set env variable C{PYGEODESY_FSUM_RESIDUAL} to a C{float} string greater than
21
- C{"0.0"} as the threshold to throw a L{ResidualError} in division or exponention
22
- of an L{Fsum} instance with a I{relative} C{residual} exceeding the threshold,
23
- see methods L{Fsum.RESIDUAL}, L{Fsum.pow}, L{Fsum.__ipow__} and L{Fsum.__itruediv__}.
18
+ C{"0.0"} as the threshold to throw a L{ResidualError} for a division, power or
19
+ root operation of an L{Fsum} instance with a C{residual} I{ratio} exceeding
20
+ the threshold. See methods L{Fsum.RESIDUAL}, L{Fsum.pow}, L{Fsum.__ipow__}
21
+ and L{Fsum.__itruediv__}.
24
22
  '''
25
23
  # make sure int/int division yields float quotient, see .basics
26
24
  from __future__ import division as _; del _ # PYCHOK semicolon
27
25
 
28
- from pygeodesy.basics import iscomplex, isint, isscalar, itemsorted, \
26
+ from pygeodesy.basics import isbool, iscomplex, isint, isscalar, itemsorted, \
29
27
  signOf, _signOf
30
28
  from pygeodesy.constants import INT0, _isfinite, NEG0, _pos_self, \
31
29
  _0_0, _1_0, _N_1_0, Float, Int
32
- from pygeodesy.errors import _AssertionError, _OverflowError, _TypeError, \
33
- _ValueError, _xError, _xError2, _xkwds_get, \
34
- _ZeroDivisionError
35
- from pygeodesy.interns import NN, _arg_, _COMMASPACE_, _DASH_, _DOT_, _EQUAL_, \
36
- _exceeds_, _from_, _iadd_op_, _LANGLE_, _negative_, \
37
- _NOTEQUAL_, _not_finite_, _PERCENT_, _PLUS_, _R_, \
38
- _RANGLE_, _SLASH_, _SPACE_, _STAR_, _UNDER_
30
+ from pygeodesy.errors import _OverflowError, _TypeError, _ValueError, \
31
+ _xError, _xError2, _xkwds_get
32
+ from pygeodesy.interns import NN, _arg_, _COMMASPACE_, _DASH_, _DOT_, \
33
+ _enquote, _EQUAL_, _from_, _LANGLE_, _NOTEQUAL_, \
34
+ _not_finite_, _PERCENT_, _PLUS_, _RANGLE_, \
35
+ _SLASH_, _SPACE_, _STAR_, _UNDER_
39
36
  from pygeodesy.lazily import _ALL_LAZY, _getenv, _sys_version_info2
40
- from pygeodesy.named import _Named, _NamedTuple, _NotImplemented, Fmt, unstr
37
+ from pygeodesy.named import _Named, _NamedTuple, _NotImplemented
41
38
  from pygeodesy.props import _allPropertiesOf_n, deprecated_property_RO, \
42
39
  Property_RO, property_RO
43
- # from pygeodesy.streprs import Fmt, unstr # from .named
40
+ from pygeodesy.streprs import Fmt, fstr, unstr
44
41
  # from pygeodesy.units import Float, Int # from .constants
45
42
 
46
43
  from math import ceil as _ceil, fabs, floor as _floor # PYCHOK used! .ltp
47
44
 
48
45
  __all__ = _ALL_LAZY.fsums
49
- __version__ = '24.04.24'
50
-
51
- _add_op_ = _PLUS_ # in .auxilats.auxAngle
52
- _eq_op_ = _EQUAL_ * 2 # _DEQUAL_
53
- _COMMASPACE_R_ = _COMMASPACE_ + _R_
54
- _div_ = 'div'
55
- _exceeds_R_ = _SPACE_ + _exceeds_(_R_)
56
- _floordiv_op_ = _SLASH_ * 2 # _DSLASH_
57
- _fset_op_ = _EQUAL_
58
- _ge_op_ = _RANGLE_ + _EQUAL_
59
- _gt_op_ = _RANGLE_
60
- _integer_ = 'integer'
61
- _le_op_ = _LANGLE_ + _EQUAL_
62
- _lt_op_ = _LANGLE_
63
- _mod_ = 'mod'
64
- _mod_op_ = _PERCENT_
65
- _mul_op_ = _STAR_
66
- _ne_op_ = _NOTEQUAL_
67
- _non_zero_ = 'non-zero'
68
- _pow_op_ = _STAR_ * 2 # _DSTAR_, in .fmath
69
- _sub_op_ = _DASH_ # in .auxilats.auxAngle, .fsums
70
- _truediv_op_ = _SLASH_
71
- _divmod_op_ = _floordiv_op_ + _mod_op_
72
- _isub_op_ = _sub_op_ + _fset_op_ # in .auxilats.auxAngle, .fsums
46
+ __version__ = '24.05.06'
47
+
48
+ _abs = abs
49
+ _add_op_ = _PLUS_ # in .auxilats.auxAngle
50
+ _eq_op_ = _EQUAL_ * 2 # _DEQUAL_
51
+ _div_ = 'div'
52
+ _Float = float # in .fstats
53
+ _floordiv_op_ = _SLASH_ * 2 # _DSLASH_
54
+ _fset_op_ = _EQUAL_
55
+ _ge_op_ = _RANGLE_ + _EQUAL_
56
+ _gt_op_ = _RANGLE_
57
+ _iadd_op_ = _add_op_ + _EQUAL_ # in .auxilats.auxAngle, .fstats
58
+ _integer_ = 'integer'
59
+ _isAn = isinstance # in .fstats
60
+ _le_op_ = _LANGLE_ + _EQUAL_
61
+ _len = len
62
+ _List = list
63
+ _lt_op_ = _LANGLE_
64
+ _mod_ = 'mod'
65
+ _mod_op_ = _PERCENT_
66
+ _mul_op_ = _STAR_
67
+ _ne_op_ = _NOTEQUAL_
68
+ _non_zero_ = 'non-zero'
69
+ _pow_op_ = _STAR_ * 2 # _DSTAR_
70
+ _significant_ = 'significant'
71
+ _sub_op_ = _DASH_ # in .auxilats.auxAngle
72
+ _threshold_ = 'threshold'
73
+ _truediv_op_ = _SLASH_
74
+ _Tuple = tuple
75
+ _divmod_op_ = _floordiv_op_ + _mod_op_
76
+ _isub_op_ = _sub_op_ + _fset_op_ # in .auxilats.auxAngle
73
77
 
74
78
 
75
79
  def _2delta(*ab):
@@ -79,11 +83,11 @@ def _2delta(*ab):
79
83
  a, b = _2sum(*ab)
80
84
  except _OverflowError:
81
85
  a, b = ab
82
- return float(a if fabs(a) > fabs(b) else b)
86
+ return _Float(a if fabs(a) > fabs(b) else b)
83
87
 
84
88
 
85
89
  def _2error(unused):
86
- '''(INTERNAL) Throw a C{not finite} exception.
90
+ '''(INTERNAL) Throw a C{not-finite} exception.
87
91
  '''
88
92
  raise ValueError(_not_finite_)
89
93
 
@@ -93,7 +97,7 @@ def _2float(index=None, **name_value): # in .fmath, .fstats
93
97
  '''
94
98
  n, v = name_value.popitem() # _xkwds_item2(name_value)
95
99
  try:
96
- v = float(v)
100
+ v = _Float(v)
97
101
  return v if _isfinite(v) else _2error(v)
98
102
  except Exception as X:
99
103
  raise _xError(X, Fmt.INDEX(n, index), v)
@@ -103,16 +107,17 @@ def _X_ps(X): # for _2floats only
103
107
  return X._ps
104
108
 
105
109
 
106
- def _2floats(xs, origin=0, _X=_X_ps, _x=float):
110
+ def _2floats(xs, origin=0, _X=_X_ps, _x=_Float):
107
111
  '''(INTERNAL) Yield each B{C{xs}} as a C{float}.
108
112
  '''
109
113
  try:
110
114
  i, x = origin, None
111
115
  _fin = _isfinite
112
- _Fs = Fsum
116
+ _FsT = _Fsum_Fsum2Tuple_types
117
+ _is = _isAn
113
118
  for x in xs:
114
- if isinstance(x, _Fs):
115
- for p in _X(x):
119
+ if _is(x, _FsT):
120
+ for p in _X(x._Fsum):
116
121
  yield p
117
122
  else:
118
123
  f = _x(x)
@@ -146,15 +151,27 @@ def _2halfeven(s, r, p):
146
151
  return s
147
152
 
148
153
 
149
- def _1_over(x, op=_truediv_op_, **raiser):
150
- '''(INTERNAL) Return C{Fsum(1) /= B{x}}.
154
+ def _isFsum(x): # in .fmath
155
+ '''(INTERNAL) Is C{x} an C{Fsum} instance?
156
+ '''
157
+ return _isAn(x, Fsum)
158
+
159
+
160
+ def _isFsumTuple(x): # in .fmath
161
+ '''(INTERNAL) Is C{x} an C{Fsum} or C{Fsum2Tuple} instance?
162
+ '''
163
+ return _isAn(x, _Fsum_Fsum2Tuple_types)
164
+
165
+
166
+ def _1_Over(x, op, **raiser_RESIDUAL): # vs _1_over
167
+ '''(INTERNAL) Return C{Fsum(1) / B{x}}.
151
168
  '''
152
- return _Psum_(_1_0)._ftruediv(x, op, **raiser)
169
+ return _Psum_(_1_0)._ftruediv(x, op, **raiser_RESIDUAL)
153
170
 
154
171
 
155
172
  def _1primed(xs): # in .fmath
156
173
  '''(INTERNAL) 1-Primed summation of iterable C{xs}
157
- items, all I{known} to be C{finite float}.
174
+ items, all I{known} to be C{scalar}.
158
175
  '''
159
176
  yield _1_0
160
177
  for x in xs:
@@ -162,19 +179,11 @@ def _1primed(xs): # in .fmath
162
179
  yield _N_1_0
163
180
 
164
181
 
165
- def _2ps(s, r):
166
- '''(INTERNAL) Return an C{s} and C{r} pair, I{ps-ordered}.
167
- '''
168
- if fabs(s) < fabs(r):
169
- s, r = r, s
170
- return (r, s) if r else (s,) # PYCHOK types
171
-
172
-
173
182
  def _psum(ps): # PYCHOK used!
174
- '''(INTERNAL) Partials sum, updating C{ps}, I{overridden below}.
183
+ '''(INTERNAL) Partials summation, updating C{ps}.
175
184
  '''
176
- # assert isinstance(ps, list)
177
- i = len(ps) - 1
185
+ # assert _isAn(ps, _List)
186
+ i = _len(ps) - 1
178
187
  s = _0_0 if i < 0 else ps[i]
179
188
  _2s = _2sum
180
189
  while i > 0:
@@ -191,60 +200,69 @@ def _psum(ps): # PYCHOK used!
191
200
  return s
192
201
 
193
202
 
194
- def _Psum(ps, **name):
203
+ def _Psum(ps, **name_RESIDUAL):
195
204
  '''(INTERNAL) Return an C{Fsum} from I{ordered} partials C{ps}.
196
205
  '''
197
- F = Fsum(**name) if name else Fsum()
206
+ f = Fsum(**name_RESIDUAL) if name_RESIDUAL else Fsum()
198
207
  if ps:
199
- F._ps[:] = ps
200
- F._n = len(F._ps)
201
- return F
208
+ f._ps[:] = ps
209
+ f._n = _len(f._ps)
210
+ return f
202
211
 
203
212
 
204
- def _Psum_(*ps, **name):
213
+ def _Psum_(*ps, **name_RESIDUAL):
205
214
  '''(INTERNAL) Return an C{Fsum} from 1 or 2 known scalar(s) C{ps}.
206
215
  '''
207
- return _Psum(ps, **name)
216
+ return _Psum(ps, **name_RESIDUAL)
208
217
 
209
218
 
210
- def _2scalar(other, _raiser=None, **mod):
211
- '''(INTERNAL) Return B{C{other}} as C{int}, C{float} or C{as-is}.
219
+ def _2scalar2(other):
220
+ '''(INTERNAL) Return 2-tuple C{(other, r)} with C{other} as C{int},
221
+ C{float} or C{as-is} and C{r} the residual of C{as-is}.
212
222
  '''
213
- if isinstance(other, Fsum):
223
+ if _isFsumTuple(other):
214
224
  s, r = other._fint2
215
225
  if r:
216
226
  s, r = other._fprs2
217
227
  if r: # PYCHOK no cover
218
- if _raiser and _raiser(r, s):
219
- t = _stresidual(_non_zero_, r, **mod)
220
- raise ResidualError(t, txt=None)
221
228
  s = other # L{Fsum} as-is
222
229
  else:
230
+ r = 0
223
231
  s = other # C{type} as-is
224
232
  if isint(s, both=True):
225
233
  s = int(s)
226
- return s
234
+ return s, r
235
+
236
+
237
+ def _s_r(s, r):
238
+ '''(INTERNAL) Return C{(s, r)}, I{ordered}.
239
+ '''
240
+ if r:
241
+ if fabs(s) < fabs(r):
242
+ s, r = r, (s or INT0)
243
+ else:
244
+ r = INT0
245
+ return s, r
227
246
 
228
247
 
229
248
  def _strcomplex(s, *args):
230
249
  '''(INTERNAL) C{Complex} 2- or 3-arg C{pow} error as C{str}.
231
250
  '''
232
251
  c = _strcomplex.__name__[4:]
233
- n = _DASH_(len(args), _arg_)
252
+ n = _DASH_(_len(args), _arg_)
234
253
  t = unstr(pow, *args)
235
254
  return _SPACE_(c, s, _from_, n, t)
236
255
 
237
256
 
238
- def _stresidual(prefix, residual, **name_values):
239
- '''(INTERNAL) Residual error as C{str}.
257
+ def _stresidual(prefix, residual, R=0, **mod_ratio):
258
+ '''(INTERNAL) Residual error txt C{str}.
240
259
  '''
241
260
  p = _stresidual.__name__[3:]
242
261
  t = Fmt.PARENSPACED(p, Fmt(residual))
243
- for n, v in itemsorted(name_values):
244
- n = n.replace(_UNDER_, _SPACE_)
262
+ for n, v in itemsorted(mod_ratio):
245
263
  p = Fmt.PARENSPACED(n, Fmt(v))
246
264
  t = _COMMASPACE_(t, p)
247
- return _SPACE_(prefix, t)
265
+ return _SPACE_(prefix, t, Fmt.exceeds_R(R), _threshold_)
248
266
 
249
267
 
250
268
  def _2sum(a, b): # by .testFmath
@@ -260,6 +278,16 @@ def _2sum(a, b): # by .testFmath
260
278
  raise _OverflowError(u, txt=t)
261
279
 
262
280
 
281
+ def _threshold(threshold):
282
+ '''(INTERNAL) Get the L{ResidualError}s threshold.
283
+ '''
284
+ try:
285
+ t = _Float(threshold) or _0_0
286
+ return t if _isfinite(t) else _2error(t) # PYCHOK None
287
+ except Exception as x:
288
+ raise ResidualError(threshold=threshold, cause=x)
289
+
290
+
263
291
  class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
264
292
  '''Precision floating point summation and I{running} summation.
265
293
 
@@ -267,8 +295,9 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
267
295
  I{running}, precision floating point summations. Accumulation may continue after any
268
296
  intermediate, I{running} summuation.
269
297
 
270
- @note: Accumulated values may be L{Fsum} or C{scalar} instances, any C{type} having
271
- method C{__float__} to convert the C{scalar} to a single C{float}.
298
+ @note: Values may be L{Fsum}, L{Fsum2Tuple}, C{int}, C{float} or C{scalar} instances,
299
+ any C{type} having method C{__float__} to convert the C{scalar} to a single
300
+ C{float}, except C{complex}.
272
301
 
273
302
  @note: Handling of exceptions and C{inf}, C{INF}, C{nan} and C{NAN} differs from
274
303
  Python's C{math.fsum}.
@@ -280,54 +309,56 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
280
309
  file I{Modules/mathmodule.c} and the issue log U{Full precision summation
281
310
  <https://Bugs.Python.org/issue2819>}.
282
311
  '''
283
- _math_fsum = None
284
- _n = 0
312
+ _math_fsum = None
313
+ _n = 0
285
314
  # _ps = [] # partial sums
286
- # _ps_max = 0 # max(Fsum._ps_max, len(Fsum._ps))
287
- _ratio = None # see method _raiser
288
- _recursive = bool(_getenv('PYGEODESY_FSUM_RECURSIVE', NN))
289
- _RESIDUAL = max(float(_getenv('PYGEODESY_FSUM_RESIDUAL', _0_0)), _0_0)
315
+ # _ps_max = 0 # max(Fsum._ps_max, _len(Fsum._ps))
316
+ _RESIDUAL = _threshold(_getenv('PYGEODESY_FSUM_RESIDUAL', _0_0))
290
317
 
291
318
  def __init__(self, *xs, **name_RESIDUAL):
292
319
  '''New L{Fsum} for I{running} precision floating point summation.
293
320
 
294
- @arg xs: No, one or more initial values, all positional (each C{scalar}
295
- or an L{Fsum} instance).
321
+ @arg xs: No, one or more items to add (each C{scalar} or an L{Fsum}
322
+ or L{Fsum2Tuple} instance), all positional.
296
323
  @kwarg name_RESIDUAL: Optional C{B{name}=NN} for this L{Fsum} and
297
- C{B{RESIDUAL}=None} for the L{ResidualError} threshold.
324
+ the C{B{RESIDUAL}=0.0} threshold for L{ResidualError}s.
298
325
 
299
326
  @see: Methods L{Fsum.fadd} and L{Fsum.RESIDUAL}.
300
327
  '''
301
328
  if name_RESIDUAL:
302
- n = _xkwds_get(name_RESIDUAL, name=NN)
303
- if n: # set name before ...
329
+
330
+ def _n_R(name=NN, RESIDUAL=None):
331
+ return name, RESIDUAL
332
+
333
+ n, R = _n_R(**name_RESIDUAL)
334
+ if R is not None:
335
+ self.RESIDUAL(R)
336
+ if n:
304
337
  self.name = n
305
- r = _xkwds_get(name_RESIDUAL, RESIDUAL=None)
306
- if r is not None:
307
- self.RESIDUAL(r) # ... ResidualError
338
+
308
339
  self._ps = [] # [_0_0], see L{Fsum._fprs}
309
340
  if xs:
310
- self._facc(xs, origin=1, up=False)
341
+ self._facc_1(xs, up=False)
311
342
 
312
343
  def __abs__(self):
313
344
  '''Return this instance' absolute value as an L{Fsum}.
314
345
  '''
315
- s = _fsum(self._ps_1primed()) # == self._cmp_0(0, ...)
346
+ s = self.signOf() # == self._cmp_0(0)
316
347
  return (-self) if s < 0 else self._copy_2(self.__abs__)
317
348
 
318
349
  def __add__(self, other):
319
350
  '''Return C{B{self} + B{other}} as an L{Fsum}.
320
351
 
321
- @arg other: An L{Fsum} or C{scalar}.
352
+ @arg other: An L{Fsum}, L{Fsum2Tuple} or C{scalar}.
322
353
 
323
354
  @return: The sum (L{Fsum}).
324
355
 
325
- @see: Method L{Fsum.__iadd__}.
356
+ @see: Methods L{Fsum.fadd_} and L{Fsum.fadd}.
326
357
  '''
327
358
  f = self._copy_2(self.__add__)
328
359
  return f._fadd(other, _add_op_)
329
360
 
330
- def __bool__(self): # PYCHOK not special in Python 2-
361
+ def __bool__(self): # PYCHOK Python 3+
331
362
  '''Return C{True} if this instance is I{exactly} non-zero.
332
363
  '''
333
364
  s, r = self._fprs2
@@ -352,19 +383,23 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
352
383
  s = self._cmp_0(other, self.cmp.__name__)
353
384
  return _signOf(s, 0)
354
385
 
355
- cmp = __cmp__
356
-
357
- def __divmod__(self, other):
386
+ def __divmod__(self, other, **raiser_RESIDUAL):
358
387
  '''Return C{divmod(B{self}, B{other})} as a L{DivMod2Tuple}
359
388
  with quotient C{div} an C{int} in Python 3+ or C{float}
360
- in Python 2- and remainder C{mod} an L{Fsum}.
389
+ in Python 2- and remainder C{mod} an L{Fsum} instance.
361
390
 
362
- @arg other: An L{Fsum} or C{scalar} modulus.
391
+ @arg other: An L{Fsum}, L{Fsum2Tuple} or C{scalar} modulus.
392
+ @kwarg raiser_RESIDUAL: Use C{B{raiser}=False} (C{bool}) to
393
+ ignore L{ResidualError}s and C{B{RESIDUAL}=scalar}
394
+ to override the L{RESIDUAL<Fsum.RESIDUAL>}.
363
395
 
364
- @see: Method L{Fsum.__itruediv__}.
396
+ @raise ResidualError: Non-zero, significant residual or invalid
397
+ B{C{RESIDUAL}}.
398
+
399
+ @see: Method L{Fsum.fdiv}.
365
400
  '''
366
401
  f = self._copy_2(self.__divmod__)
367
- return f._fdivmod2(other, _divmod_op_)
402
+ return f._fdivmod2(other, _divmod_op_, **raiser_RESIDUAL)
368
403
 
369
404
  def __eq__(self, other):
370
405
  '''Compare this with an other instance or C{scalar}.
@@ -376,7 +411,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
376
411
 
377
412
  @see: Methods L{Fsum.fsum} and L{Fsum.int_float}.
378
413
  '''
379
- return float(self._fprs)
414
+ return _Float(self._fprs)
380
415
 
381
416
  def __floor__(self): # PYCHOK not special in Python 2-
382
417
  '''Return this instance' C{math.floor} as C{int} or C{float}.
@@ -390,7 +425,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
390
425
  def __floordiv__(self, other):
391
426
  '''Return C{B{self} // B{other}} as an L{Fsum}.
392
427
 
393
- @arg other: An L{Fsum} or C{scalar} divisor.
428
+ @arg other: An L{Fsum}, L{Fsum2Tuple} or C{scalar} divisor.
394
429
 
395
430
  @return: The C{floor} quotient (L{Fsum}).
396
431
 
@@ -421,25 +456,26 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
421
456
  def __iadd__(self, other):
422
457
  '''Apply C{B{self} += B{other}} to this instance.
423
458
 
424
- @arg other: An L{Fsum} or C{scalar} instance.
459
+ @arg other: An L{Fsum}, L{Fsum2Tuple} or C{scalar} instance.
425
460
 
426
461
  @return: This instance, updated (L{Fsum}).
427
462
 
428
463
  @raise TypeError: Invalid B{C{other}}, not
429
464
  C{scalar} nor L{Fsum}.
430
465
 
431
- @see: Methods L{Fsum.fadd} and L{Fsum.fadd_}.
466
+ @see: Methods L{Fsum.fadd_} and L{Fsum.fadd}.
432
467
  '''
433
468
  return self._fadd(other, _iadd_op_)
434
469
 
435
470
  def __ifloordiv__(self, other):
436
471
  '''Apply C{B{self} //= B{other}} to this instance.
437
472
 
438
- @arg other: An L{Fsum} or C{scalar} divisor.
473
+ @arg other: An L{Fsum}, L{Fsum2Tuple} or C{scalar} divisor.
439
474
 
440
475
  @return: This instance, updated (L{Fsum}).
441
476
 
442
- @raise ResidualError: Non-zero residual in B{C{other}}.
477
+ @raise ResidualError: Non-zero, significant residual
478
+ in B{C{other}}.
443
479
 
444
480
  @raise TypeError: Invalid B{C{other}} type.
445
481
 
@@ -458,7 +494,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
458
494
  def __imod__(self, other):
459
495
  '''Apply C{B{self} %= B{other}} to this instance.
460
496
 
461
- @arg other: An L{Fsum} or C{scalar} modulus.
497
+ @arg other: An L{Fsum}, L{Fsum2Tuple} or C{scalar} modulus.
462
498
 
463
499
  @return: This instance, updated (L{Fsum}).
464
500
 
@@ -469,7 +505,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
469
505
  def __imul__(self, other):
470
506
  '''Apply C{B{self} *= B{other}} to this instance.
471
507
 
472
- @arg other: An L{Fsum} or C{scalar} factor.
508
+ @arg other: An L{Fsum}, L{Fsum2Tuple} or C{scalar} factor.
473
509
 
474
510
  @return: This instance, updated (L{Fsum}).
475
511
 
@@ -484,9 +520,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
484
520
  def __int__(self):
485
521
  '''Return this instance as an C{int}.
486
522
 
487
- @see: Methods L{Fsum.int_float}, L{Fsum.__ceil__}
488
- and L{Fsum.__floor__} and properties
489
- L{Fsum.ceil} and L{Fsum.floor}.
523
+ @see: Method L{Fsum.int_float} and properties L{Fsum.ceil}
524
+ and L{Fsum.floor}.
490
525
  '''
491
526
  i, _ = self._fint2
492
527
  return i
@@ -496,55 +531,54 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
496
531
  # Luciano Ramalho, "Fluent Python", O'Reilly, 2nd Ed, 2022 p. 567
497
532
  return _NotImplemented(self)
498
533
 
499
- def __ipow__(self, other, *mod, **raiser): # PYCHOK 2 vs 3 args
534
+ def __ipow__(self, other, *mod, **raiser_RESIDUAL): # PYCHOK 2 vs 3 args
500
535
  '''Apply C{B{self} **= B{other}} to this instance.
501
536
 
502
- @arg other: The exponent (L{Fsum} or C{scalar}).
503
- @arg mod: Optional modulus (C{int} or C{None}) for the
504
- 3-argument C{pow(B{self}, B{other}, B{mod})}
505
- version.
506
- @kwarg raiser: Use C{B{raiser}=False} to ignore L{ResidualError}s
507
- (C{bool}), see also method L{RESIDUAL}.
537
+ @arg other: The exponent (C{scalar}, L{Fsum} or L{Fsum2Tuple}).
538
+ @arg mod: Optional modulus (C{int} or C{None}) for the 3-argument
539
+ C{pow(B{self}, B{other}, B{mod})} version.
540
+ @kwarg raiser_RESIDUAL: Use C{B{raiser}=False} (C{bool}) to
541
+ ignore L{ResidualError}s and C{B{RESIDUAL}=scalar}
542
+ to override the L{RESIDUAL<Fsum.RESIDUAL>}.
508
543
 
509
544
  @return: This instance, updated (L{Fsum}).
510
545
 
511
546
  @note: If B{C{mod}} is given, the result will be an C{integer}
512
547
  L{Fsum} in Python 3+ if this instance C{is_integer} or
513
- set to C{as_integer} if B{C{mod}} given as C{None}.
548
+ set to C{as_integer} and B{C{mod}} is given as C{None}.
514
549
 
515
550
  @raise OverflowError: Partial C{2sum} overflow.
516
551
 
517
- @raise ResidualError: Non-zero residual in B{C{other}} and
518
- env var C{PYGEODESY_FSUM_RESIDUAL}
519
- set or this instance has a non-zero
520
- residual and either B{C{mod}} is
521
- given and non-C{None} or B{C{other}}
522
- is a negative or fractional C{scalar}.
552
+ @raise ResidualError: Invalid B{C{RESIDUAL}} or the residual
553
+ is non-zero and significant and either
554
+ B{C{other}} is a fractional or negative
555
+ C{scalar} or B{C{mod}} is given and not
556
+ C{None}.
523
557
 
524
- @raise TypeError: Invalid B{C{other}} type or 3-argument
525
- C{pow} invocation failed.
558
+ @raise TypeError: Invalid B{C{other}} type or 3-argument C{pow}
559
+ invocation failed.
526
560
 
527
- @raise ValueError: If B{C{other}} is a negative C{scalar}
528
- and this instance is C{0} or B{C{other}}
529
- is a fractional C{scalar} and this
530
- instance is negative or has a non-zero
531
- residual or B{C{mod}} is given and C{0}.
561
+ @raise ValueError: If B{C{other}} is a negative C{scalar} and this
562
+ instance is C{0} or B{C{other}} is a fractional
563
+ C{scalar} and this instance is negative or has a
564
+ non-zero and significant residual or B{C{mod}}
565
+ is given as C{0}.
532
566
 
533
567
  @see: CPython function U{float_pow<https://GitHub.com/
534
568
  python/cpython/blob/main/Objects/floatobject.c>}.
535
569
  '''
536
- return self._fpow(other, _pow_op_ + _fset_op_, *mod, **raiser)
570
+ return self._fpow(other, _pow_op_ + _fset_op_, *mod, **raiser_RESIDUAL)
537
571
 
538
572
  def __isub__(self, other):
539
573
  '''Apply C{B{self} -= B{other}} to this instance.
540
574
 
541
- @arg other: An L{Fsum} or C{scalar}.
575
+ @arg other: An L{Fsum}, L{Fsum2Tuple} or C{scalar}.
542
576
 
543
577
  @return: This instance, updated (L{Fsum}).
544
578
 
545
579
  @raise TypeError: Invalid B{C{other}} type.
546
580
 
547
- @see: Method L{Fsum.fadd}.
581
+ @see: Methods L{Fsum.fsub_} and L{Fsum.fsub}.
548
582
  '''
549
583
  return self._fsub(other, _isub_op_)
550
584
 
@@ -553,19 +587,20 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
553
587
  '''
554
588
  return iter(self.partials)
555
589
 
556
- def __itruediv__(self, other, **raiser):
590
+ def __itruediv__(self, other, **raiser_RESIDUAL):
557
591
  '''Apply C{B{self} /= B{other}} to this instance.
558
592
 
559
- @arg other: An L{Fsum} or C{scalar} divisor.
560
- @kwarg raiser: Use C{B{raiser}=False} to ignore L{ResidualError}s
561
- (C{bool}), see also method L{RESIDUAL}.
593
+ @arg other: An L{Fsum}, L{Fsum2Tuple} or C{scalar} divisor.
594
+ @kwarg raiser_RESIDUAL: Use C{B{raiser}=False} (C{bool}) to
595
+ ignore L{ResidualError}s and C{B{RESIDUAL}=scalar}
596
+ to override the L{RESIDUAL<Fsum.RESIDUAL>}.
562
597
 
563
598
  @return: This instance, updated (L{Fsum}).
564
599
 
565
600
  @raise OverflowError: Partial C{2sum} overflow.
566
601
 
567
- @raise ResidualError: Non-zero residual in B{C{other}} and
568
- env var C{PYGEODESY_FSUM_RESIDUAL} set.
602
+ @raise ResidualError: Non-zero, significant residual or invalid
603
+ B{C{RESIDUAL}}.
569
604
 
570
605
  @raise TypeError: Invalid B{C{other}} type.
571
606
 
@@ -575,7 +610,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
575
610
 
576
611
  @see: Method L{Fsum.__ifloordiv__}.
577
612
  '''
578
- return self._ftruediv(other, _truediv_op_ + _fset_op_, **raiser)
613
+ return self._ftruediv(other, _truediv_op_ + _fset_op_, **raiser_RESIDUAL)
579
614
 
580
615
  def __le__(self, other):
581
616
  '''Compare this with an other instance or C{scalar}.
@@ -645,8 +680,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
645
680
  return f._fadd(self, _add_op_)
646
681
 
647
682
  def __rdivmod__(self, other):
648
- '''Return C{divmod(B{other}, B{self})} as 2-tuple C{(quotient,
649
- remainder)}.
683
+ '''Return C{divmod(B{other}, B{self})} as 2-tuple
684
+ C{(quotient, remainder)}.
650
685
 
651
686
  @see: Method L{Fsum.__divmod__}.
652
687
  '''
@@ -686,14 +721,14 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
686
721
  f = self._copy_2r(other, self.__rmul__)
687
722
  return f._fmul(self, _mul_op_)
688
723
 
689
- def __round__(self, *ndigits): # PYCHOK no cover
724
+ def __round__(self, *ndigits): # PYCHOK Python 3+
690
725
  '''Return C{round(B{self}, *B{ndigits}} as an L{Fsum}.
691
726
 
692
727
  @arg ndigits: Optional number of digits (C{int}).
693
728
  '''
729
+ f = self._copy_2(self.__round__)
694
730
  # <https://docs.Python.org/3.12/reference/datamodel.html?#object.__round__>
695
- return _Psum_(round(float(self), *ndigits), # can be C{int}
696
- name=self.__round__.__name__)
731
+ return f._fset(round(_Float(self), *ndigits)) # can be C{int}
697
732
 
698
733
  def __rpow__(self, other, *mod):
699
734
  '''Return C{B{other}**B{self}} as an L{Fsum}.
@@ -711,13 +746,13 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
711
746
  f = self._copy_2r(other, self.__rsub__)
712
747
  return f._fsub(self, _sub_op_)
713
748
 
714
- def __rtruediv__(self, other, **raiser):
749
+ def __rtruediv__(self, other, **raiser_RESIDUAL):
715
750
  '''Return C{B{other} / B{self}} as an L{Fsum}.
716
751
 
717
752
  @see: Method L{Fsum.__itruediv__}.
718
753
  '''
719
754
  f = self._copy_2r(other, self.__rtruediv__)
720
- return f._ftruediv(self, _truediv_op_, **raiser)
755
+ return f._ftruediv(self, _truediv_op_, **raiser_RESIDUAL)
721
756
 
722
757
  def __str__(self):
723
758
  '''Return the default C{str(self)}.
@@ -727,7 +762,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
727
762
  def __sub__(self, other):
728
763
  '''Return C{B{self} - B{other}} as an L{Fsum}.
729
764
 
730
- @arg other: An L{Fsum} or C{scalar}.
765
+ @arg other: An L{Fsum}, L{Fsum2Tuple} or C{scalar}.
731
766
 
732
767
  @return: The difference (L{Fsum}).
733
768
 
@@ -736,19 +771,22 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
736
771
  f = self._copy_2(self.__sub__)
737
772
  return f._fsub(other, _sub_op_)
738
773
 
739
- def __truediv__(self, other, **raiser):
774
+ def __truediv__(self, other, **raiser_RESIDUAL):
740
775
  '''Return C{B{self} / B{other}} as an L{Fsum}.
741
776
 
742
- @arg other: An L{Fsum} or C{scalar} divisor.
743
- @kwarg raiser: Use C{B{raiser}=False} to ignore L{ResidualError}s
744
- (C{bool}), see also method L{RESIDUAL}.
777
+ @arg other: An L{Fsum}, L{Fsum2Tuple} or C{scalar} divisor.
778
+ @kwarg raiser_RESIDUAL: Use C{B{raiser}=False} (C{bool}) to
779
+ ignore L{ResidualError}s and C{B{RESIDUAL}=scalar}
780
+ to override the L{RESIDUAL<Fsum.RESIDUAL>}.
745
781
 
746
782
  @return: The quotient (L{Fsum}).
747
783
 
784
+ @raise ResidualError: Non-zero, significant residual or invalid
785
+ B{C{RESIDUAL}}.
786
+
748
787
  @see: Method L{Fsum.__itruediv__}.
749
788
  '''
750
- f = self._copy_2(self.__truediv__)
751
- return f._ftruediv(other, _truediv_op_, **raiser)
789
+ return self._truediv(other, _truediv_op_, **raiser_RESIDUAL)
752
790
 
753
791
  __trunc__ = __int__
754
792
 
@@ -763,14 +801,15 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
763
801
  def as_integer_ratio(self):
764
802
  '''Return this instance as the ratio of 2 integers.
765
803
 
766
- @return: 2-Tuple C{(numerator, denominator)} both
767
- C{int} and with positive C{denominator}.
804
+ @return: 2-Tuple C{(numerator, denominator)} both C{int}
805
+ with C{numerator} signed and C{denominator}
806
+ non-zero, positive.
768
807
 
769
- @see: Standard C{float.as_integer_ratio} in Python 3+.
808
+ @see: Standard C{float.as_integer_ratio} in Python 2.7+.
770
809
  '''
771
810
  n, r = self._fint2
772
811
  if r:
773
- i, d = r.as_integer_ratio()
812
+ i, d = _Float(r).as_integer_ratio()
774
813
  n *= d
775
814
  n += i
776
815
  else: # PYCHOK no cover
@@ -779,17 +818,18 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
779
818
 
780
819
  @property_RO
781
820
  def as_iscalar(self):
782
- '''Get this instance I{as-is} (L{Fsum}) or C{scalar} iff scalar.
821
+ '''Get this instance I{as-is} (L{Fsum} or C{scalar}), the
822
+ latter only if the C{residual} equals C{zero}.
783
823
  '''
784
824
  s, r = self._fprs2
785
825
  return self if r else s
786
826
 
787
827
  @property_RO
788
828
  def ceil(self):
789
- '''Get this instance' C{ceil} value (C{int} in Python 3+,
790
- but C{float} in Python 2-).
829
+ '''Get this instance' C{ceil} value (C{int} in Python 3+, but
830
+ C{float} in Python 2-).
791
831
 
792
- @note: The C{ceil} takes the C{residual} into account.
832
+ @note: This C{ceil} takes the C{residual} into account.
793
833
 
794
834
  @see: Method L{Fsum.int_float} and properties L{Fsum.floor},
795
835
  L{Fsum.imag} and L{Fsum.real}.
@@ -800,16 +840,17 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
800
840
  c += 1
801
841
  return c
802
842
 
843
+ cmp = __cmp__
844
+
803
845
  def _cmp_0(self, other, op):
804
846
  '''(INTERNAL) Return C{scalar(self - B{other})} for 0-comparison.
805
847
  '''
806
- if isinstance(other, Fsum):
807
- s = _fsum(self._ps_1primed(*other._ps))
848
+ if _isFsumTuple(other):
849
+ s = self._ps_1sum(*other._ps)
808
850
  elif self._scalar(other, op):
809
- s = _fsum(self._ps_1primed(other))
851
+ s = self._ps_1sum(other)
810
852
  else:
811
- s, r = self._fprs2
812
- s = _signOf(s, -r)
853
+ s = self.signOf() # res=True
813
854
  return s
814
855
 
815
856
  def copy(self, deep=False, name=NN):
@@ -819,9 +860,10 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
819
860
  '''
820
861
  f = _Named.copy(self, deep=deep, name=name)
821
862
  if f._ps is self._ps:
822
- f._ps = list(self._ps) # separate list
863
+ f._ps = _List(self._ps) # separate list
823
864
  if not deep:
824
865
  f._n = 1
866
+ # assert f._Fsum is f
825
867
  return f
826
868
 
827
869
  def _copy_2(self, which, name=NN):
@@ -830,15 +872,16 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
830
872
  n = name or which.__name__
831
873
  # NOT .classof due to .Fdot(a, *b) args, etc.
832
874
  f = _Named.copy(self, deep=False, name=n)
875
+ f._ps = _List(self._ps) # separate list
833
876
  # assert f._n == self._n
834
- f._ps = list(self._ps) # separate list
877
+ # assert f._Fsum is f
835
878
  return f
836
879
 
837
880
  def _copy_2r(self, other, which):
838
881
  '''(INTERNAL) Copy for I{reverse-dyadic} operators.
839
882
  '''
840
- return other._copy_2(which) if isinstance(other, Fsum) else \
841
- Fsum(other, name=which.__name__)
883
+ return other._copy_2(which) if _isFsum(other) else \
884
+ self._copy_2(which)._fset(other)
842
885
 
843
886
  # def _copy_RESIDUAL(self, other):
844
887
  # '''(INTERNAL) Copy C{other._RESIDUAL}.
@@ -847,22 +890,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
847
890
  # if R is not Fsum._RESIDUAL:
848
891
  # self._RESIDUAL = R
849
892
 
850
- def divmod(self, other, **raiser):
851
- '''Return C{divmod(B{self}, B{other})} as 2-tuple C{(quotient,
852
- remainder)}.
853
-
854
- @arg other: An L{Fsum} or C{scalar} divisor.
855
- @kwarg raiser: Use C{B{raiser}=False} to ignore L{ResidualError}s
856
- (C{bool}), see also method L{RESIDUAL}.
857
-
858
- @return: A L{DivMod2Tuple}C{(div, mod)}, with quotient C{div}
859
- an C{int} in Python 3+ or C{float} in Python 2- and
860
- remainder C{mod} an L{Fsum} instance.
861
-
862
- @see: Method L{Fsum.__itruediv__}.
863
- '''
864
- f = self._copy_2(self.divmod)
865
- return f._fdivmod2(other, _divmod_op_, **raiser)
893
+ divmod = __divmod__
866
894
 
867
895
  def _Error(self, op, other, Error, **txt_cause):
868
896
  '''(INTERNAL) Format an B{C{Error}} for C{{self} B{op} B{other}}.
@@ -881,8 +909,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
881
909
  '''(INTERNAL) Format the caught exception C{X}.
882
910
  '''
883
911
  E, t = _xError2(X)
884
- n = unstr(self.named3, *xs[:3], _ELLIPSIS=len(xs) > 3, **kwds)
885
- return E(n, txt=t, cause=X)
912
+ u = unstr(self.named3, *xs[:3], _ELLIPSIS=_len(xs) > 3, **kwds)
913
+ return E(u, txt=t, cause=X)
886
914
 
887
915
  def _facc(self, xs, up=True, **origin_X_x):
888
916
  '''(INTERNAL) Accumulate more C{scalars} or L{Fsum}s.
@@ -890,39 +918,38 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
890
918
  if xs:
891
919
  _xs = _2floats(xs, **origin_X_x) # PYCHOK yield
892
920
  ps = self._ps
893
- ps[:] = self._ps_acc(list(ps), _xs, up=up)
921
+ ps[:] = self._ps_acc(_List(ps), _xs, up=up)
894
922
  return self
895
923
 
896
924
  def _facc_1(self, xs, **up):
897
925
  '''(INTERNAL) Accumulate 0, 1 or more C{scalars} or L{Fsum}s,
898
926
  all positional C{xs} in the caller of this method.
899
927
  '''
900
- # assert islistuple(xs)
901
- return self._fadd(xs[0], _add_op_) if len(xs) == 1 else \
928
+ return self._fadd(xs[0], _add_op_, **up) if _len(xs) == 1 else \
902
929
  self._facc(xs, origin=1, **up)
903
930
 
904
- def _facc_neg(self, xs, up=True, **origin):
931
+ def _facc_neg(self, xs, **up_origin):
905
932
  '''(INTERNAL) Accumulate more C{scalars} or L{Fsum}s, negated.
906
933
  '''
907
- if xs:
908
- def _neg(x):
909
- return -x
934
+ def _N(X):
935
+ return X._ps_neg
910
936
 
911
- _x = _2floats(xs, **origin) # PYCHOK yield
912
- ps = self._ps
913
- ps[:] = self._ps_acc(list(ps), map(_neg, _x), up=up)
914
- return self
937
+ def _n(x):
938
+ return -_Float(x)
939
+
940
+ return self._facc(xs, _X=_N, _x=_n, **up_origin)
915
941
 
916
- def _facc_power(self, power, xs, which, **raiser): # in .fmath
942
+ def _facc_power(self, power, xs, which, **raiser_RESIDUAL): # in .fmath
917
943
  '''(INTERNAL) Add each C{xs} as C{float(x**power)}.
918
944
  '''
919
945
  def _Pow4(p):
920
946
  r = 0
921
- if isinstance(p, Fsum):
947
+ if _isFsumTuple(p):
922
948
  s, r = p._fprs2
923
- if r == 0:
949
+ if r:
950
+ m = Fsum._pow
951
+ else: # scalar
924
952
  return _Pow4(s)
925
- m = Fsum._pow
926
953
  elif isint(p, both=True) and int(p) >= 0:
927
954
  p = s = int(p)
928
955
  m = Fsum._pow_int
@@ -933,73 +960,71 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
933
960
 
934
961
  _Pow, p, s, r = _Pow4(power)
935
962
  if p: # and xs:
936
- _pow = Fsum._pow_2_3
937
- _Fs = Fsum
938
- _Ps = _Psum_ # ()._fset_ps_
939
963
  op = which.__name__
940
-
941
- def _X(X):
942
- f = _Pow(X, p, power, op, **raiser)
943
- return f._ps if isinstance(f, _Fs) else (f,)
944
-
945
- def _x(x):
946
- x = float(x)
947
- X = _Ps(x)
948
- f = _pow(X, x, s, power, op, **raiser)
949
- if r:
950
- f *= _pow(X, x, r, power, op, **raiser)
964
+ _Fs = Fsum
965
+ _is = _isAn
966
+ _pow = self._pow_2_3
967
+
968
+ def _P(X):
969
+ f = _Pow(X, p, power, op, **raiser_RESIDUAL)
970
+ return f._ps if _is(f, _Fs) else (f,)
971
+
972
+ def _p(x):
973
+ x = _Float(x)
974
+ f = _pow(x, s, power, op, **raiser_RESIDUAL)
975
+ if f and r:
976
+ f *= _pow(x, r, power, op, **raiser_RESIDUAL)
951
977
  return f
952
978
 
953
- f = self._facc(xs, origin=1, _X=_X, _x=_x)
979
+ f = self._facc(xs, origin=1, _X=_P, _x=_p)
954
980
  else:
955
- f = self._facc_scalar_(float(len(xs))) # x**0 == 1
981
+ f = self._facc_scalar_(_Float(_len(xs))) # x**0 == 1
956
982
  return f
957
983
 
958
984
  def _facc_scalar(self, xs, **up):
959
985
  '''(INTERNAL) Accumulate all C{xs}, known to be scalar.
960
986
  '''
961
987
  if xs:
962
- self._ps_acc(self._ps, xs, **up)
988
+ _ = self._ps_acc(self._ps, xs, **up)
963
989
  return self
964
990
 
965
991
  def _facc_scalar_(self, *xs, **up):
966
992
  '''(INTERNAL) Accumulate all positional C{xs}, known to be scalar.
967
993
  '''
968
994
  if xs:
969
- self._ps_acc(self._ps, xs, **up)
995
+ _ = self._ps_acc(self._ps, xs, **up)
970
996
  return self
971
997
 
972
998
  # def _facc_up(self, up=True):
973
999
  # '''(INTERNAL) Update the C{partials}, by removing
974
1000
  # and re-accumulating the final C{partial}.
975
1001
  # '''
976
- # while len(self._ps) > 1:
977
- # p = self._ps.pop()
1002
+ # ps = self._ps
1003
+ # while _len(ps) > 1:
1004
+ # p = ps.pop()
978
1005
  # if p:
979
1006
  # n = self._n
980
- # self._facc_scalar_(p, up=False)
1007
+ # _ = self._ps_acc(ps, (p,), up=False)
981
1008
  # self._n = n
982
1009
  # break
983
- # return self._update() if up else self # ._fpsqz()
1010
+ # return self._update() if up else self
984
1011
 
985
1012
  def fadd(self, xs=()):
986
- '''Add an iterable of C{scalar} or L{Fsum} instances
987
- to this instance.
1013
+ '''Add an iterable's items to this instance.
988
1014
 
989
- @arg xs: Iterable, list, tuple, etc. (C{scalar} or
990
- L{Fsum} instances).
1015
+ @arg xs: Iterable of items to add (each C{scalar}
1016
+ or an L{Fsum} or L{Fsum2Tuple} instance).
991
1017
 
992
1018
  @return: This instance (L{Fsum}).
993
1019
 
994
1020
  @raise OverflowError: Partial C{2sum} overflow.
995
1021
 
996
- @raise TypeError: An invalid B{C{xs}} type, not C{scalar}
997
- nor L{Fsum}.
1022
+ @raise TypeError: An invalid B{C{xs}} item.
998
1023
 
999
1024
  @raise ValueError: Invalid or non-finite B{C{xs}} value.
1000
1025
  '''
1001
- if isinstance(xs, Fsum):
1002
- self._facc_scalar(xs._ps) # tuple
1026
+ if _isFsumTuple(xs):
1027
+ self._facc_scalar(xs._ps) # _Tuple(xs._ps)
1003
1028
  elif isscalar(xs): # for backward compatibility
1004
1029
  self._facc_scalar_(_2float(x=xs)) # PYCHOK no cover
1005
1030
  elif xs: # assert isiterable(xs)
@@ -1007,46 +1032,39 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1007
1032
  return self
1008
1033
 
1009
1034
  def fadd_(self, *xs):
1010
- '''Add all positional C{scalar} or L{Fsum} instances
1011
- to this instance.
1012
-
1013
- @arg xs: Values to add (C{scalar} or L{Fsum} instances),
1014
- all positional.
1035
+ '''Add all positional items to this instance.
1015
1036
 
1016
- @return: This instance (L{Fsum}).
1017
-
1018
- @raise OverflowError: Partial C{2sum} overflow.
1037
+ @arg xs: Values to add (each C{scalar} or an L{Fsum}
1038
+ or L{Fsum2Tuple} instance), all positional.
1019
1039
 
1020
- @raise TypeError: An invalid B{C{xs}} type, not C{scalar}
1021
- nor L{Fsum}.
1022
-
1023
- @raise ValueError: Invalid or non-finite B{C{xs}} value.
1040
+ @see: Method L{Fsum.fadd} for further details.
1024
1041
  '''
1025
1042
  return self._facc_1(xs)
1026
1043
 
1027
1044
  def _fadd(self, other, op, **up): # in .fmath.Fhorner
1028
1045
  '''(INTERNAL) Apply C{B{self} += B{other}}.
1029
1046
  '''
1030
- if isinstance(other, Fsum):
1031
- self._facc_scalar(other._ps, **up) # tuple
1047
+ if not self._ps: # new Fsum(x)
1048
+ self._fset(other, as_is=False, **up)
1049
+ elif _isFsumTuple(other):
1050
+ self._facc_scalar(other._ps, **up) # _Tuple
1032
1051
  elif self._scalar(other, op):
1033
1052
  self._facc_scalar_(other, **up)
1034
1053
  return self
1035
1054
 
1036
- fcopy = copy # for backward compatibility
1037
- fdiv = __itruediv__ # for backward compatibility
1038
- fdivmod = __divmod__ # for backward compatibility
1055
+ fcopy = copy # for backward compatibility
1056
+ fdiv = __itruediv__
1057
+ fdivmod = __divmod__
1039
1058
 
1040
- def _fdivmod2(self, other, op, **raiser):
1059
+ def _fdivmod2(self, other, op, **raiser_RESIDUAL):
1041
1060
  '''(INTERNAL) Apply C{B{self} %= B{other}} and return a L{DivMod2Tuple}.
1042
1061
  '''
1043
1062
  # result mostly follows CPython function U{float_divmod
1044
1063
  # <https://GitHub.com/python/cpython/blob/main/Objects/floatobject.c>},
1045
1064
  # but at least divmod(-3, 2) equals Cpython's result (-2, 1).
1046
- f = self._copy_2(self._fdivmod2)
1047
- q = f._ftruediv(other, op, **raiser).floor
1065
+ q = self._truediv(other, op, **raiser_RESIDUAL).floor
1048
1066
  if q: # == float // other == floor(float / other)
1049
- self -= other * q
1067
+ self -= Fsum(q) * other # NOT other * q!
1050
1068
 
1051
1069
  s = signOf(other) # make signOf(self) == signOf(other)
1052
1070
  if s and self.signOf() == -s: # PYCHOK no cover
@@ -1063,35 +1081,36 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1063
1081
  if _isfinite(other):
1064
1082
  return other
1065
1083
  raise ValueError(_not_finite_) if op is None else \
1066
- self._ValueError(op, other, txt=_not_finite_)
1084
+ self._Error(op, other, _ValueError, txt=_not_finite_)
1067
1085
 
1068
- def fint(self, raiser=True, name=NN, **RESIDUAL):
1086
+ def fint(self, name=NN, **raiser_RESIDUAL):
1069
1087
  '''Return this instance' current running sum as C{integer}.
1070
1088
 
1071
- @kwarg raiser: Use C{B{raiser}=False} to ignore L{ResidualError}s
1072
- (C{bool}), see also method L{RESIDUAL}.
1073
1089
  @kwarg name: Optional name (C{str}), overriding C{"fint"}.
1074
- @kwarg RESIDUAL: Optional threshold, overriding the current
1075
- L{RESIDUAL<Fsum.RESIDUAL>} (C{scalar}).
1090
+ @kwarg raiser_RESIDUAL: Use C{B{raiser}=False} (C{bool}) to
1091
+ ignore L{ResidualError}s and C{B{RESIDUAL}=scalar}
1092
+ to override the L{RESIDUAL<Fsum.RESIDUAL>}.
1076
1093
 
1077
- @return: The C{integer} sum (L{Fsum}) if this instance
1078
- C{is_integer} and the residual is zero or
1079
- insignificant or if C{B{raiser}=False}.
1094
+ @return: The C{integer} sum (L{Fsum}) if this instance C{is_integer}
1095
+ with a zero or insignificant I{integer} residual.
1080
1096
 
1081
- @raise ResidualError: Non-zero I{integer} residual.
1097
+ @raise ResidualError: Non-zero, significant residual or invalid
1098
+ B{C{RESIDUAL}}.
1082
1099
 
1083
- @see: Methods L{Fsum.int_float} and L{Fsum.is_integer}.
1100
+ @see: Methods L{Fsum.fint2}, L{Fsum.int_float} and L{Fsum.is_integer}.
1084
1101
  '''
1085
1102
  i, r = self._fint2
1086
- if r and raiser and self._raiser2sum(r, i, **RESIDUAL):
1087
- t = _stresidual(_integer_, r)
1088
- raise ResidualError(_integer_, i, txt=t)
1103
+ if r:
1104
+ R = self._raiser(r, i, **raiser_RESIDUAL)
1105
+ if R:
1106
+ t = _stresidual(_integer_, r, **R)
1107
+ raise ResidualError(_integer_, i, txt=t)
1089
1108
  f = self._copy_2(self.fint, name=name)
1090
1109
  return f._fset(i)
1091
1110
 
1092
1111
  def fint2(self, **name):
1093
- '''Return this instance' current running sum as C{int} and
1094
- the I{integer} residual.
1112
+ '''Return this instance' current running sum as C{int} and the
1113
+ I{integer} residual.
1095
1114
 
1096
1115
  @kwarg name: Optional name (C{str}).
1097
1116
 
@@ -1107,7 +1126,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1107
1126
  '''
1108
1127
  s, r = self._fprs2
1109
1128
  i = int(s)
1110
- r = _fsum(self._ps_1primed(i)) if r else float(s - i)
1129
+ n = _len(self._ps)
1130
+ r = self._ps_1sum(i) if r and n > 1 else _Float(s - i)
1111
1131
  return i, (r or INT0) # Fsum2Tuple?
1112
1132
 
1113
1133
  @deprecated_property_RO
@@ -1120,7 +1140,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1120
1140
  '''Get this instance' C{floor} (C{int} in Python 3+, but
1121
1141
  C{float} in Python 2-).
1122
1142
 
1123
- @note: The C{floor} takes the C{residual} into account.
1143
+ @note: This C{floor} takes the C{residual} into account.
1124
1144
 
1125
1145
  @see: Method L{Fsum.int_float} and properties L{Fsum.ceil},
1126
1146
  L{Fsum.imag} and L{Fsum.real}.
@@ -1131,63 +1151,68 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1131
1151
  f -= 1
1132
1152
  return f
1133
1153
 
1134
- # floordiv = __floordiv__ # for naming consistency
1154
+ # ffloordiv = __ifloordiv__ # for naming consistency
1155
+ # floordiv = __floordiv__ # for naming consistency
1135
1156
 
1136
- def _floordiv(self, other, op, **raiser): # rather _ffloordiv?
1157
+ def _floordiv(self, other, op, **raiser_RESIDUAL): # rather _ffloordiv?
1137
1158
  '''Apply C{B{self} //= B{other}}.
1138
1159
  '''
1139
- q = self._ftruediv(other, op, **raiser) # == self
1160
+ q = self._ftruediv(other, op, **raiser_RESIDUAL) # == self
1140
1161
  return self._fset(q.floor) # floor(q)
1141
1162
 
1142
- fmul = __imul__ # for backward compatibility
1163
+ fmul = __imul__
1143
1164
 
1144
1165
  def _fmul(self, other, op):
1145
1166
  '''(INTERNAL) Apply C{B{self} *= B{other}}.
1146
1167
  '''
1147
- if isinstance(other, Fsum):
1148
- if len(self._ps) != 1:
1168
+ if _isFsumTuple(other):
1169
+ if _len(self._ps) != 1:
1149
1170
  f = self._mul_Fsum(other, op)
1150
- elif len(other._ps) != 1: # and len(self._ps) == 1
1171
+ elif _len(other._ps) != 1: # and _len(self._ps) == 1
1151
1172
  f = other._mul_scalar(self._ps[0], op)
1152
- else: # len(other._ps) == len(self._ps) == 1
1173
+ else: # _len(other._ps) == _len(self._ps) == 1
1153
1174
  f = self._finite(self._ps[0] * other._ps[0])
1154
1175
  else:
1155
1176
  s = self._scalar(other, op)
1156
1177
  f = self._mul_scalar(s, op)
1157
- return self._fset(f) # n=len(self) + 1
1178
+ return self._fset(f) # n=_len(self) + 1
1158
1179
 
1159
- def fover(self, over, **raiser):
1180
+ def fover(self, over, **raiser_RESIDUAL):
1160
1181
  '''Apply C{B{self} /= B{over}} and summate.
1161
1182
 
1162
1183
  @arg over: An L{Fsum} or C{scalar} denominator.
1163
- @kwarg raiser: Use C{B{raiser}=False} to ignore L{ResidualError}s
1164
- (C{bool}), see also method L{RESIDUAL}.
1184
+ @kwarg raiser_RESIDUAL: Use C{B{raiser}=False} (C{bool}) to
1185
+ ignore L{ResidualError}s and C{B{RESIDUAL}=scalar}
1186
+ to override the L{RESIDUAL<Fsum.RESIDUAL>}.
1165
1187
 
1166
1188
  @return: Precision running sum (C{float}).
1167
1189
 
1190
+ @raise ResidualError: Non-zero, significant residual or invalid
1191
+ B{C{RESIDUAL}}.
1192
+
1168
1193
  @see: Methods L{Fsum.fsum} and L{Fsum.__itruediv__}.
1169
1194
  '''
1170
- return float(self.fdiv(over, **raiser)._fprs)
1195
+ return _Float(self.fdiv(over, **raiser_RESIDUAL)._fprs)
1171
1196
 
1172
- fpow = __ipow__ # for backward compatibility
1197
+ fpow = __ipow__
1173
1198
 
1174
- def _fpow(self, other, op, *mod, **raiser):
1199
+ def _fpow(self, other, op, *mod, **raiser_RESIDUAL):
1175
1200
  '''Apply C{B{self} **= B{other}}, optional B{C{mod}} or C{None}.
1176
1201
  '''
1177
1202
  if mod:
1178
1203
  if mod[0] is not None: # == 3-arg C{pow}
1179
- f = self._pow_2_3(self, other, other, op, *mod, **raiser)
1204
+ f = self._pow_2_3(self, other, other, op, *mod, **raiser_RESIDUAL)
1180
1205
  elif self.is_integer():
1181
1206
  # return an exact C{int} for C{int}**C{int}
1182
1207
  i, _ = self._fint2 # assert _ == 0
1183
- x = _2scalar(other) # C{int}, C{float} or other
1184
- f = self._pow_2_3(i, x, other, op, **raiser) if isscalar(x) else \
1185
- _Psum_(i)._pow( x, other, op, **raiser) # x is Fsum
1208
+ x, r = _2scalar2(other) # C{int}, C{float} or other
1209
+ f = _Psum_(i)._pow_Fsum(other, op, **raiser_RESIDUAL) if r else \
1210
+ self._pow_2_3(i, x, other, op, **raiser_RESIDUAL)
1186
1211
  else: # mod[0] is None, power(self, other)
1187
- f = self._pow(other, other, op, **raiser)
1212
+ f = self._pow(other, other, op, **raiser_RESIDUAL)
1188
1213
  else: # pow(self, other)
1189
- f = self._pow(other, other, op, **raiser)
1190
- return self._fset(f, asis=isint(f)) # n=max(len(self), 1)
1214
+ f = self._pow(other, other, op, **raiser_RESIDUAL)
1215
+ return self._fset(f, as_is=isint(f)) # n=max(_len(self), 1)
1191
1216
 
1192
1217
  @Property_RO
1193
1218
  def _fprs(self):
@@ -1204,76 +1229,70 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1204
1229
  '''(INTERNAL) Get and cache this instance' precision
1205
1230
  running sum and residual (L{Fsum2Tuple}).
1206
1231
  '''
1207
- ps = self._ps
1208
- n = len(ps) - 2
1209
- if n > 0: # len(ps) > 2
1232
+ ps = self._ps
1233
+ n = _len(ps) - 2
1234
+ if n > 0: # _len(ps) > 2
1210
1235
  s = _psum(ps)
1211
- n = len(ps) - 2
1236
+ n = _len(ps) - 2
1212
1237
  if n > 0:
1213
- r = _fsum(self._ps_1primed(s)) or INT0
1214
- return Fsum2Tuple(s, r)
1215
- if n == 0: # len(ps) == 2
1216
- ps[:] = _2ps(*_2sum(*ps))
1217
- r, s = (INT0, ps[0]) if len(ps) != 2 else ps
1218
- elif ps: # len(ps) == 1
1238
+ r = self._ps_1sum(s)
1239
+ return Fsum2Tuple(*_s_r(s, r))
1240
+ if n == 0: # _len(ps) == 2
1241
+ s, r = _s_r(*_2sum(*ps))
1242
+ ps[:] = (r, s) if r else (s,)
1243
+ elif ps: # _len(ps) == 1
1219
1244
  s, r = ps[0], INT0
1220
- else: # len(ps) == 0
1245
+ else: # _len(ps) == 0
1221
1246
  s, r = _0_0, INT0
1222
1247
  ps[:] = s,
1223
1248
  # assert self._ps is ps
1224
1249
  return Fsum2Tuple(s, r)
1225
1250
 
1226
- # def _fpsqz(self):
1227
- # '''(INTERNAL) Compress, squeeze the C{partials}.
1228
- # '''
1229
- # if len(self._ps) > 2:
1230
- # _ = self._fprs2
1231
- # return self
1232
-
1233
1251
  def fset_(self, *xs):
1234
- '''Replace this instance' value with C{xs}.
1252
+ '''Replace this instance' value with all positional items.
1235
1253
 
1236
- @arg xs: Optional, new values (C{scalar} or L{Fsum}
1237
- instances), all positional.
1254
+ @arg xs: Optional, new values (each C{scalar} or
1255
+ an L{Fsum} or L{Fsum2Tuple} instance),
1256
+ all positional.
1238
1257
 
1239
- @return: This instance (C{Fsum}).
1258
+ @return: This instance, replaced (C{Fsum}).
1240
1259
 
1241
1260
  @see: Method L{Fsum.fadd} for further details.
1242
1261
  '''
1243
- self._ps[:] = 0,
1244
- self._n = 0
1245
- return self.fadd(xs) if xs else self._update()
1262
+ f = Fsum(*xs) if xs else _0_0
1263
+ return self._fset(f)
1246
1264
 
1247
- def _fset(self, other, asis=True, n=0):
1265
+ def _fset(self, other, as_is=True, n=0, up=True):
1248
1266
  '''(INTERNAL) Overwrite this instance with an other or a C{scalar}.
1249
1267
  '''
1250
1268
  if other is self:
1251
1269
  pass # from ._fmul, ._ftruediv and ._pow_0_1
1252
- elif isinstance(other, Fsum):
1270
+ elif _isFsumTuple(other):
1253
1271
  self._ps[:] = other._ps
1254
1272
  self._n = n or other._n
1255
1273
  # self._copy_RESIDUAL(other)
1256
- # use or zap the C{Property_RO} values
1257
- Fsum._fint2._update_from(self, other)
1258
- Fsum._fprs ._update_from(self, other)
1259
- Fsum._fprs2._update_from(self, other)
1274
+ if up: # use or zap the C{Property_RO} values
1275
+ Fsum._fint2._update_from(self, other)
1276
+ Fsum._fprs ._update_from(self, other)
1277
+ Fsum._fprs2._update_from(self, other)
1260
1278
  elif isscalar(other):
1261
- s = other if asis else float(other)
1262
- i = int(s) # see ._fint2
1263
- t = i, ((s - i) or INT0)
1279
+ s = other if as_is else _Float(other)
1264
1280
  self._ps[:] = s,
1265
1281
  self._n = n or 1
1266
- # Property_ROs _fint2, _fprs and _fprs2 can't be a Property:
1267
- # Property's _fset zaps the value just set by the @setter
1268
- self.__dict__.update(_fint2=t, _fprs=s, _fprs2=Fsum2Tuple(s, INT0))
1282
+ if up:
1283
+ i = int(s) # see ._fint2
1284
+ t = i, ((s - i) or INT0)
1285
+ # Property_ROs _fint2, _fprs and _fprs2 can't be a Property:
1286
+ # Property's _fset zaps the value just set by the @setter
1287
+ self.__dict__.update(_fint2=t, _fprs=s, _fprs2=Fsum2Tuple(s, INT0))
1269
1288
  else: # PYCHOK no cover
1270
- raise self._Error(_fset_op_, other, _AssertionError)
1289
+ raise self._Error(_fset_op_, other, _TypeError)
1271
1290
  return self
1272
1291
 
1273
1292
  def _fset_ps(self, other, n=0): # in .fmath
1274
- '''(INTERNAL) Set partials from a known C{Fsum} or C{scalar}.
1293
+ '''(INTERNAL) Set partials from a known C{scalar}, L{Fsum} or L{Fsum2Tuple}.
1275
1294
  '''
1276
- if isinstance(other, Fsum):
1295
+ if _isFsumTuple(other):
1277
1296
  self._ps[:] = other._ps
1278
1297
  self._n = n or other._n
1279
1298
  else: # assert isscalar(other)
@@ -1281,57 +1300,39 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1281
1300
  self._n = n or 1
1282
1301
  return self
1283
1302
 
1284
- # def _fset_ps_(self, *xs):
1285
- # '''(INTERNAL) Set partials to all known scalar C{xs}.
1286
- # '''
1287
- # self._ps[:] = xs
1288
- # self.n = len(xs)
1289
- # return self
1290
-
1291
1303
  def fsub(self, xs=()):
1292
- '''Subtract an iterable of C{scalar} or L{Fsum} instances from
1293
- this instance.
1294
-
1295
- @arg xs: Iterable, list, tuple. etc. (C{scalar} or L{Fsum}
1296
- instances).
1297
-
1298
- @return: This instance, updated (L{Fsum}).
1304
+ '''Subtract an iterable's items from this instance.
1299
1305
 
1300
- @see: Method L{Fsum.fadd}.
1306
+ @see: Method L{Fsum.fadd} for further details.
1301
1307
  '''
1302
1308
  return self._facc_neg(xs)
1303
1309
 
1304
1310
  def fsub_(self, *xs):
1305
- '''Subtract all positional C{scalar} or L{Fsum} instances from
1306
- this instance.
1307
-
1308
- @arg xs: Values to subtract (C{scalar} or L{Fsum} instances),
1309
- all positional.
1310
-
1311
- @return: This instance, updated (L{Fsum}).
1311
+ '''Subtract all positional items from this instance.
1312
1312
 
1313
- @see: Method L{Fsum.fadd}.
1313
+ @see: Method L{Fsum.fadd_} for further details.
1314
1314
  '''
1315
- return self._fsub(xs[0], _sub_op_) if len(xs) == 1 else \
1315
+ return self._fsub(xs[0], _sub_op_) if _len(xs) == 1 else \
1316
1316
  self._facc_neg(xs, origin=1)
1317
1317
 
1318
1318
  def _fsub(self, other, op):
1319
1319
  '''(INTERNAL) Apply C{B{self} -= B{other}}.
1320
1320
  '''
1321
- if isinstance(other, Fsum):
1321
+ if _isFsumTuple(other):
1322
1322
  if other is self: # or other._fprs2 == self._fprs2:
1323
- self._fset(_0_0) # n=len(self) * 2, self -= self
1323
+ self._fset(_0_0, n=_len(self) * 2)
1324
1324
  elif other._ps:
1325
1325
  self._facc_scalar(other._ps_neg)
1326
1326
  elif self._scalar(other, op):
1327
- self._facc_scalar_(-self._finite(other, op))
1327
+ self._facc_scalar_(-other)
1328
1328
  return self
1329
1329
 
1330
1330
  def fsum(self, xs=()):
1331
- '''Add more C{scalar} or L{Fsum} instances and summate.
1331
+ '''Add an iterable's items, summate and return the
1332
+ current precision running sum.
1332
1333
 
1333
- @kwarg xs: Iterable, list, tuple, etc. (C{scalar} or
1334
- L{Fsum} instances).
1334
+ @arg xs: Iterable of items to add (each item C{scalar}
1335
+ or an L{Fsum} or L{Fsum2Tuple} instance).
1335
1336
 
1336
1337
  @return: Precision running sum (C{float} or C{int}).
1337
1338
 
@@ -1342,10 +1343,11 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1342
1343
  return self._facc(xs)._fprs
1343
1344
 
1344
1345
  def fsum_(self, *xs):
1345
- '''Add all positional C{scalar} or L{Fsum} instances and summate.
1346
+ '''Add any positional items, summate and return the
1347
+ current precision running sum.
1346
1348
 
1347
- @arg xs: Values to add (C{scalar} or L{Fsum} instances), all
1348
- positional.
1349
+ @arg xs: Items to add (each C{scalar} or an L{Fsum}
1350
+ or L{Fsum2Tuple} instance), all positional.
1349
1351
 
1350
1352
  @return: Precision running sum (C{float} or C{int}).
1351
1353
 
@@ -1353,19 +1355,34 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1353
1355
  '''
1354
1356
  return self._facc_1(xs)._fprs
1355
1357
 
1356
- def Fsum_(self, *xs):
1357
- '''Like method L{Fsum.fsum_} but returning an L{Fsum}.
1358
+ @property_RO
1359
+ def _Fsum(self): # like L{Fsum2Tuple._Fsum}, for C{_2floats}.
1360
+ return self # NOT @Property_RO, see .copy and ._copy_2
1361
+
1362
+ def Fsum_(self, *xs, **name):
1363
+ '''Like method L{Fsum.fsum_} but returning a named L{Fsum}.
1364
+
1365
+ @kwarg name: Optional name (C{str}).
1358
1366
 
1359
- @return: Current, precision running sum (L{Fsum}).
1367
+ @return: Copy of this updated instance (L{Fsum}).
1360
1368
  '''
1361
- return self._facc_1(xs)._copy_2(self.Fsum_)
1369
+ return self._facc_1(xs)._copy_2(self.Fsum_, **name)
1370
+
1371
+ def Fsum2Tuple_(self, *xs, **name):
1372
+ '''Like method L{Fsum.fsum_} but returning a named L{Fsum2Tuple}.
1373
+
1374
+ @kwarg name: Optional name (C{str}).
1375
+
1376
+ @return: Precision running sum (L{Fsum2Tuple}).
1377
+ '''
1378
+ return Fsum2Tuple(self._facc_1(xs)._fprs2, **name)
1362
1379
 
1363
1380
  def fsum2(self, xs=(), name=NN):
1364
- '''Add more C{scalar} or L{Fsum} instances and return the
1365
- current precision running sum and the C{residual}.
1381
+ '''Add an iterable's items, summate and return the
1382
+ current precision running sum I{and} the C{residual}.
1366
1383
 
1367
- @kwarg xs: Iterable, list, tuple, etc. (C{scalar} or L{Fsum}
1368
- instances).
1384
+ @arg xs: Iterable of items to add (each item C{scalar}
1385
+ or an L{Fsum} or L{Fsum2Tuple} instance).
1369
1386
  @kwarg name: Optional name (C{str}).
1370
1387
 
1371
1388
  @return: L{Fsum2Tuple}C{(fsum, residual)} with C{fsum} the
@@ -1380,11 +1397,11 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1380
1397
  return t.dup(name=name) if name else t
1381
1398
 
1382
1399
  def fsum2_(self, *xs):
1383
- '''Add any positional C{scalar} or L{Fsum} instances and return
1384
- the precision running sum and the C{differential}.
1400
+ '''Add any positional items, summate and return the current
1401
+ precision running sum and the I{differential}.
1385
1402
 
1386
- @arg xs: Values to add (C{scalar} or L{Fsum} instances), all
1387
- positional.
1403
+ @arg xs: Values to add (each C{scalar} or an L{Fsum} or
1404
+ L{Fsum2Tuple} instance), all positional.
1388
1405
 
1389
1406
  @return: 2Tuple C{(fsum, delta)} with the current, precision
1390
1407
  running C{fsum} like method L{Fsum.fsum} and C{delta},
@@ -1405,37 +1422,35 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1405
1422
  return p, _0_0
1406
1423
 
1407
1424
  def fsumf_(self, *xs):
1408
- '''Like method L{Fsum.fsum_} but only for C{B{xs}}, I{known to be scalar}.
1425
+ '''Like method L{Fsum.fsum_} iff I{all} C{B{xs}} are I{known to be scalar}.
1409
1426
  '''
1410
1427
  return self._facc_scalar(xs)._fprs
1411
1428
 
1412
1429
  def Fsumf_(self, *xs):
1413
- '''Like method L{Fsum.Fsum_} but only for C{B{xs}}, I{known to be scalar}.
1430
+ '''Like method L{Fsum.Fsum_} iff I{all} C{B{xs}} are I{known to be scalar}.
1414
1431
  '''
1415
1432
  return self._facc_scalar(xs)._copy_2(self.Fsumf_)
1416
1433
 
1417
1434
  def fsum2f_(self, *xs):
1418
- '''Like method L{Fsum.fsum2_} but only for C{B{xs}}, I{known to be scalar}.
1435
+ '''Like method L{Fsum.fsum2_} iff I{all} C{B{xs}} are I{known to be scalar}.
1419
1436
  '''
1420
1437
  return self._fsum2(xs, self._facc_scalar, origin=1)
1421
1438
 
1422
1439
  # ftruediv = __itruediv__ # for naming consistency?
1423
1440
 
1424
- def _ftruediv(self, other, op, **raiser):
1441
+ def _ftruediv(self, other, op, **raiser_RESIDUAL):
1425
1442
  '''(INTERNAL) Apply C{B{self} /= B{other}}.
1426
1443
  '''
1427
1444
  n = _1_0
1428
- if isinstance(other, Fsum):
1429
- if other is self or other == self:
1430
- return self._fset(n) # n=len(self)
1445
+ if _isFsumTuple(other):
1446
+ if other is self or self == other:
1447
+ return self._fset(n) # n=_len(self)
1431
1448
  d, r = other._fprs2
1432
1449
  if r:
1433
- if d:
1434
- if self._raiser(r, d, **raiser):
1435
- raise self._ResidualError(op, other, r)
1436
- d, n = other.as_integer_ratio()
1437
- else: # PYCHOK no cover
1438
- d = r
1450
+ R = self._raiser(r, d, **raiser_RESIDUAL)
1451
+ if R:
1452
+ raise self._ResidualError(op, other, r, **R)
1453
+ d, n = other.as_integer_ratio()
1439
1454
  else:
1440
1455
  d = self._scalar(other, op)
1441
1456
  try:
@@ -1443,43 +1458,47 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1443
1458
  except Exception as X:
1444
1459
  raise self._ErrorX(X, op, other)
1445
1460
  f = self._mul_scalar(s, _mul_op_) # handles 0, INF, NAN
1446
- return self._fset(f) # asis=False
1461
+ return self._fset(f) # as_is=False
1447
1462
 
1448
1463
  @property_RO
1449
1464
  def imag(self):
1450
1465
  '''Get the C{imaginary} part of this instance (C{0.0}, always).
1451
1466
 
1452
- @see: Properties L{Fsum.ceil}, L{Fsum.floor} and L{Fsum.real}.
1467
+ @see: Property L{Fsum.real}.
1453
1468
  '''
1454
1469
  return _0_0
1455
1470
 
1456
- def int_float(self, raiser=False, **RESIDUAL):
1471
+ def int_float(self, **raiser_RESIDUAL):
1457
1472
  '''Return this instance' current running sum as C{int} or C{float}.
1458
1473
 
1459
- @kwarg raiser: If C{True} throw a L{ResidualError} if the
1460
- residual exceeds the C{RESIDUAL} (C{bool}).
1461
- @kwarg RESIDUAL: Optional threshold, overriding the current
1462
- L{RESIDUAL<Fsum.RESIDUAL>} (C{scalar}).
1474
+ @kwarg raiser_RESIDUAL: Use C{B{raiser}=False} (C{bool}) to
1475
+ ignore L{ResidualError}s and C{B{RESIDUAL}=scalar}
1476
+ to override the L{RESIDUAL<Fsum.RESIDUAL>}.
1463
1477
 
1464
1478
  @return: This C{integer} sum if this instance C{is_integer},
1465
1479
  otherwise return the C{float} sum if the residual is
1466
- zero or insignificant or if C{B{raiser}=False}.
1480
+ zero or not significant.
1467
1481
 
1468
- @raise ResidualError: Non-zero residual and C{B{raiser}=True}.
1482
+ @raise ResidualError: Non-zero, significant residual or invalid
1483
+ B{C{RESIDUAL}}.
1469
1484
 
1470
- @see: Methods L{Fsum.fint} and L{Fsum.fint2} and property L{Fsum.as_iscalar}.
1485
+ @see: Methods L{Fsum.fint}, L{Fsum.fint2}, L{Fsum.RESIDUAL} and
1486
+ property L{Fsum.as_iscalar}.
1471
1487
  '''
1472
1488
  s, r = self._fint2
1473
1489
  if r:
1474
1490
  s, r = self._fprs2
1475
- if r and raiser and self._raiser2sum(r, s, **RESIDUAL): # PYCHOK no cover
1476
- t = _stresidual(_non_zero_, r)
1477
- raise ResidualError(int_float=s, txt=t)
1478
- s = float(s) # redundant
1491
+ if r: # PYCHOK no cover
1492
+ R = self._raiser(r, s, **raiser_RESIDUAL)
1493
+ if R:
1494
+ t = _stresidual(_non_zero_, r, **R)
1495
+ raise ResidualError(int_float=s, txt=t)
1496
+ s = _Float(s) # redundant
1479
1497
  return s
1480
1498
 
1481
1499
  def is_exact(self):
1482
- '''Is this instance' running C{fsum} considered to be exact? (C{bool}).
1500
+ '''Is this instance' running C{fsum} considered to be exact?
1501
+ (C{bool}), C{True} only if the C{residual is }L{INT0}.
1483
1502
  '''
1484
1503
  return self.residual is INT0
1485
1504
 
@@ -1505,26 +1524,38 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1505
1524
  f = Fsum._math_fsum
1506
1525
  return 2 if _psum is f else bool(f)
1507
1526
 
1508
- def is_scalar(self):
1509
- '''Is this instance' running sum C{scalar}? (C{bool}).
1527
+ def is_scalar(self, **raiser_RESIDUAL):
1528
+ '''Is this instance' running sum C{scalar} without residual or with
1529
+ a residual I{ratio} not exceeding the RESIDUAL threshold?
1510
1530
 
1511
- @see: Method L{Fsum.is_integer} and property L{Fsum.as_iscalar}.
1531
+ @kwarg raiser_RESIDUAL: Use C{B{raiser}=False} (C{bool}) to ignore
1532
+ L{ResidualError}s and C{B{RESIDUAL}=scalar} to override
1533
+ the L{RESIDUAL<Fsum.RESIDUAL>} threshold.
1534
+
1535
+ @return: C{True} if this instance' non-zero residual C{ratio} exceeds
1536
+ the L{RESIDUAL<Fsum.RESIDUAL>} threshold (C{bool}).
1537
+
1538
+ @raise ResidualError: Non-zero, significant residual or invalid
1539
+ B{C{RESIDUAL}}.
1540
+
1541
+ @see: Method L{Fsum.RESIDUAL}, L{Fsum.is_integer} and property
1542
+ L{Fsum.as_iscalar}.
1512
1543
  '''
1513
- s, r = t = self._fprs2
1514
- return False if r and _2sum(s, r) != t else True
1544
+ s, r = self._fprs2
1545
+ return False if r and self._raiser(r, s, **raiser_RESIDUAL) else True
1515
1546
 
1516
1547
  def _mul_Fsum(self, other, op=_mul_op_): # in .fmath.Fhorner
1517
- '''(INTERNAL) Return C{B{self} * Fsum B{other}} as L{Fsum} or C{0}.
1548
+ '''(INTERNAL) Return C{B{self} * B{other}} as L{Fsum} or C{0}.
1518
1549
  '''
1519
- # assert isinstance(other, Fsum)
1550
+ # assert _isFsumTuple(other)
1520
1551
  if self._ps and other._ps:
1521
- f = self._ps_mul(op, *other._ps) # NO .as_iscalar
1552
+ f = self._ps_mul(op, *other._ps) # NO .as_iscalar!
1522
1553
  else:
1523
1554
  f = _0_0
1524
1555
  return f
1525
1556
 
1526
1557
  def _mul_scalar(self, factor, op): # in .fmath.Fhorner
1527
- '''(INTERNAL) Return C{B{self} * scalar B{factor}} as L{Fsum}, C{0} or C{self}.
1558
+ '''(INTERNAL) Return C{B{self} * scalar B{factor}} as L{Fsum}, C{0.0} or C{self}.
1528
1559
  '''
1529
1560
  # assert isscalar(factor)
1530
1561
  if self._ps and self._finite(factor, op):
@@ -1545,20 +1576,24 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1545
1576
  def partials(self):
1546
1577
  '''Get this instance' current, partial sums (C{tuple} of C{float}s).
1547
1578
  '''
1548
- return tuple(self._ps)
1579
+ return _Tuple(self._ps)
1549
1580
 
1550
- def pow(self, x, *mod, **raiser):
1581
+ def pow(self, x, *mod, **raiser_RESIDUAL):
1551
1582
  '''Return C{B{self}**B{x}} as L{Fsum}.
1552
1583
 
1553
- @arg x: The exponent (L{Fsum} or C{scalar}).
1584
+ @arg x: The exponent (C{scalar} or L{Fsum}).
1554
1585
  @arg mod: Optional modulus (C{int} or C{None}) for the 3-argument
1555
1586
  C{pow(B{self}, B{other}, B{mod})} version.
1556
- @kwarg raiser: Use C{B{raiser}=False} to ignore L{ResidualError}s
1557
- (C{bool}), see also method L{RESIDUAL}.
1587
+ @kwarg raiser_RESIDUAL: Use C{B{raiser}=False} (C{bool}) to
1588
+ ignore L{ResidualError}s and C{B{RESIDUAL}=scalar}
1589
+ to override the L{RESIDUAL<Fsum.RESIDUAL>}.
1558
1590
 
1559
1591
  @return: The C{pow(self, B{x})} or C{pow(self, B{x}, *B{mod})}
1560
1592
  result (L{Fsum}).
1561
1593
 
1594
+ @raise ResidualError: Non-zero, significant residual or invalid
1595
+ B{C{RESIDUAL}}.
1596
+
1562
1597
  @note: If B{C{mod}} is given as C{None}, the result will be an
1563
1598
  C{integer} L{Fsum} provided this instance C{is_integer}
1564
1599
  or set to C{integer} by an L{Fsum.fint} call.
@@ -1567,21 +1602,16 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1567
1602
  and L{Fsum.root}.
1568
1603
  '''
1569
1604
  f = self._copy_2(self.pow)
1570
- return f._fpow(x, _pow_op_, *mod, **raiser) # f = pow(f, x, *mod)
1605
+ return f._fpow(x, _pow_op_, *mod, **raiser_RESIDUAL) # f = pow(f, x, *mod)
1571
1606
 
1572
- def _pow(self, other, unused, op, **raiser):
1607
+ def _pow(self, other, unused, op, **raiser_RESIDUAL):
1573
1608
  '''Return C{B{self} ** B{other}}.
1574
1609
  '''
1575
- if isinstance(other, Fsum):
1576
- x, r = other._fprs2
1577
- if r and self._raiser(r, x, **raiser):
1578
- raise self._ResidualError(op, other, r)
1579
- f = self._pow_scalar(x, other, op, **raiser)
1580
- if r:
1581
- f *= self._pow_scalar(r, other, op, **raiser)
1610
+ if _isFsumTuple(other):
1611
+ f = self._pow_Fsum(other, op, **raiser_RESIDUAL)
1582
1612
  elif self._scalar(other, op):
1583
1613
  x = self._finite(other, op)
1584
- f = self._pow_scalar(x, other, op, **raiser)
1614
+ f = self._pow_scalar(x, other, op, **raiser_RESIDUAL)
1585
1615
  else:
1586
1616
  f = self._pow_0_1(0, other)
1587
1617
  return f
@@ -1591,18 +1621,25 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1591
1621
  '''
1592
1622
  return self if x else (1 if isint(other) and self.is_integer() else _1_0)
1593
1623
 
1594
- def _pow_2_3(self, b, x, other, op, *mod, **raiser):
1624
+ def _pow_2_3(self, b, x, other, op, *mod, **raiser_RESIDUAL):
1595
1625
  '''(INTERNAL) 2-arg C{pow(B{b}, scalar B{x})} and 3-arg C{pow(B{b},
1596
1626
  B{x}, int B{mod} or C{None})}, embellishing errors.
1597
1627
  '''
1628
+
1629
+ if mod: # b, x, mod all C{int}, unless C{mod} is C{None}
1630
+ m = mod[0]
1631
+ # assert _isFsumTuple(b)
1632
+
1633
+ def _s(s, r):
1634
+ R = self._raiser(r, s, **raiser_RESIDUAL)
1635
+ if R:
1636
+ raise self._ResidualError(op, other, r, mod=m, **R)
1637
+ return s
1638
+
1639
+ b = _s(*(b._fprs2 if m is None else b._fint2))
1640
+ x = _s(*_2scalar2(x))
1641
+
1598
1642
  try:
1599
- if mod: # b, x, mod all C{int}, unless C{mod} is C{None}
1600
- m = mod[0]
1601
- b, r = b._fprs2 if m is None else b._fint2
1602
- if r and self._raiser(r, b, **raiser):
1603
- t = _non_zero_ if m is None else _integer_
1604
- raise ResidualError(_stresidual(t, r, mod=m), txt=None)
1605
- x = _2scalar(x, _raiser=self._raiser, mod=m)
1606
1643
  # 0**INF == 0.0, 1**INF == 1.0, -1**2.3 == -(1**2.3)
1607
1644
  s = pow(b, x, *mod)
1608
1645
  if iscomplex(s):
@@ -1612,12 +1649,22 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1612
1649
  except Exception as X:
1613
1650
  raise self._ErrorX(X, op, other, *mod)
1614
1651
 
1615
- def _pow_int(self, x, other, op, **raiser):
1652
+ def _pow_Fsum(self, other, op, **raiser_RESIDUAL):
1653
+ '''(INTERNAL) Return C{B{self} **= B{other}} for C{_isFsumTuple(other)}.
1654
+ '''
1655
+ # assert _isFsumTuple(other)
1656
+ x, r = other._fprs2
1657
+ f = self._pow_scalar(x, other, op, **raiser_RESIDUAL)
1658
+ if f and r:
1659
+ f *= self._pow_scalar(r, other, op, **raiser_RESIDUAL)
1660
+ return f
1661
+
1662
+ def _pow_int(self, x, other, op, **raiser_RESIDUAL):
1616
1663
  '''(INTERNAL) Return C{B{self} **= B{x}} for C{int B{x} >= 0}.
1617
1664
  '''
1618
1665
  # assert isint(x) and x >= 0
1619
1666
  ps = self._ps
1620
- if len(ps) > 1:
1667
+ if _len(ps) > 1:
1621
1668
  _mul_Fsum = Fsum._mul_Fsum
1622
1669
  if x > 4:
1623
1670
  p = self
@@ -1628,61 +1675,64 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1628
1675
  if (m & 1):
1629
1676
  f = _mul_Fsum(f, p, op) # f *= p
1630
1677
  m >>= 1 # //= 2
1631
- elif x > 1: # self**2, 3 or 4
1678
+ elif x > 1: # self**2, 3, or 4
1632
1679
  f = _mul_Fsum(self, self, op)
1633
1680
  if x > 2: # self**3 or 4
1634
1681
  p = self if x < 4 else f
1635
- f = _mul_Fsum(f, p, op).as_iscalar
1682
+ f = _mul_Fsum(f, p, op)
1636
1683
  else: # self**1 or self**0 == 1 or _1_0
1637
1684
  f = self._pow_0_1(x, other)
1638
1685
  elif ps: # self._ps[0]**x
1639
- f = self._pow_2_3(ps[0], x, other, op, **raiser)
1686
+ f = self._pow_2_3(ps[0], x, other, op, **raiser_RESIDUAL)
1640
1687
  else: # PYCHOK no cover
1641
1688
  # 0**pos_int == 0, but 0**0 == 1
1642
1689
  f = 0 if x else 1
1643
1690
  return f
1644
1691
 
1645
- def _pow_scalar(self, x, other, op, **raiser):
1692
+ def _pow_scalar(self, x, other, op, **raiser_RESIDUAL):
1646
1693
  '''(INTERNAL) Return C{self**B{x}} for C{scalar B{x}}.
1647
1694
  '''
1648
1695
  s, r = self._fprs2
1649
- if isint(x, both=True):
1650
- x = int(x) # Fsum**int
1651
- y = abs(x)
1652
- if y > 1:
1653
- if r:
1654
- f = self._pow_int(y, other, op, **raiser)
1655
- if x > 0: # > 1
1656
- return f
1657
- # assert x < 0 # < -1
1658
- s, r = f._fprs2 if isinstance(f, Fsum) else (f, 0)
1659
- if r:
1660
- return _1_over(f, op, **raiser) # PYCHOK 2 args
1661
- # use **= -1 for the CPython float_pow
1662
- # error if s is zero, and not s = 1 / s
1696
+ if r:
1697
+ # assert s != 0
1698
+ if isint(x, both=True): # self**int
1699
+ x = int(x)
1700
+ y = _abs(x)
1701
+ if y > 1:
1702
+ f = self._pow_int(y, other, op, **raiser_RESIDUAL)
1703
+ if x > 0: # i.e. > 1
1704
+ return f # Fsum or scalar
1705
+ # assert x < 0 # i.e. < -1
1706
+ if _isFsum(f):
1707
+ s, r = f._fprs2
1708
+ if r:
1709
+ return _1_Over(f, op, **raiser_RESIDUAL)
1710
+ else: # scalar
1711
+ s = f
1712
+ # use s**(-1) to get the CPython
1713
+ # float_pow error iff s is zero
1663
1714
  x = -1
1664
- elif x < 0: # == -1: self**(-1) == 1 / self
1665
- if r:
1666
- return _1_over(self, op, **raiser) # PYCHOK 2 args
1667
- else: # self**1 or self**0
1668
- return self._pow_0_1(x, other) # self, 1 or 1.0
1669
- elif r: # non-zero residual**fractional
1670
- if s:
1715
+ elif x < 0: # self**(-1)
1716
+ return _1_Over(self, op, **raiser_RESIDUAL) # 1 / self
1717
+ else: # self**1 or self**0
1718
+ return self._pow_0_1(x, other) # self, 1 or 1.0
1719
+ else: # self**fractional
1720
+ R = self._raiser(r, s, **raiser_RESIDUAL)
1721
+ if R:
1722
+ raise self._ResidualError(op, other, r, **R)
1671
1723
  n, d = self.as_integer_ratio()
1672
- if abs(n) > abs(d):
1724
+ if _abs(n) > _abs(d):
1673
1725
  n, d, x = d, n, (-x)
1674
1726
  s = n / d
1675
- else:
1676
- s = r
1677
1727
  # assert isscalar(s) and isscalar(x)
1678
- return self._pow_2_3(s, x, other, op, **raiser)
1728
+ return self._pow_2_3(s, x, other, op, **raiser_RESIDUAL)
1679
1729
 
1680
1730
  def _ps_acc(self, ps, xs, up=True, **unused):
1681
- '''(INTERNAL) Accumulate all scalar C{xs} into C{ps}.
1731
+ '''(INTERNAL) Accumulate C{xs} scalars into list C{ps}.
1682
1732
  '''
1683
1733
  n = 0
1684
1734
  _2s = _2sum
1685
- for x in (tuple(xs) if xs is ps else xs):
1735
+ for x in (_Tuple(xs) if xs is ps else xs):
1686
1736
  # assert isscalar(x) and _isfinite(x)
1687
1737
  if x:
1688
1738
  i = 0
@@ -1695,17 +1745,17 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1695
1745
  n += 1
1696
1746
  if n:
1697
1747
  self._n += n
1698
- # Fsum._ps_max = max(Fsum._ps_max, len(ps))
1748
+ # Fsum._ps_max = max(Fsum._ps_max, _len(ps))
1699
1749
  if up:
1700
1750
  self._update()
1701
1751
  return ps
1702
1752
 
1703
1753
  def _ps_mul(self, op, *factors):
1704
- '''(INTERNAL) Multiply this instance' C{partials} with
1705
- each of the scalar B{C{factors}} and accumulate.
1754
+ '''(INTERNAL) Multiply this instance' C{partials} with each
1755
+ of the scalar B{C{factors}} and accumulate.
1706
1756
  '''
1707
1757
  def _pfs(ps, fs):
1708
- if len(ps) < len(fs):
1758
+ if _len(ps) < _len(fs):
1709
1759
  ps, fs = fs, ps
1710
1760
  _fin = _isfinite
1711
1761
  for f in fs:
@@ -1713,7 +1763,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1713
1763
  p *= f
1714
1764
  yield p if _fin(p) else self._finite(p, op)
1715
1765
 
1716
- return _Psum(self._ps_acc([], _pfs(self._ps, factors)))
1766
+ return _Psum(self._ps_acc([], _pfs(self._ps, factors), up=False))
1717
1767
 
1718
1768
  @property_RO
1719
1769
  def _ps_neg(self):
@@ -1722,32 +1772,33 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1722
1772
  for p in self._ps:
1723
1773
  yield -p
1724
1774
 
1725
- def _ps_1primed(self, *less):
1726
- '''(INTERNAL) Yield partials, 1-primed and subtract any C{less} scalars.
1775
+ def _ps_1sum(self, *less):
1776
+ '''(INTERNAL) Return the partials sum, 1-primed C{less} any scalars.
1727
1777
  '''
1728
- yield _1_0
1729
- for p in self._ps:
1730
- yield p
1731
- for p in less:
1732
- yield -p
1733
- yield _N_1_0
1778
+ def _1pls(ps, ls):
1779
+ yield _1_0
1780
+ for p in ps:
1781
+ yield p
1782
+ for p in ls:
1783
+ yield -p
1784
+ yield _N_1_0
1785
+
1786
+ return _fsum(_1pls(self._ps, less))
1734
1787
 
1735
1788
  def _raiser(self, r, s, raiser=True, **RESIDUAL):
1736
- '''(INTERNAL) Does ratio C{r / s} exceed the RESIDUAL threshold?
1789
+ '''(INTERNAL) Does ratio C{r / s} exceed the RESIDUAL threshold
1790
+ I{and} is residual C{r} I{non-zero} or I{significant} (for a
1791
+ negative respectively positive C{RESIDUAL} threshold)?
1737
1792
  '''
1738
- self._ratio = r = (r / s) if s else s # == 0.
1739
1793
  if r and raiser:
1740
- R = self._RESIDUAL
1794
+ t = self._RESIDUAL
1741
1795
  if RESIDUAL:
1742
- R = _xkwds_get(RESIDUAL, RESIDUAL=R)
1743
- return fabs(r) > R
1744
- return False
1745
-
1746
- def _raiser2sum(self, r, s, **raiser_RESIDUAL):
1747
- '''(INTERNAL) Does ratio C{r / s} exceed the RESIDUAL threshold
1748
- I{and} is the residual B{C{r}} significant vs sum B{C{s}}?
1749
- '''
1750
- return self._raiser(r, s, **raiser_RESIDUAL) and _2sum(s, r) != (s, r)
1796
+ t = _threshold(_xkwds_get(RESIDUAL, RESIDUAL=t))
1797
+ if t < 0 or (s + r) != s:
1798
+ q = (r / s) if s else s # == 0.
1799
+ if fabs(q) > fabs(t):
1800
+ return dict(ratio=q, R=t)
1801
+ return {}
1751
1802
 
1752
1803
  @property_RO
1753
1804
  def real(self):
@@ -1757,14 +1808,14 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1757
1808
  and properties L{Fsum.ceil}, L{Fsum.floor},
1758
1809
  L{Fsum.imag} and L{Fsum.residual}.
1759
1810
  '''
1760
- return float(self._fprs)
1811
+ return _Float(self._fprs)
1761
1812
 
1762
1813
  @property_RO
1763
1814
  def residual(self):
1764
- '''Get this instance' residual (C{float} or C{int}), the
1815
+ '''Get this instance' residual (C{float} or C{int}): the
1765
1816
  C{sum(partials)} less the precision running sum C{fsum}.
1766
1817
 
1767
- @note: If the C{residual is INT0}, the precision running
1818
+ @note: The C{residual is INT0} iff the precision running
1768
1819
  C{fsum} is considered to be I{exact}.
1769
1820
 
1770
1821
  @see: Methods L{Fsum.fsum}, L{Fsum.fsum2} and L{Fsum.is_exact}.
@@ -1783,52 +1834,59 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1783
1834
 
1784
1835
  @return: The previous C{RESIDUAL} setting (C{float}), default C{0.0}.
1785
1836
 
1786
- @raise ValueError: Negative B{C{threshold}}.
1837
+ @raise ResidualError: Invalid B{C{threshold}}.
1787
1838
 
1788
- @note: L{ResidualError}s will be thrown if the non-zero I{ratio}
1789
- C{residual / fsum} exceeds the B{C{threshold}}.
1839
+ @note: L{ResidualError}s may be thrown if the non-zero I{ratio}
1840
+ C{residual / fsum} exceeds the given B{C{threshold}} and
1841
+ if the C{residual} is non-zero and I{significant} vs the
1842
+ C{fsum}, i.e. C{(fsum + residual) != fsum} and if optional
1843
+ keyword argument C{raiser=False} is missing. Specify a
1844
+ negative B{C{threshold}} for only non-zero C{residual}
1845
+ testing without I{significant}.
1790
1846
  '''
1791
1847
  r = self._RESIDUAL
1792
1848
  if threshold:
1793
1849
  t = threshold[0]
1794
- t = Fsum._RESIDUAL if t is None else (
1795
- float(t) if isscalar(t) else ( # for backward ...
1796
- _0_0 if bool(t) else _1_0)) # ... compatibility
1797
- if t < 0:
1798
- u = _DOT_(self, unstr(self.RESIDUAL, *threshold))
1799
- raise _ValueError(u, RESIDUAL=t, txt=_negative_)
1800
- self._RESIDUAL = t
1850
+ self._RESIDUAL = Fsum._RESIDUAL if t is None else ( # for ...
1851
+ (_0_0 if t else _1_0) if isbool(t) else
1852
+ _threshold(t)) # ... backward compatibility
1801
1853
  return r
1802
1854
 
1803
- def _ResidualError(self, op, other, residual):
1855
+ def _ResidualError(self, op, other, residual, **mod_R):
1804
1856
  '''(INTERNAL) Non-zero B{C{residual}} etc.
1805
1857
  '''
1806
- t = _stresidual(_non_zero_, residual, ratio=self._ratio,
1807
- RESIDUAL=self._RESIDUAL)
1808
- t = t.replace(_COMMASPACE_R_, _exceeds_R_)
1858
+ def _p(mod=None, R=0, **unused): # ratio=0
1859
+ return (_non_zero_ if R < 0 else _significant_) \
1860
+ if mod is None else _integer_
1861
+
1862
+ t = _stresidual(_p(**mod_R), residual, **mod_R)
1809
1863
  return self._Error(op, other, ResidualError, txt=t)
1810
1864
 
1811
- def root(self, root, **raiser):
1865
+ def root(self, root, **raiser_RESIDUAL):
1812
1866
  '''Return C{B{self}**(1 / B{root})} as L{Fsum}.
1813
1867
 
1814
- @arg root: The order (C{scalar} or C{Fsum}), non-zero.
1815
- @kwarg raiser: Use C{B{raiser}=False} to ignore L{ResidualError}s
1816
- (C{bool}), see also method L{RESIDUAL}.
1868
+ @arg root: The order (C{scalar} or L{Fsum}), non-zero.
1869
+ @kwarg raiser_RESIDUAL: Use C{B{raiser}=False} (C{bool}) to
1870
+ ignore L{ResidualError}s and C{B{RESIDUAL}=scalar}
1871
+ to override the L{RESIDUAL<Fsum.RESIDUAL>}.
1817
1872
 
1818
1873
  @return: The C{self ** (1 / B{root})} result (L{Fsum}).
1819
1874
 
1875
+ @raise ResidualError: Non-zero, significant residual or invalid
1876
+ B{C{RESIDUAL}}.
1877
+
1820
1878
  @see: Method L{Fsum.pow}.
1821
1879
  '''
1822
- x = _1_over(root, **raiser)
1880
+ x = _1_Over(root, _truediv_op_, **raiser_RESIDUAL)
1823
1881
  f = self._copy_2(self.root)
1824
- return f._fpow(x, f.name, **raiser) # == pow(f, x)
1882
+ return f._fpow(x, f.name, **raiser_RESIDUAL) # == pow(f, x)
1825
1883
 
1826
1884
  def _scalar(self, other, op, **txt):
1827
1885
  '''(INTERNAL) Return scalar C{other}.
1828
1886
  '''
1829
1887
  if isscalar(other):
1830
1888
  return other
1831
- raise self._TypeError(op, other, **txt) # _invalid_
1889
+ raise self._Error(op, other, _TypeError, **txt) # _invalid_
1832
1890
 
1833
1891
  def signOf(self, res=True):
1834
1892
  '''Determine the sign of this instance.
@@ -1839,44 +1897,41 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1839
1897
  @return: The sign (C{int}, -1, 0 or +1).
1840
1898
  '''
1841
1899
  s, r = self._fprs2
1842
- return _signOf(s, (-r) if res else 0)
1900
+ r = (-r) if res else 0
1901
+ return _signOf(s, r)
1843
1902
 
1844
- def toRepr(self, **prec_sep_fmt_lenc): # PYCHOK signature
1903
+ def toRepr(self, **lenc_prec_sep_fmt): # PYCHOK signature
1845
1904
  '''Return this C{Fsum} instance as representation.
1846
1905
 
1847
- @kwarg prec_sep_fmt_lenc: Optional keyword arguments for
1848
- method L{Fsum2Tuple.toRepr} plus C{B{lenc}=True}
1849
- (C{bool}) to in-/exclude the current C{[len]}
1850
- of this L{Fsum} enclosed in I{[brackets]}.
1906
+ @kwarg lenc_prec_sep_fmt: Optional keyword arguments
1907
+ for method L{Fsum.toStr}.
1851
1908
 
1852
1909
  @return: This instance (C{repr}).
1853
1910
  '''
1854
- return self._toT(self._fprs2.toRepr, **prec_sep_fmt_lenc)
1911
+ return Fmt.repr_at(self, self.toStr(**lenc_prec_sep_fmt))
1855
1912
 
1856
- def toStr(self, **prec_sep_fmt_lenc): # PYCHOK signature
1913
+ def toStr(self, lenc=True, **prec_sep_fmt): # PYCHOK signature
1857
1914
  '''Return this C{Fsum} instance as string.
1858
1915
 
1859
- @kwarg prec_sep_fmt_lenc: Optional keyword arguments for
1860
- method L{Fsum2Tuple.toStr} plus C{B{lenc}=True}
1861
- (C{bool}) to in-/exclude the current C{[len]}
1862
- of this L{Fsum} enclosed in I{[brackets]}.
1916
+ @kwarg lenc: If C{True} include the current C{[len]} of this
1917
+ L{Fsum} enclosed in I{[brackets]} (C{bool}).
1918
+ @kwarg prec_sep_fmt: Optional keyword arguments for method
1919
+ L{Fsum2Tuple.toStr}.
1863
1920
 
1864
1921
  @return: This instance (C{str}).
1865
1922
  '''
1866
- return self._toT(self._fprs2.toStr, **prec_sep_fmt_lenc)
1867
-
1868
- def _toT(self, toT, fmt=Fmt.g, lenc=True, **kwds):
1869
- '''(INTERNAL) Helper for C{toRepr} and C{toStr}.
1870
- '''
1871
- n = self.named3
1923
+ p = self.classname
1872
1924
  if lenc:
1873
- n = Fmt.SQUARE(n, len(self))
1874
- return _SPACE_(n, toT(fmt=fmt, **kwds))
1925
+ p = Fmt.SQUARE(p, _len(self))
1926
+ n = _enquote(self.name, white=_UNDER_)
1927
+ t = self._fprs2.toStr(**prec_sep_fmt)
1928
+ return NN(p, _SPACE_, n, t)
1875
1929
 
1876
- def _TypeError(self, op, other, **txt): # PYCHOK no cover
1877
- '''(INTERNAL) Return a C{TypeError}.
1930
+ def _truediv(self, other, op, **raiser_RESIDUAL):
1931
+ '''(INTERNAL) Return C{B{self} / B{other}} as an L{Fsum}.
1878
1932
  '''
1879
- return self._Error(op, other, _TypeError, **txt)
1933
+ f = self._copy_2(self.__truediv__)
1934
+ return f._ftruediv(other, op, **raiser_RESIDUAL)
1880
1935
 
1881
1936
  def _update(self, updated=True): # see ._fset
1882
1937
  '''(INTERNAL) Zap all cached C{Property_RO} values.
@@ -1890,17 +1945,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1890
1945
  # Fsum._fprs2._update(self)
1891
1946
  return self # for .fset_
1892
1947
 
1893
- def _ValueError(self, op, other, **txt): # PYCHOK no cover
1894
- '''(INTERNAL) Return a C{ValueError}.
1895
- '''
1896
- return self._Error(op, other, _ValueError, **txt)
1897
-
1898
- def _ZeroDivisionError(self, op, other, **txt): # PYCHOK no cover
1899
- '''(INTERNAL) Return a C{ZeroDivisionError}.
1900
- '''
1901
- return self._Error(op, other, _ZeroDivisionError, **txt)
1902
-
1903
- _ROs = _allPropertiesOf_n(3, Fsum, Property_RO) # PYCHOK assert, see Fsum._fset, -._update
1948
+ _ROs = _allPropertiesOf_n(3, Fsum, Property_RO) # PYCHOK see Fsum._update
1904
1949
 
1905
1950
 
1906
1951
  def _Float_Int(arg, **name_Error):
@@ -1914,8 +1959,8 @@ class DivMod2Tuple(_NamedTuple):
1914
1959
  '''2-Tuple C{(div, mod)} with the quotient C{div} and remainder
1915
1960
  C{mod} results of a C{divmod} operation.
1916
1961
 
1917
- @note: Quotient C{div} an C{int} in Python 3+ or a C{float} in
1918
- Python 2-. Remainder C{mod} an L{Fsum} instance.
1962
+ @note: Quotient C{div} an C{int} in Python 3+ but a C{float}
1963
+ in Python 2-. Remainder C{mod} an L{Fsum} instance.
1919
1964
  '''
1920
1965
  _Names_ = (_div_, _mod_)
1921
1966
  _Units_ = (_Float_Int, Fsum)
@@ -1924,7 +1969,7 @@ class DivMod2Tuple(_NamedTuple):
1924
1969
  class Fsum2Tuple(_NamedTuple):
1925
1970
  '''2-Tuple C{(fsum, residual)} with the precision running C{fsum}
1926
1971
  and the C{residual}, the sum of the remaining partials. Each
1927
- item is either C{float} or C{int}.
1972
+ item is C{float} or C{int}.
1928
1973
 
1929
1974
  @note: If the C{residual is INT0}, the C{fsum} is considered
1930
1975
  to be I{exact}, see method L{Fsum2Tuple.is_exact}.
@@ -1932,12 +1977,70 @@ class Fsum2Tuple(_NamedTuple):
1932
1977
  _Names_ = ( Fsum.fsum.__name__, Fsum.residual.name)
1933
1978
  _Units_ = (_Float_Int, _Float_Int)
1934
1979
 
1980
+ def __abs__(self): # in .fmath
1981
+ return self._Fsum.__abs__()
1982
+
1983
+ def __bool__(self): # PYCHOK Python 3+
1984
+ return bool(self._Fsum)
1985
+
1986
+ def __eq__(self, other):
1987
+ return self._other_op(other, self.__eq__)
1988
+
1989
+ def __float__(self):
1990
+ return self._Fsum.__float__()
1991
+
1992
+ def __ge__(self, other):
1993
+ return self._other_op(other, self.__ge__)
1994
+
1995
+ def __gt__(self, other):
1996
+ return self._other_op(other, self.__gt__)
1997
+
1998
+ def __le__(self, other):
1999
+ return self._other_op(other, self.__le__)
2000
+
2001
+ def __lt__(self, other):
2002
+ return self._other_op(other, self.__lt__)
2003
+
2004
+ def __int__(self):
2005
+ return self._Fsum.__int__()
2006
+
2007
+ def __ne__(self, other):
2008
+ return self._other_op(other, self.__ne__)
2009
+
2010
+ def __neg__(self):
2011
+ return self._Fsum.__neg__()
2012
+
2013
+ __nonzero__ = __bool__ # Python 2-
2014
+
2015
+ def __pos__(self):
2016
+ return self._Fsum.__pos__()
2017
+
2018
+ def as_integer_ratio(self):
2019
+ '''Return this instance as the ratio of 2 integers.
2020
+
2021
+ @see: Method L{Fsum.as_integer_ratio} for further details.
2022
+ '''
2023
+ return self._Fsum.as_integer_ratio()
2024
+
2025
+ @property_RO
2026
+ def _fint2(self):
2027
+ return self._Fsum._fint2
2028
+
2029
+ @property_RO
2030
+ def _fprs2(self):
2031
+ return self._Fsum._fprs2
2032
+
1935
2033
  @Property_RO
1936
- def _Fsum(self):
1937
- '''(INTERNAL) Get this L{Fsum2Tuple} as an L{Fsum}.
2034
+ def _Fsum(self): # this C{Fsum2Tuple} as L{Fsum}
2035
+ s, r = _s_r(*self)
2036
+ ps = (r, s) if r else (s,)
2037
+ return _Psum(ps, name=self.name)
2038
+
2039
+ def Fsum_(self, *xs, **name_RESIDUAL):
2040
+ '''Return this C{Fsum2Tuple} as an L{Fsum} plus some C{xs}.
1938
2041
  '''
1939
- s, r = map(float, self)
1940
- return _Psum(_2ps(s, r), name=self.name)
2042
+ f = _Psum(self._Fsum._ps, **name_RESIDUAL)
2043
+ return f._facc_1(xs, up=False) if xs else f
1941
2044
 
1942
2045
  def is_exact(self):
1943
2046
  '''Is this L{Fsum2Tuple} considered to be exact? (C{bool}).
@@ -1949,10 +2052,46 @@ class Fsum2Tuple(_NamedTuple):
1949
2052
  '''
1950
2053
  return self._Fsum.is_integer()
1951
2054
 
2055
+ def _mul_scalar(self, other, op): # for Fsum._fmul
2056
+ return self._Fsum._mul_scalar(other, op)
2057
+
2058
+ @property_RO
2059
+ def _n(self):
2060
+ return self._Fsum._n
2061
+
2062
+ def _other_op(self, other, which):
2063
+ C, s = (_Tuple, self) if _isAn(other, _Tuple) else (Fsum, self._Fsum)
2064
+ return getattr(C, which.__name__)(s, other)
2065
+
2066
+ @property_RO
2067
+ def _ps(self):
2068
+ return self._Fsum._ps
2069
+
2070
+ @property_RO
2071
+ def _ps_neg(self):
2072
+ return self._Fsum._ps_neg
2073
+
2074
+ def signOf(self, **res):
2075
+ '''Like method L{Fsum.signOf}.
2076
+ '''
2077
+ return self._Fsum.signOf(**res)
2078
+
2079
+ def toStr(self, fmt=Fmt.g, **prec_sep): # PYCHOK signature
2080
+ '''Return this L{Fsum2Tuple} as string (C{str}).
2081
+
2082
+ @kwarg fmt: Optional C{float} format (C{letter}).
2083
+ @kwarg prec_sep: Optional keyword arguments for function
2084
+ L{fstr<streprs.fstr>}.
2085
+ '''
2086
+ return Fmt.PAREN(fstr(self, fmt=fmt, strepr=str, force=False, **prec_sep))
2087
+
2088
+ _Fsum_Fsum2Tuple_types = Fsum, Fsum2Tuple # PYCHOK in .fstats
2089
+
1952
2090
 
1953
2091
  class ResidualError(_ValueError):
1954
- '''Error raised for an operation involving a L{pygeodesy.sums.Fsum}
1955
- instance with a non-zero C{residual}, I{integer} or otherwise.
2092
+ '''Error raised for a division, power or root operation of
2093
+ an L{Fsum} instance with a C{residual} I{ratio} exceeding
2094
+ the L{RESIDUAL<Fsum.RESIDUAL>} threshold.
1956
2095
 
1957
2096
  @see: Module L{pygeodesy.fsums} and method L{Fsum.RESIDUAL}.
1958
2097
  '''
@@ -1969,64 +2108,59 @@ try:
1969
2108
  raise ImportError # ... use _fsum below
1970
2109
 
1971
2110
  Fsum._math_fsum = _sum = _fsum # PYCHOK exported
1972
-
1973
- if _getenv('PYGEODESY_FSUM_PARTIALS', NN) == _fsum.__name__:
1974
- _psum = _fsum # PYCHOK re-def
1975
-
1976
2111
  except ImportError:
1977
2112
  _sum = sum # Fsum(NAN) exception fall-back, in .elliptic
1978
2113
 
1979
2114
  def _fsum(xs):
1980
2115
  '''(INTERNAL) Precision summation, Python 2.5-.
1981
2116
  '''
1982
- f = Fsum()
1983
- f.name = _fsum.__name__
1984
- return f.fsum(xs)
2117
+ F = Fsum()
2118
+ F.name = _fsum.__name__
2119
+ return F._facc(xs, up=False)._fprs2.fsum
1985
2120
 
1986
2121
 
1987
2122
  def fsum(xs, floats=False):
1988
- '''Precision floating point summation based on or like Python's C{math.fsum}.
2123
+ '''Precision floating point summation based on/like Python's C{math.fsum}.
1989
2124
 
1990
- @arg xs: Iterable, list, tuple, etc. of values (C{scalar} or L{Fsum}
1991
- instances).
1992
- @kwarg floats: Use C{B{floats}=True} iff I{all} B{C{xs}} are known
1993
- to be C{float} scalars (C{bool}).
2125
+ @arg xs: Iterable of items to add (each C{scalar} or an L{Fsum} or L{Fsum2Tuple}
2126
+ instance).
2127
+ @kwarg floats: Use C{B{floats}=True} iff I{all} B{C{xs}} items are I{known to
2128
+ be scalar} (C{bool}).
1994
2129
 
1995
2130
  @return: Precision C{fsum} (C{float}).
1996
2131
 
1997
2132
  @raise OverflowError: Partial C{2sum} overflow.
1998
2133
 
1999
- @raise TypeError: Non-scalar B{C{xs}} value.
2134
+ @raise TypeError: Non-scalar B{C{xs}} item.
2000
2135
 
2001
- @raise ValueError: Invalid or non-finite B{C{xs}} value.
2136
+ @raise ValueError: Invalid or non-finite B{C{xs}} item.
2002
2137
 
2003
2138
  @note: Exception and I{non-finite} handling may differ if not based
2004
2139
  on Python's C{math.fsum}.
2005
2140
 
2006
2141
  @see: Class L{Fsum} and methods L{Fsum.fsum} and L{Fsum.fadd}.
2007
2142
  '''
2008
- return _fsum(xs if floats else _2floats(xs)) if xs else _0_0 # PYCHOK yield
2143
+ return _fsum(xs if floats is True else _2floats(xs)) if xs else _0_0 # PYCHOK yield
2009
2144
 
2010
2145
 
2011
2146
  def fsum_(*xs, **floats):
2012
- '''Precision floating point summation of all positional arguments.
2013
-
2014
- @arg xs: Values to be added (C{scalar} or L{Fsum} instances), all
2015
- positional.
2016
- @kwarg floats: Use C{B{floats}=True} iff I{all} B{C{xs}} are I{known
2017
- to be scalar} (C{bool}).
2147
+ '''Precision floating point summation of all positional items.
2018
2148
 
2019
- @return: Precision C{fsum} (C{float}).
2149
+ @arg xs: Items to add (each C{scalar} or an L{Fsum} or L{Fsum2Tuple} instance),
2150
+ all positional.
2151
+ @kwarg floats: Use C{B{floats}=True} iff I{all} B{C{xs}} items are I{known to
2152
+ be scalar} (C{bool}).
2020
2153
 
2021
- @see: Function C{fsum}.
2154
+ @see: Function L{fsum<fsums.fsum>} for further details.
2022
2155
  '''
2023
- return _fsum(xs if _xkwds_get(floats, floats=False) else
2156
+ return _fsum(xs if _xkwds_get(floats, floats=False) is True else
2024
2157
  _2floats(xs, origin=1)) if xs else _0_0 # PYCHOK yield
2025
2158
 
2026
2159
 
2027
2160
  def fsumf_(*xs):
2028
- '''Precision floating point summation, L{fsum_}C{(*B{xs}, floats=True)},
2029
- but only for C{B{xs}} I{known to be scalar}.
2161
+ '''Precision floating point summation iff I{all} C{B{xs}} items are I{known to be scalar}.
2162
+
2163
+ @see: Function L{fsum_<fsums.fsum_>} for further details.
2030
2164
  '''
2031
2165
  return _fsum(xs) if xs else _0_0
2032
2166
 
@@ -2034,44 +2168,44 @@ def fsumf_(*xs):
2034
2168
  def fsum1(xs, floats=False):
2035
2169
  '''Precision floating point summation, 1-primed.
2036
2170
 
2037
- @arg xs: Iterable, list, tuple, etc. of values (C{scalar} or L{Fsum}
2038
- instances).
2039
- @kwarg floats: Use C{B{floats}=True} iff I{all} B{C{xs}} are known
2040
- to be C{float}.
2041
-
2042
- @return: Precision C{fsum} (C{float}).
2171
+ @arg xs: Iterable of items to add (each C{scalar} or an L{Fsum} or L{Fsum2Tuple}
2172
+ instance).
2173
+ @kwarg floats: Use C{B{floats}=True} iff I{all} B{C{xs}} items are I{known to
2174
+ be scalar} (C{bool}).
2043
2175
 
2044
- @see: Function C{fsum}.
2176
+ @see: Function L{fsum<fsums.fsum>} for further details.
2045
2177
  '''
2046
- return _fsum(_1primed(xs if floats else _2floats(xs))) if xs else _0_0 # PYCHOK yield
2178
+ return _fsum(_1primed(xs if floats is True else _2floats(xs))) if xs else _0_0 # PYCHOK yield
2047
2179
 
2048
2180
 
2049
2181
  def fsum1_(*xs, **floats):
2050
- '''Precision floating point summation, 1-primed.
2051
-
2052
- @arg xs: Values to be added (C{scalar} or L{Fsum} instances), all
2053
- positional.
2054
- @kwarg floats: Use C{B{floats}=True} iff I{all} B{C{xs}} are I{known
2055
- to be scalar} (C{bool}).
2182
+ '''Precision floating point summation, 1-primed of all positional items.
2056
2183
 
2057
- @return: Precision C{fsum} (C{float}).
2184
+ @arg xs: Items to add (each C{scalar} or an L{Fsum} or L{Fsum2Tuple} instance),
2185
+ all positional.
2186
+ @kwarg floats: Use C{B{floats}=True} iff I{all} B{C{xs}} items are I{known to
2187
+ be scalar} (C{bool}).
2058
2188
 
2059
- @see: Function C{fsum}
2189
+ @see: Function L{fsum_<fsums.fsum_>} for further details.
2060
2190
  '''
2061
- return _fsum(_1primed(xs if _xkwds_get(floats, floats=False) else
2191
+ return _fsum(_1primed(xs if _xkwds_get(floats, floats=False) is True else
2062
2192
  _2floats(xs, origin=1))) if xs else _0_0 # PYCHOK yield
2063
2193
 
2064
2194
 
2065
2195
  def fsum1f_(*xs):
2066
- '''Precision floating point summation, L{fsum1_}C{(*B{xs}, floats=True)},
2067
- but only for C{B{xs}} I{known to be scalar}.
2196
+ '''Precision floating point summation iff I{all} C{B{xs}} items are I{known to be scalar}.
2197
+
2198
+ @see: Function L{fsum_<fsums.fsum_>} for further details.
2068
2199
  '''
2069
2200
  return _fsum(_1primed(xs)) if xs else _0_0
2070
2201
 
2071
2202
 
2072
2203
  if __name__ == '__main__':
2073
2204
 
2074
- # usage: [env PYGEODESY_FSUM_PARTIALS=fsum] python3 -m pygeodesy.fsums
2205
+ # usage: [env _psum=fsum] python3 -m pygeodesy.fsums
2206
+
2207
+ if _getenv(_psum.__name__, NN) == _fsum.__name__:
2208
+ _psum = _fsum
2075
2209
 
2076
2210
  def _test(n):
2077
2211
  # copied from Hettinger, see L{Fsum} reference
@@ -2083,7 +2217,7 @@ if __name__ == '__main__':
2083
2217
  F = Fsum()
2084
2218
  if F.is_math_fsum():
2085
2219
  for t in frandoms(n, seeded=True):
2086
- assert float(F.fset_(*t)) == _fsum(t)
2220
+ assert _Float(F.fset_(*t)) == _fsum(t)
2087
2221
  printf(_DOT_, end=NN)
2088
2222
  printf(NN)
2089
2223