pygeodesy 24.4.4__py2.py3-none-any.whl → 24.4.18__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
@@ -17,25 +17,24 @@ C{-1.0} and C{+1.0}, including C{INT0} if considered to be I{exact}.
17
17
  Set env variable C{PYGEODESY_FSUM_PARTIALS} to string C{"fsum"}) for summation
18
18
  of L{Fsum} partials by Python function C{math.fsum}.
19
19
 
20
- Set env variable C{PYGEODESY_FSUM_RESIDUAL} to a C{float} string greater
21
- than C{"0.0"} as the threshold to throw a L{ResidualError} in division or
22
- exponention of an L{Fsum} instance with a I{relative} C{residual} exceeding
23
- the threshold, see methods L{Fsum.RESIDUAL}, L{Fsum.pow}, L{Fsum.__ipow__}
24
- and L{Fsum.__itruediv__}.
20
+ 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__}.
25
24
  '''
26
25
  # make sure int/int division yields float quotient, see .basics
27
26
  from __future__ import division as _; del _ # PYCHOK semicolon
28
27
 
29
28
  from pygeodesy.basics import iscomplex, isint, isscalar, itemsorted, \
30
29
  signOf, _signOf
31
- from pygeodesy.constants import INT0, _isfinite, isinf, isnan, NEG0, _pos_self, \
30
+ from pygeodesy.constants import INT0, _isfinite, NEG0, _pos_self, \
32
31
  _0_0, _1_0, _N_1_0, Float, Int
33
32
  from pygeodesy.errors import _OverflowError, _TypeError, _ValueError, _xError, \
34
33
  _xError2, _xkwds_get, _ZeroDivisionError
35
34
  from pygeodesy.interns import NN, _arg_, _COMMASPACE_, _DASH_, _DOT_, _EQUAL_, \
36
35
  _exceeds_, _from_, _iadd_op_, _LANGLE_, _negative_, \
37
- _NOTEQUAL_, _not_finite_, _not_scalar_, _PERCENT_, \
38
- _PLUS_, _R_, _RANGLE_, _SLASH_, _SPACE_, _STAR_, _UNDER_
36
+ _NOTEQUAL_, _not_finite_, _PERCENT_, _PLUS_, _R_, \
37
+ _RANGLE_, _SLASH_, _SPACE_, _STAR_, _UNDER_
39
38
  from pygeodesy.lazily import _ALL_LAZY, _getenv, _sys_version_info2
40
39
  from pygeodesy.named import _Named, _NamedTuple, _NotImplemented, Fmt, unstr
41
40
  from pygeodesy.props import _allPropertiesOf_n, deprecated_property_RO, \
@@ -46,7 +45,7 @@ from pygeodesy.props import _allPropertiesOf_n, deprecated_property_RO, \
46
45
  from math import ceil as _ceil, fabs, floor as _floor # PYCHOK used! .ltp
47
46
 
48
47
  __all__ = _ALL_LAZY.fsums
49
- __version__ = '24.04.04'
48
+ __version__ = '24.04.18'
50
49
 
51
50
  _add_op_ = _PLUS_ # in .auxilats.auxAngle
52
51
  _eq_op_ = _EQUAL_ * 2 # _DEQUAL_
@@ -72,54 +71,94 @@ _divmod_op_ = _floordiv_op_ + _mod_op_
72
71
  _isub_op_ = _sub_op_ + _fset_op_ # in .auxilats.auxAngle, .fsums
73
72
 
74
73
 
74
+ def _2delta(*ab):
75
+ '''(INTERNAL) Helper for C{Fsum._fsum2}.
76
+ '''
77
+ try:
78
+ a, b = _2sum(*ab)
79
+ except _OverflowError:
80
+ a, b = ab
81
+ return float(a if fabs(a) > fabs(b) else b)
82
+
83
+
84
+ def _2error(unused):
85
+ '''(INTERNAL) Throw a C{not finite} exception.
86
+ '''
87
+ raise ValueError(_not_finite_)
88
+
89
+
75
90
  def _2float(index=None, **name_value): # in .fmath, .fstats
76
91
  '''(INTERNAL) Raise C{TypeError} or C{ValueError} if not scalar or infinite.
77
92
  '''
78
93
  n, v = name_value.popitem() # _xkwds_item2(name_value)
79
94
  try:
80
95
  v = float(v)
81
- if _isfinite(v):
82
- return v
83
- raise ValueError(_not_finite_)
96
+ return v if _isfinite(v) else _2error(v)
84
97
  except Exception as X:
85
98
  raise _xError(X, Fmt.INDEX(n, index), v)
86
99
 
87
100
 
88
- def _2floats(xs, origin=0, neg=False):
101
+ def _X_ps(X): # for _2floats only
102
+ return X._ps
103
+
104
+
105
+ def _2floats(xs, origin=0, _X=_X_ps, _x=float):
89
106
  '''(INTERNAL) Yield each B{C{xs}} as a C{float}.
90
107
  '''
91
- if neg:
92
- def _X(X):
93
- return X._ps_neg
108
+ try:
109
+ i, x = origin, None
110
+ _fin = _isfinite
111
+ _Fs = Fsum
112
+ for x in xs:
113
+ if isinstance(x, _Fs):
114
+ for p in _X(x):
115
+ yield p
116
+ else:
117
+ f = _x(x)
118
+ yield f if _fin(f) else _2error(f)
119
+ i += 1
120
+ except Exception as X:
121
+ raise _xError(X, Fmt.INDEX(xs=i), x)
94
122
 
95
- def _x(x):
96
- return -float(x)
97
- else:
98
- def _X(X): # PYCHOK re-def
99
- return X._ps
100
123
 
101
- _x = float
124
+ def _Fsumf_(*xs): # floats=True, in .auxLat, ...
125
+ '''(INTERNAL) An C{Fsum} of I{known scalars}.
126
+ '''
127
+ return Fsum()._facc_scalar(xs, up=False)
128
+
102
129
 
103
- return _2yield(xs, origin, _X, _x)
130
+ def _Fsum1f_(*xs): # floats=True, in .albers, ...
131
+ '''(INTERNAL) An C{Fsum} of I{known scalars}, 1-primed.
132
+ '''
133
+ return Fsum()._facc_scalar(_1primed(xs), up=False)
134
+
135
+
136
+ def _2halfeven(s, r, p):
137
+ '''(INTERNAL) Round half-even.
138
+ '''
139
+ if (p > 0 and r > 0) or \
140
+ (p < 0 and r < 0): # signs match
141
+ r *= 2
142
+ t = s + r
143
+ if r == (t - s):
144
+ s = t
145
+ return s
104
146
 
105
147
 
106
148
  def _1primed(xs): # in .fmath
107
- '''(INTERNAL) 1-Prime the summation of C{xs}
108
- arguments I{known} to be C{finite float}.
149
+ '''(INTERNAL) 1-Primed summation of iterable C{xs}
150
+ items, all I{known} to be C{finite float}.
109
151
  '''
110
152
  yield _1_0
111
153
  for x in xs:
112
- if x:
113
- yield x
154
+ yield x
114
155
  yield _N_1_0
115
156
 
116
157
 
117
158
  def _2ps(s, r):
118
159
  '''(INTERNAL) Return a C{s} and C{r} pair, I{ps-ordered}.
119
160
  '''
120
- if fabs(s) < fabs(r):
121
- s, r = r, s
122
- return ((r, s) if s else (r,)) if r else (s,)
161
+ return (s, r) if fabs(s) < fabs(r) else (r, s)
123
162
 
124
163
 
125
164
  def _psum(ps): # PYCHOK used!
@@ -136,20 +175,33 @@ def _psum(ps): # PYCHOK used!
136
175
  if s:
137
176
  ps[i:] = r, s
138
177
  if i > 0:
139
- p = ps[i-1] # round half-even
140
- if (p > 0 and r > 0) or \
141
- (p < 0 and r < 0): # signs match
142
- r *= 2
143
- t = s + r
144
- if r == (t - s):
145
- s = t
178
+ s = _2halfeven(s, r, ps[i-1])
146
179
  break # return s
147
180
  s = r # PYCHOK no cover
148
181
  ps[i:] = s,
149
182
  return s
150
183
 
151
184
 
152
- def _2scalar(other, _raiser=None):
185
+ def _Psum(ps, **name):
186
+ '''(INTERNAL) Return an C{Fsum} from I{ordered} partials C{ps}.
187
+ '''
188
+ F = Fsum(**name) if name else Fsum()
189
+ if ps:
190
+ F._ps[:] = ps
191
+ F._n = len(F._ps)
192
+ return F
193
+
194
+
195
+ def _Psum_1(p=_1_0, **name):
196
+ '''(INTERNAL) Return an C{Fsum} from a single partial C{p}.
197
+ '''
198
+ F = Fsum(**name) if name else Fsum()
199
+ F._ps[:] = p,
200
+ F._n = 1 # len(F._ps)
201
+ return F
202
+
203
+
204
+ def _2scalar(other, _raiser=None, **mod):
153
205
  '''(INTERNAL) Return B{C{other}} as C{int}, C{float} or C{as-is}.
154
206
  '''
155
207
  if isinstance(other, Fsum):
@@ -158,7 +210,8 @@ def _2scalar(other, _raiser=None):
158
210
  s, r = other._fprs2
159
211
  if r: # PYCHOK no cover
160
212
  if _raiser and _raiser(r, s):
161
- raise ValueError(_stresidual(_non_zero_, r))
213
+ t = _stresidual(_non_zero_, r, **mod)
214
+ raise ResidualError(t, txt=None)
162
215
  s = other # L{Fsum} as-is
163
216
  else:
164
217
  s = other # C{type} as-is
@@ -192,35 +245,13 @@ def _2sum(a, b): # by .testFmath
192
245
  '''(INTERNAL) Return C{a + b} as 2-tuple (sum, residual).
193
246
  '''
194
247
  s = a + b
195
- if not _isfinite(s):
196
- u = unstr(_2sum.__name__, a, b)
197
- t = Fmt.PARENSPACED(_not_finite_, s)
198
- raise _OverflowError(u, txt=t)
199
- if fabs(a) < fabs(b):
200
- a, b = b, a
201
- return s, (b - (s - a))
202
-
203
-
204
- def _2yield(xs, i, _X_ps, _x):
205
- '''(INTERNAL) Yield each B{C{xs}} as a C{float}.
206
- '''
207
- x = None
208
- try:
209
- _fin = _isfinite
210
- _Fs = Fsum
211
- for x in xs:
212
- if isinstance(x, _Fs):
213
- for p in _X_ps(x):
214
- yield p
215
- else:
216
- f = _x(x)
217
- if f:
218
- if not _fin(f):
219
- raise ValueError(_not_finite_)
220
- yield f
221
- i += 1
222
- except Exception as X:
223
- raise _xError(X, Fmt.INDEX(xs=i), x)
248
+ if _isfinite(s):
249
+ if fabs(a) < fabs(b):
250
+ b, a = a, b
251
+ return s, (b - (s - a))
252
+ u = unstr(_2sum, a, b)
253
+ t = Fmt.PARENSPACED(_not_finite_, s)
254
+ raise _OverflowError(u, txt=t)
224
255
 
225
256
 
226
257
  class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
@@ -246,8 +277,9 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
246
277
  _math_fsum = None
247
278
  _n = 0
248
279
  # _ps = [] # partial sums
249
- # _px = 0 # max(Fsum._px, len(Fsum._ps))
250
- _ratio = None
280
+ # _ps_max = 0 # max(Fsum._ps_max, len(Fsum._ps))
281
+ _ratio = None # see method _raiser
282
+ _recursive = bool(_getenv('PYGEODESY_FSUM_RECURSIVE', NN))
251
283
  _RESIDUAL = max(float(_getenv('PYGEODESY_FSUM_RESIDUAL', _0_0)), _0_0)
252
284
 
253
285
  def __init__(self, *xs, **name_RESIDUAL):
@@ -267,22 +299,18 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
267
299
  r = _xkwds_get(name_RESIDUAL, RESIDUAL=None)
268
300
  if r is not None:
269
301
  self.RESIDUAL(r) # ... ResidualError
270
- # self._n = 0
271
302
  self._ps = [] # [_0_0], see L{Fsum._fprs}
272
- if len(xs) > 1:
273
- self._facc(_2floats(xs, origin=1), up=False) # PYCHOK yield
274
- elif xs: # len(xs) == 1
275
- self._n = 1
276
- self._ps[:] = _2float(x=xs[0]),
303
+ if xs:
304
+ self._facc(xs, origin=1, up=False)
277
305
 
278
306
  def __abs__(self):
279
307
  '''Return this instance' absolute value as an L{Fsum}.
280
308
  '''
281
- s = _fsum(self._ps_1()) # == self._cmp_0(0, ...)
309
+ s = _fsum(self._ps_1primed()) # == self._cmp_0(0, ...)
282
310
  return (-self) if s < 0 else self._copy_2(self.__abs__)
283
311
 
284
312
  def __add__(self, other):
285
- '''Return the C{Fsum(B{self}, B{other})}.
313
+ '''Return C{B{self} + B{other}} as an L{Fsum}.
286
314
 
287
315
  @arg other: An L{Fsum} or C{scalar}.
288
316
 
@@ -338,7 +366,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
338
366
  return self._cmp_0(other, _eq_op_) == 0
339
367
 
340
368
  def __float__(self):
341
- '''Return this instance' current precision running sum as C{float}.
369
+ '''Return this instance' current, precision running sum as C{float}.
342
370
 
343
371
  @see: Methods L{Fsum.fsum} and L{Fsum.int_float}.
344
372
  '''
@@ -462,13 +490,15 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
462
490
  # Luciano Ramalho, "Fluent Python", O'Reilly, 2nd Ed, 2022 p. 567
463
491
  return _NotImplemented(self)
464
492
 
465
- def __ipow__(self, other, *mod): # PYCHOK 2 vs 3 args
493
+ def __ipow__(self, other, *mod, **raiser): # PYCHOK 2 vs 3 args
466
494
  '''Apply C{B{self} **= B{other}} to this instance.
467
495
 
468
496
  @arg other: The exponent (L{Fsum} or C{scalar}).
469
497
  @arg mod: Optional modulus (C{int} or C{None}) for the
470
498
  3-argument C{pow(B{self}, B{other}, B{mod})}
471
499
  version.
500
+ @kwarg raiser: Use C{B{raiser}=False} to ignore L{ResidualError}s
501
+ (C{bool}), see also method L{RESIDUAL}.
472
502
 
473
503
  @return: This instance, updated (L{Fsum}).
474
504
 
@@ -497,7 +527,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
497
527
  @see: CPython function U{float_pow<https://GitHub.com/
498
528
  python/cpython/blob/main/Objects/floatobject.c>}.
499
529
  '''
500
- return self._fpow(other, _pow_op_ + _fset_op_, *mod)
530
+ return self._fpow(other, _pow_op_ + _fset_op_, *mod, **raiser)
501
531
 
502
532
  def __isub__(self, other):
503
533
  '''Apply C{B{self} -= B{other}} to this instance.
@@ -517,10 +547,12 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
517
547
  '''
518
548
  return iter(self.partials)
519
549
 
520
- def __itruediv__(self, other):
550
+ def __itruediv__(self, other, **raiser):
521
551
  '''Apply C{B{self} /= B{other}} to this instance.
522
552
 
523
553
  @arg other: An L{Fsum} or C{scalar} divisor.
554
+ @kwarg raiser: Use C{B{raiser}=False} to ignore L{ResidualError}s
555
+ (C{bool}), see also method L{RESIDUAL}.
524
556
 
525
557
  @return: This instance, updated (L{Fsum}).
526
558
 
@@ -537,7 +569,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
537
569
 
538
570
  @see: Method L{Fsum.__ifloordiv__}.
539
571
  '''
540
- return self._ftruediv(other, _truediv_op_ + _fset_op_)
572
+ return self._ftruediv(other, _truediv_op_ + _fset_op_, **raiser)
541
573
 
542
574
  def __le__(self, other):
543
575
  '''Compare this with an other instance or C{scalar}.
@@ -654,8 +686,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
654
686
  @arg ndigits: Optional number of digits (C{int}).
655
687
  '''
656
688
  # <https://docs.Python.org/3.12/reference/datamodel.html?#object.__round__>
657
- return _Fsum_ps(round(float(self), *ndigits), # can be C{int}
658
- name=self.__round__.__name__)
689
+ return _Psum_1(round(float(self), *ndigits), # can be C{int}
690
+ name=self.__round__.__name__)
659
691
 
660
692
  def __rpow__(self, other, *mod):
661
693
  '''Return C{B{other}**B{self}} as an L{Fsum}.
@@ -673,13 +705,13 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
673
705
  f = self._copy_2r(other, self.__rsub__)
674
706
  return f._fsub(self, _sub_op_)
675
707
 
676
- def __rtruediv__(self, other):
708
+ def __rtruediv__(self, other, **raiser):
677
709
  '''Return C{B{other} / B{self}} as an L{Fsum}.
678
710
 
679
711
  @see: Method L{Fsum.__itruediv__}.
680
712
  '''
681
713
  f = self._copy_2r(other, self.__rtruediv__)
682
- return f._ftruediv(self, _truediv_op_)
714
+ return f._ftruediv(self, _truediv_op_, **raiser)
683
715
 
684
716
  def __str__(self):
685
717
  '''Return the default C{str(self)}.
@@ -698,17 +730,19 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
698
730
  f = self._copy_2(self.__sub__)
699
731
  return f._fsub(other, _sub_op_)
700
732
 
701
- def __truediv__(self, other):
733
+ def __truediv__(self, other, **raiser):
702
734
  '''Return C{B{self} / B{other}} as an L{Fsum}.
703
735
 
704
736
  @arg other: An L{Fsum} or C{scalar} divisor.
737
+ @kwarg raiser: Use C{B{raiser}=False} to ignore L{ResidualError}s
738
+ (C{bool}), see also method L{RESIDUAL}.
705
739
 
706
740
  @return: The quotient (L{Fsum}).
707
741
 
708
742
  @see: Method L{Fsum.__itruediv__}.
709
743
  '''
710
744
  f = self._copy_2(self.__truediv__)
711
- return f._ftruediv(other, _truediv_op_)
745
+ return f._ftruediv(other, _truediv_op_, **raiser)
712
746
 
713
747
  __trunc__ = __int__
714
748
 
@@ -757,15 +791,12 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
757
791
  '''(INTERNAL) Return C{scalar(self - B{other})} for 0-comparison.
758
792
  '''
759
793
  if isinstance(other, Fsum):
760
- s = _fsum(self._ps_1(*other._ps))
761
- elif isscalar(other):
762
- if other:
763
- s = _fsum(self._ps_1(other))
764
- else:
765
- s, r = self._fprs2
766
- s = _signOf(s, -r)
794
+ s = _fsum(self._ps_1primed(*other._ps))
795
+ elif self._scalar(other, op):
796
+ s = _fsum(self._ps_1primed(other))
767
797
  else:
768
- raise self._TypeError(op, other) # txt=_invalid_
798
+ s, r = self._fprs2
799
+ s = _signOf(s, -r)
769
800
  return s
770
801
 
771
802
  def copy(self, deep=False, name=NN):
@@ -774,8 +805,10 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
774
805
  @return: The copy (L{Fsum}).
775
806
  '''
776
807
  f = _Named.copy(self, deep=deep, name=name)
777
- f._n = self._n if deep else 1
778
- f._ps = list(self._ps) # separate list
808
+ if f._ps is self._ps:
809
+ f._ps = list(self._ps) # separate list
810
+ if not deep:
811
+ f._n = 1
779
812
  return f
780
813
 
781
814
  def _copy_2(self, which, name=NN):
@@ -801,11 +834,13 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
801
834
  # if R is not Fsum._RESIDUAL:
802
835
  # self._RESIDUAL = R
803
836
 
804
- def divmod(self, other):
837
+ def divmod(self, other, **raiser):
805
838
  '''Return C{divmod(B{self}, B{other})} as 2-tuple C{(quotient,
806
839
  remainder)}.
807
840
 
808
841
  @arg other: An L{Fsum} or C{scalar} divisor.
842
+ @kwarg raiser: Use C{B{raiser}=False} to ignore L{ResidualError}s
843
+ (C{bool}), see also method L{RESIDUAL}.
809
844
 
810
845
  @return: A L{DivMod2Tuple}C{(div, mod)}, with quotient C{div}
811
846
  an C{int} in Python 3+ or C{float} in Python 2- and
@@ -814,12 +849,12 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
814
849
  @see: Method L{Fsum.__itruediv__}.
815
850
  '''
816
851
  f = self._copy_2(self.divmod)
817
- return f._fdivmod2(other, _divmod_op_)
852
+ return f._fdivmod2(other, _divmod_op_, **raiser)
818
853
 
819
854
  def _Error(self, op, other, Error, **txt_cause):
820
855
  '''(INTERNAL) Format an B{C{Error}} for C{{self} B{op} B{other}}.
821
856
  '''
822
- return Error(_SPACE_(self.toRepr(), op, repr(other)), **txt_cause)
857
+ return Error(_SPACE_(self.toStr(), op, other), **txt_cause)
823
858
 
824
859
  def _ErrorX(self, X, op, other, *mod):
825
860
  '''(INTERNAL) Format the caught exception C{X}.
@@ -836,64 +871,89 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
836
871
  n = unstr(self.named3, *xs[:3], _ELLIPSIS=len(xs) > 3, **kwds)
837
872
  return E(n, txt=t, cause=X)
838
873
 
839
- def _facc(self, xs, up=True): # from .elliptic._Defer.Fsum
840
- '''(INTERNAL) Accumulate more known C{scalar}s.
874
+ def _facc(self, xs, up=True, **origin_X_x):
875
+ '''(INTERNAL) Accumulate more C{scalars} or L{Fsum}s.
841
876
  '''
842
- n, ps, _2s = 0, self._ps, _2sum
843
- for x in xs: # _iter()
844
- # assert isscalar(x) and isfinite(x)
845
- if x:
846
- i = 0
847
- for p in ps:
848
- x, p = _2s(x, p)
849
- if p:
850
- ps[i] = p
851
- i += 1
852
- ps[i:] = (x,) if x else ()
853
- n += 1
854
- # assert self._ps is ps
855
- if n:
856
- self._n += n
857
- # Fsum._px = max(Fsum._px, len(ps))
858
- if up:
859
- self._update()
877
+ if xs:
878
+ _x = _2floats(xs, **origin_X_x) # PYCHOK yield
879
+ ps = self._ps
880
+ ps[:] = self._ps_acc(list(ps), _x, up=up)
860
881
  return self
861
882
 
862
- def _facc_(self, *xs, **up):
863
- '''(INTERNAL) Accumulate all positional C{scalar}s.
883
+ def _facc_1(self, xs, **up):
884
+ '''(INTERNAL) Accumulate 0, 1 or more C{scalars} or L{Fsum}s,
885
+ all positional C{xs} in the caller of this method.
864
886
  '''
865
- return self._facc(xs, **up) if xs else self
887
+ # assert islistuple(xs)
888
+ return self._fadd(xs[0], _add_op_) if len(xs) == 1 else \
889
+ self._facc(xs, origin=1, **up)
890
+
891
+ def _facc_neg(self, xs, up=True, **origin):
892
+ '''(INTERNAL) Accumulate more C{scalars} or L{Fsum}s, negated.
893
+ '''
894
+ if xs:
895
+ def _neg(x):
896
+ return -x
866
897
 
867
- def _facc_power(self, power, xs, which): # in .fmath
898
+ _x = _2floats(xs, **origin) # PYCHOK yield
899
+ ps = self._ps
900
+ ps[:] = self._ps_acc(list(ps), map(_neg, _x), up=up)
901
+ return self
902
+
903
+ def _facc_power(self, power, xs, which, **raiser): # in .fmath
868
904
  '''(INTERNAL) Add each C{xs} as C{float(x**power)}.
869
905
  '''
870
- p = power
871
- if isinstance(p, Fsum):
872
- if p.is_exact:
873
- return self._facc_power(p._fprs, xs, which)
874
- _Pow = Fsum._pow_any
875
- elif isint(p, both=True) and p >= 0:
876
- _Pow, p = Fsum._pow_int, int(p)
877
- else:
878
- _Pow, p = Fsum._pow_scalar, _2float(power=p)
906
+ def _Pow4(p):
907
+ r = 0
908
+ if isinstance(p, Fsum):
909
+ s, r = p._fprs2
910
+ if r:
911
+ return _Pow4(s)
912
+ m = Fsum._pow
913
+ elif isint(p, both=True) and int(p) >= 0:
914
+ p = s = int(p)
915
+ m = Fsum._pow_int
916
+ else:
917
+ p = s = _2float(power=p)
918
+ m = Fsum._pow_scalar
919
+ return m, p, s, r
879
920
 
880
- if p:
881
- from math import pow as _pow
882
- op = which.__name__
921
+ _Pow, p, s, r = _Pow4(power)
922
+ if p: # and xs:
923
+ _pow = Fsum._pow_2_3
924
+ _Fs = Fsum
925
+ _Ps = _Psum_1()._fset_ps_
926
+ op = which.__name__
883
927
 
884
928
  def _X(X):
885
- f = _Pow(X, p, power, op)
886
- try: # isinstance(f, Fsum)
887
- return f._ps
888
- except AttributeError: # scalar
889
- return f,
929
+ f = _Pow(X, p, power, op, **raiser)
930
+ return f._ps if isinstance(f, _Fs) else (f,)
890
931
 
891
932
  def _x(x):
892
- return _pow(float(x), p)
933
+ x = float(x)
934
+ X = _Ps(x)
935
+ f = _pow(X, x, s, power, op, **raiser)
936
+ if r:
937
+ f *= _pow(X, x, r, power, op, **raiser)
938
+ return f
893
939
 
894
- self._facc(_2yield(xs, 1, _X, _x)) # PYCHOK yield
940
+ f = self._facc(xs, origin=1, _X=_X, _x=_x)
895
941
  else:
896
- self._facc_(float(len(xs))) # x**0 == 1
942
+ f = self._facc_scalar_(float(len(xs))) # x**0 == 1
943
+ return f
944
+
945
+ def _facc_scalar(self, xs, **up):
946
+ '''(INTERNAL) Accumulate all C{xs}, known to be scalar.
947
+ '''
948
+ if xs:
949
+ self._ps_acc(self._ps, xs, **up)
950
+ return self
951
+
952
+ def _facc_scalar_(self, *xs, **up):
953
+ '''(INTERNAL) Accumulate all positional C{xs}, known to be scalar.
954
+ '''
955
+ if xs:
956
+ self._ps_acc(self._ps, xs, **up)
897
957
  return self
898
958
 
899
959
  # def _facc_up(self, up=True):
@@ -904,7 +964,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
904
964
  # p = self._ps.pop()
905
965
  # if p:
906
966
  # n = self._n
907
- # self._facc_(p, up=False)
967
+ # self._facc_scalar_(p, up=False)
908
968
  # self._n = n
909
969
  # break
910
970
  # return self._update() if up else self # ._fpsqz()
@@ -926,11 +986,11 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
926
986
  @raise ValueError: Invalid or non-finite B{C{xs}} value.
927
987
  '''
928
988
  if isinstance(xs, Fsum):
929
- self._facc(xs._ps)
989
+ self._facc_scalar(xs._ps) # tuple
930
990
  elif isscalar(xs): # for backward compatibility
931
- self._facc_(_2float(x=xs)) # PYCHOK no cover
932
- elif xs:
933
- self._facc(_2floats(xs)) # PYCHOK yield
991
+ self._facc_scalar_(_2float(x=xs)) # PYCHOK no cover
992
+ elif xs: # assert isiterable(xs)
993
+ self._facc(xs)
934
994
  return self
935
995
 
936
996
  def fadd_(self, *xs):
@@ -949,33 +1009,29 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
949
1009
 
950
1010
  @raise ValueError: Invalid or non-finite B{C{xs}} value.
951
1011
  '''
952
- return self._facc(_2floats(xs, origin=1)) # PYCHOK yield
1012
+ return self._facc_1(xs)
953
1013
 
954
1014
  def _fadd(self, other, op, **up): # in .fmath.Fhorner
955
1015
  '''(INTERNAL) Apply C{B{self} += B{other}}.
956
1016
  '''
957
1017
  if isinstance(other, Fsum):
958
- if other is self:
959
- self._facc_(*other._ps, **up) # == ._facc(tuple(other._ps))
960
- elif other._ps:
961
- self._facc(other._ps, **up)
962
- elif not isscalar(other):
963
- raise self._TypeError(op, other) # txt=_invalid_
964
- elif other:
965
- self._facc_(other, **up)
1018
+ self._facc_scalar(other._ps, **up) # tuple
1019
+ elif self._scalar(other, op):
1020
+ self._facc_scalar_(other, **up)
966
1021
  return self
967
1022
 
968
1023
  fcopy = copy # for backward compatibility
969
1024
  fdiv = __itruediv__ # for backward compatibility
970
1025
  fdivmod = __divmod__ # for backward compatibility
971
1026
 
972
- def _fdivmod2(self, other, op):
1027
+ def _fdivmod2(self, other, op, **raiser):
973
1028
  '''(INTERNAL) Apply C{B{self} %= B{other}} and return a L{DivMod2Tuple}.
974
1029
  '''
975
1030
  # result mostly follows CPython function U{float_divmod
976
1031
  # <https://GitHub.com/python/cpython/blob/main/Objects/floatobject.c>},
977
1032
  # but at least divmod(-3, 2) equals Cpython's result (-2, 1).
978
- q = self._copy_2(self._fdivmod2)._ftruediv(other, op).floor
1033
+ f = self._copy_2(self._fdivmod2)
1034
+ q = f._ftruediv(other, op, **raiser).floor
979
1035
  if q: # == float // other == floor(float / other)
980
1036
  self -= other * q
981
1037
 
@@ -999,8 +1055,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
999
1055
  def fint(self, raiser=True, **name):
1000
1056
  '''Return this instance' current running sum as C{integer}.
1001
1057
 
1002
- @kwarg raiser: If C{True} throw a L{ResidualError} if the
1003
- I{integer} residual is non-zero.
1058
+ @kwarg raiser: Use C{B{raiser}=False} to ignore L{ResidualError}s
1059
+ (C{bool}), see also method L{RESIDUAL}.
1004
1060
  @kwarg name: Optional name (C{str}), overriding C{"fint"}.
1005
1061
 
1006
1062
  @return: The C{integer} (L{Fsum}).
@@ -1034,8 +1090,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1034
1090
  '''
1035
1091
  s, r = self._fprs2
1036
1092
  i = int(s)
1037
- r = _fsum(self._ps_1(i)) if r else float(s - i)
1038
- return i, (r or INT0)
1093
+ r = _fsum(self._ps_1primed(i)) if r else float(s - i)
1094
+ return i, (r or INT0) # Fsum2Tuple?
1039
1095
 
1040
1096
  @deprecated_property_RO
1041
1097
  def float_int(self): # PYCHOK no cover
@@ -1060,10 +1116,10 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1060
1116
 
1061
1117
  # floordiv = __floordiv__ # for naming consistency
1062
1118
 
1063
- def _floordiv(self, other, op): # rather _ffloordiv?
1119
+ def _floordiv(self, other, op, **raiser): # rather _ffloordiv?
1064
1120
  '''Apply C{B{self} //= B{other}}.
1065
1121
  '''
1066
- q = self._ftruediv(other, op) # == self
1122
+ q = self._ftruediv(other, op, **raiser) # == self
1067
1123
  return self._fset(q.floor) # floor(q)
1068
1124
 
1069
1125
  fmul = __imul__ # for backward compatibility
@@ -1078,41 +1134,42 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1078
1134
  f = other._mul_scalar(self._ps[0], op)
1079
1135
  else: # len(other._ps) == len(self._ps) == 1
1080
1136
  f = self._finite(self._ps[0] * other._ps[0])
1081
- elif isscalar(other):
1082
- f = self._mul_scalar(other, op)
1083
1137
  else:
1084
- raise self._TypeError(op, other) # txt=_invalid_
1138
+ s = self._scalar(other, op)
1139
+ f = self._mul_scalar(s, op)
1085
1140
  return self._fset(f) # n=len(self) + 1
1086
1141
 
1087
- def fover(self, over):
1142
+ def fover(self, over, **raiser):
1088
1143
  '''Apply C{B{self} /= B{over}} and summate.
1089
1144
 
1090
1145
  @arg over: An L{Fsum} or C{scalar} denominator.
1146
+ @kwarg raiser: Use C{B{raiser}=False} to ignore L{ResidualError}s
1147
+ (C{bool}), see also method L{RESIDUAL}.
1091
1148
 
1092
1149
  @return: Precision running sum (C{float}).
1093
1150
 
1094
1151
  @see: Methods L{Fsum.fsum} and L{Fsum.__itruediv__}.
1095
1152
  '''
1096
- return float(self.fdiv(over)._fprs)
1153
+ return float(self.fdiv(over, **raiser)._fprs)
1097
1154
 
1098
1155
  fpow = __ipow__ # for backward compatibility
1099
1156
 
1100
- def _fpow(self, other, op, *mod):
1157
+ def _fpow(self, other, op, *mod, **raiser):
1101
1158
  '''Apply C{B{self} **= B{other}}, optional B{C{mod}} or C{None}.
1102
1159
  '''
1103
1160
  if mod:
1104
1161
  if mod[0] is not None: # == 3-arg C{pow}
1105
- f = self._pow_3(other, mod[0], op)
1162
+ f = self._pow_2_3(self, other, other, op, *mod, **raiser)
1106
1163
  elif self.is_integer():
1107
1164
  # return an exact C{int} for C{int}**C{int}
1165
+ i, _ = self._fint2 # assert _ == 0
1108
1166
  x = _2scalar(other) # C{int}, C{float} or other
1109
- i = self._fint2[0] # assert _fint2[1] == 0
1110
- f = self._pow_2(i, x, other, op) if isscalar(x) else \
1111
- _Fsum_ps(i)._pow_any(x, other, op)
1167
+ f = self._pow_2_3(i, x, other, op, **raiser) if isscalar(x) else \
1168
+ _Psum_1(i)._pow( x, other, op, **raiser) # x is Fsum
1112
1169
  else: # mod[0] is None, power(self, other)
1113
- f = self._pow_any(other, other, op)
1114
- else: # pow(self, other) == pow(self, other, None)
1115
- f = self._pow_any(other, other, op)
1170
+ f = self._pow(other, other, op, **raiser)
1171
+ else: # pow(self, other)
1172
+ f = self._pow(other, other, op, **raiser)
1116
1173
  return self._fset(f, asis=isint(f)) # n=max(len(self), 1)
1117
1174
 
1118
1175
  @Property_RO
@@ -1134,8 +1191,11 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1134
1191
  n = len(ps) - 2
1135
1192
  if n > 0: # len(ps) > 2
1136
1193
  s = _psum(ps)
1137
- r = _fsum(self._ps_1(s)) or INT0
1138
- elif n == 0: # len(ps) == 2
1194
+ n = len(ps) - 2
1195
+ if n > 0:
1196
+ r = _fsum(self._ps_1primed(s)) or INT0
1197
+ return Fsum2Tuple(s, r)
1198
+ if n == 0: # len(ps) == 2
1139
1199
  ps[:] = _2ps(*_2sum(*ps))
1140
1200
  r, s = (INT0, ps[0]) if len(ps) != 2 else ps
1141
1201
  elif ps: # len(ps) == 1
@@ -1150,7 +1210,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1150
1210
  # '''(INTERNAL) Compress, squeeze the C{partials}.
1151
1211
  # '''
1152
1212
  # if len(self._ps) > 2:
1153
- # _ = self._fprs
1213
+ # _ = self._fprs2
1154
1214
  # return self
1155
1215
 
1156
1216
  def fset_(self, *xs):
@@ -1163,18 +1223,18 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1163
1223
 
1164
1224
  @see: Method L{Fsum.fadd} for further details.
1165
1225
  '''
1166
- self._n = 0
1167
1226
  self._ps[:] = 0,
1227
+ self._n = 0
1168
1228
  return self.fadd(xs) if xs else self._update()
1169
1229
 
1170
1230
  def _fset(self, other, asis=True, n=0):
1171
1231
  '''(INTERNAL) Overwrite this instance with an other or a C{scalar}.
1172
1232
  '''
1173
1233
  if other is self:
1174
- pass # from ._fmul, ._ftruediv and ._pow_scalar
1234
+ pass # from ._fmul, ._ftruediv and ._pow_0_1
1175
1235
  elif isinstance(other, Fsum):
1176
- self._n = n or other._n
1177
1236
  self._ps[:] = other._ps
1237
+ self._n = n or other._n
1178
1238
  # self._copy_RESIDUAL(other)
1179
1239
  # use or zap the C{Property_RO} values
1180
1240
  Fsum._fint2._update_from(self, other)
@@ -1184,24 +1244,32 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1184
1244
  s = other if asis else float(other)
1185
1245
  i = int(s) # see ._fint2
1186
1246
  t = i, ((s - i) or INT0)
1187
- self._n = n or 1
1188
1247
  self._ps[:] = s,
1248
+ self._n = n or 1
1189
1249
  # Property_ROs _fint2, _fprs and _fprs2 can't be a Property:
1190
1250
  # Property's _fset zaps the value just set by the @setter
1191
1251
  self.__dict__.update(_fint2=t, _fprs=s, _fprs2=Fsum2Tuple(s, INT0))
1192
1252
  else: # PYCHOK no cover
1193
- raise self._TypeError(_fset_op_, other) # txt=_invalid_
1253
+ raise self._TypeError(_fset_op_, other) # AssertionError
1194
1254
  return self
1195
1255
 
1196
1256
  def _fset_ps(self, other, n=0): # in .fmath
1197
- '''(INTERNAL) Set a known C{Fsum} or C{scalar}.
1257
+ '''(INTERNAL) Set partials from a known C{Fsum} or C{scalar}.
1198
1258
  '''
1199
1259
  if isinstance(other, Fsum):
1200
- self._n = n or other._n
1201
1260
  self._ps[:] = other._ps
1261
+ self._n = n or other._n
1202
1262
  else: # assert isscalar(other)
1203
- self._n = n or 1
1204
1263
  self._ps[:] = other,
1264
+ self._n = n or 1
1265
+ return self
1266
+
1267
+ def _fset_ps_(self, *xs):
1268
+ '''(INTERNAL) Set partials to all known scalar C{xs}.
1269
+ '''
1270
+ self._ps[:] = xs
1271
+ self.n = len(xs)
1272
+ return self
1205
1273
 
1206
1274
  def fsub(self, xs=()):
1207
1275
  '''Subtract an iterable of C{scalar} or L{Fsum} instances from
@@ -1214,7 +1282,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1214
1282
 
1215
1283
  @see: Method L{Fsum.fadd}.
1216
1284
  '''
1217
- return self._facc(_2floats(xs, neg=True)) if xs else self # PYCHOK yield
1285
+ return self._facc_neg(xs)
1218
1286
 
1219
1287
  def fsub_(self, *xs):
1220
1288
  '''Subtract all positional C{scalar} or L{Fsum} instances from
@@ -1227,7 +1295,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1227
1295
 
1228
1296
  @see: Method L{Fsum.fadd}.
1229
1297
  '''
1230
- return self._facc(_2floats(xs, origin=1, neg=True)) if xs else self # PYCHOK yield
1298
+ return self._fsub(xs[0], _sub_op_) if len(xs) == 1 else \
1299
+ self._facc_neg(xs, origin=1)
1231
1300
 
1232
1301
  def _fsub(self, other, op):
1233
1302
  '''(INTERNAL) Apply C{B{self} -= B{other}}.
@@ -1236,11 +1305,9 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1236
1305
  if other is self: # or other._fprs2 == self._fprs2:
1237
1306
  self._fset(_0_0) # n=len(self) * 2, self -= self
1238
1307
  elif other._ps:
1239
- self._facc(other._ps_neg)
1240
- elif not isscalar(other):
1241
- raise self._TypeError(op, other) # txt=_invalid_
1242
- elif self._finite(other, op):
1243
- self._facc_(-other)
1308
+ self._facc_scalar(other._ps_neg)
1309
+ elif self._scalar(other, op):
1310
+ self._facc_scalar_(-self._finite(other, op))
1244
1311
  return self
1245
1312
 
1246
1313
  def fsum(self, xs=()):
@@ -1255,21 +1322,26 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1255
1322
 
1256
1323
  @note: Accumulation can continue after summation.
1257
1324
  '''
1258
- f = self._facc(_2floats(xs)) if xs else self # PYCHOK yield
1259
- return f._fprs
1325
+ return self._facc(xs)._fprs
1260
1326
 
1261
1327
  def fsum_(self, *xs):
1262
1328
  '''Add all positional C{scalar} or L{Fsum} instances and summate.
1263
1329
 
1264
- @arg xs: Values to add (C{scalar} or L{Fsum} instances),
1265
- all positional.
1330
+ @arg xs: Values to add (C{scalar} or L{Fsum} instances), all
1331
+ positional.
1266
1332
 
1267
1333
  @return: Precision running sum (C{float} or C{int}).
1268
1334
 
1269
- @see: Methods L{Fsum.fsum} and L{Fsum.fsumf_}.
1335
+ @see: Methods L{Fsum.fsum}, L{Fsum.Fsum_} and L{Fsum.fsumf_}.
1336
+ '''
1337
+ return self._facc_1(xs)._fprs
1338
+
1339
+ def Fsum_(self, *xs):
1340
+ '''Like method L{Fsum.fsum_} but returning an L{Fsum}.
1341
+
1342
+ @return: Current, precision running sum (L{Fsum}).
1270
1343
  '''
1271
- f = self._facc(_2floats(xs, origin=1)) if xs else self # PYCHOK yield
1272
- return f._fprs
1344
+ return self._facc_1(xs)._copy_2(self.Fsum_)
1273
1345
 
1274
1346
  def fsum2(self, xs=(), name=NN):
1275
1347
  '''Add more C{scalar} or L{Fsum} instances and return the
@@ -1287,66 +1359,74 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1287
1359
 
1288
1360
  @see: Methods L{Fsum.fint2}, L{Fsum.fsum} and L{Fsum.fsum2_}
1289
1361
  '''
1290
- f = self._facc(_2floats(xs)) if xs else self # PYCHOK yield
1291
- t = f._fprs2
1292
- if name:
1293
- t = t.dup(name=name)
1294
- return t
1362
+ t = self._facc(xs)._fprs2
1363
+ return t.dup(name=name) if name else t
1295
1364
 
1296
1365
  def fsum2_(self, *xs):
1297
1366
  '''Add any positional C{scalar} or L{Fsum} instances and return
1298
1367
  the precision running sum and the C{differential}.
1299
1368
 
1300
- @arg xs: Values to add (C{scalar} or L{Fsum} instances),
1301
- all positional.
1369
+ @arg xs: Values to add (C{scalar} or L{Fsum} instances), all
1370
+ positional.
1302
1371
 
1303
- @return: 2-Tuple C{(fsum, delta)} with the current precision
1304
- running C{fsum} and C{delta}, the difference with
1305
- the previous running C{fsum} (C{float}s).
1372
+ @return: 2Tuple C{(fsum, delta)} with the current, precision
1373
+ running C{fsum} like method L{Fsum.fsum} and C{delta},
1374
+ the difference with previous running C{fsum}, C{float}.
1306
1375
 
1307
1376
  @see: Methods L{Fsum.fsum_} and L{Fsum.fsum}.
1308
1377
  '''
1309
- p, r = self._fprs2
1378
+ return self._fsum2(xs, self._facc_1)
1379
+
1380
+ def _fsum2(self, xs, _f, **origin):
1381
+ '''(INTERNAL) Helper for L{Fsum.fsum2_} and L{Fsum.fsum2f_}.
1382
+ '''
1383
+ p, q = self._fprs2
1310
1384
  if xs:
1311
- s, t = self._facc(_2floats(xs, origin=1))._fprs2 # PYCHOK yield
1312
- return s, _fsum((s, -p, r, -t)) # ((s - p) + (r - t))
1313
- else: # PYCHOK no cover
1385
+ s, r = _f(xs, **origin)._fprs2
1386
+ return s, _2delta(s - p, r - q) # _fsum(_1primed((s, -p, r, -q))
1387
+ else:
1314
1388
  return p, _0_0
1315
1389
 
1316
1390
  def fsumf_(self, *xs):
1317
- '''Like method L{Fsum.fsum_} but only for known C{float B{xs}}.
1391
+ '''Like method L{Fsum.fsum_} but only for C{B{xs}}, I{known to be scalar}.
1392
+ '''
1393
+ return self._facc_scalar(xs)._fprs
1394
+
1395
+ def Fsumf_(self, *xs):
1396
+ '''Like method L{Fsum.Fsum_} but only for C{B{xs}}, I{known to be scalar}.
1397
+ '''
1398
+ return self._facc_scalar(xs)._copy_2(self.Fsumf_)
1399
+
1400
+ def fsum2f_(self, *xs):
1401
+ '''Like method L{Fsum.fsum2_} but only for C{B{xs}}, I{known to be scalar}.
1318
1402
  '''
1319
- f = self._facc(xs) if xs else self # PYCHOK yield
1320
- return f._fprs
1403
+ return self._fsum2(xs, self._facc_scalar, origin=1)
1321
1404
 
1322
- # ftruediv = __itruediv__ # for naming consistency
1405
+ # ftruediv = __itruediv__ # for naming consistency?
1323
1406
 
1324
- def _ftruediv(self, other, op):
1407
+ def _ftruediv(self, other, op, **raiser):
1325
1408
  '''(INTERNAL) Apply C{B{self} /= B{other}}.
1326
1409
  '''
1327
1410
  n = _1_0
1328
1411
  if isinstance(other, Fsum):
1329
1412
  if other is self or other == self:
1330
- return self._fset(_1_0) # n=len(self)
1413
+ return self._fset(n) # n=len(self)
1331
1414
  d, r = other._fprs2
1332
1415
  if r:
1333
1416
  if d:
1334
- if self._raiser(r, d):
1417
+ if self._raiser(r, d, **raiser):
1335
1418
  raise self._ResidualError(op, other, r)
1336
1419
  d, n = other.as_integer_ratio()
1337
1420
  else: # PYCHOK no cover
1338
1421
  d = r
1339
- elif isscalar(other):
1340
- d = other
1341
- else: # PYCHOK no cover
1342
- raise self._TypeError(op, other) # txt=_invalid_
1422
+ else:
1423
+ d = self._scalar(other, op)
1343
1424
  try:
1344
- s = 0 if isinf(d) else (
1345
- d if isnan(d) else self._finite(n / d))
1425
+ s = n / d
1346
1426
  except Exception as X:
1347
1427
  raise self._ErrorX(X, op, other)
1348
- f = self._mul_scalar(s, _mul_op_) # handles 0, NAN, etc.
1349
- return self._fset(f, asis=False)
1428
+ f = self._mul_scalar(s, _mul_op_) # handles 0, INF, NAN
1429
+ return self._fset(f) # asis=False
1350
1430
 
1351
1431
  @property_RO
1352
1432
  def imag(self):
@@ -1360,7 +1440,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1360
1440
  '''Return this instance' current running sum as C{int} or C{float}.
1361
1441
 
1362
1442
  @kwarg raiser: If C{True} throw a L{ResidualError} if the
1363
- residual is non-zero.
1443
+ residual is non-zero (C{bool}).
1364
1444
 
1365
1445
  @return: This C{integer} sum if this instance C{is_integer},
1366
1446
  otherwise return the C{float} sum if the residual
@@ -1380,13 +1460,12 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1380
1460
  return s
1381
1461
 
1382
1462
  def is_exact(self):
1383
- '''Is this instance' current running C{fsum} considered to
1384
- be exact? (C{bool}).
1463
+ '''Is this instance' running C{fsum} considered to be exact? (C{bool}).
1385
1464
  '''
1386
1465
  return self.residual is INT0
1387
1466
 
1388
1467
  def is_integer(self):
1389
- '''Is this instance' current running sum C{integer}? (C{bool}).
1468
+ '''Is this instance' running sum C{integer}? (C{bool}).
1390
1469
 
1391
1470
  @see: Methods L{Fsum.fint} and L{Fsum.fint2}.
1392
1471
  '''
@@ -1412,7 +1491,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1412
1491
  '''
1413
1492
  # assert isinstance(other, Fsum)
1414
1493
  if self._ps and other._ps:
1415
- f = _Fsum_xs(self._ps_mul(op, *other._ps))
1494
+ f = self._ps_mul(op, *other._ps) # NO ._2scalar
1416
1495
  else:
1417
1496
  f = _0_0
1418
1497
  return f
@@ -1424,133 +1503,119 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1424
1503
  if self._ps and self._finite(factor, op):
1425
1504
  f = self if factor == _1_0 else (
1426
1505
  self._neg if factor == _N_1_0 else
1427
- _Fsum_xs(self._ps_mul(op, factor))) # PYCHOK indent
1506
+ self._ps_mul(op, factor)._2scalar)
1428
1507
  else:
1429
1508
  f = _0_0
1430
1509
  return f
1431
1510
 
1432
1511
  @property_RO
1433
1512
  def _neg(self):
1434
- '''(INTERNAL) Return C{-self}.
1513
+ '''(INTERNAL) Return C{Fsum(-self)} or scalar C{NEG0}.
1435
1514
  '''
1436
- return _Fsum_ps(*self._ps_neg) if self._ps else NEG0
1515
+ return _Psum(self._ps_neg) if self._ps else NEG0
1437
1516
 
1438
1517
  @property_RO
1439
1518
  def partials(self):
1440
- '''Get this instance' current partial sums (C{tuple} of C{float}s and/or C{int}s).
1519
+ '''Get this instance' current, partial sums (C{tuple} of C{float}s).
1441
1520
  '''
1442
1521
  return tuple(self._ps)
1443
1522
 
1444
- def pow(self, x, *mod):
1523
+ def pow(self, x, *mod, **raiser):
1445
1524
  '''Return C{B{self}**B{x}} as L{Fsum}.
1446
1525
 
1447
1526
  @arg x: The exponent (L{Fsum} or C{scalar}).
1448
1527
  @arg mod: Optional modulus (C{int} or C{None}) for the 3-argument
1449
1528
  C{pow(B{self}, B{other}, B{mod})} version.
1529
+ @kwarg raiser: Use C{B{raiser}=False} to ignore L{ResidualError}s
1530
+ (C{bool}), see also method L{RESIDUAL}.
1450
1531
 
1451
1532
  @return: The C{pow(self, B{x})} or C{pow(self, B{x}, *B{mod})}
1452
1533
  result (L{Fsum}).
1453
1534
 
1454
1535
  @note: If B{C{mod}} is given as C{None}, the result will be an
1455
1536
  C{integer} L{Fsum} provided this instance C{is_integer}
1456
- or set to C{integer} with L{Fsum.fint}.
1537
+ or set to C{integer} by an L{Fsum.fint} call.
1457
1538
 
1458
- @see: Methods L{Fsum.__ipow__}, L{Fsum.fint} and L{Fsum.is_integer}.
1539
+ @see: Methods L{Fsum.__ipow__}, L{Fsum.fint}, L{Fsum.is_integer}
1540
+ and L{Fsum.root}.
1459
1541
  '''
1460
1542
  f = self._copy_2(self.pow)
1461
- return f._fpow(x, _pow_op_, *mod) # f = pow(f, x, *mod)
1543
+ return f._fpow(x, _pow_op_, *mod, **raiser) # f = pow(f, x, *mod)
1462
1544
 
1463
- def _pow_0_1(self, x, other):
1464
- '''(INTERNAL) Return B{C{self}**1} or C{B{self}**0 == 1.0}.
1465
- '''
1466
- return self if x else (1 if isint(other) and self.is_integer() else _1_0)
1467
-
1468
- def _pow_2(self, b, x, other, op):
1469
- '''(INTERNAL) 2-arg C{pow(B{b}, scalar B{x})} embellishing errors.
1470
- '''
1471
- # assert isscalar(b) and isscalar(x)
1472
- try: # type(s) == type(x) if x in (_1_0, 1)
1473
- s = pow(b, x) # -1**2.3 == -(1**2.3)
1474
- if not iscomplex(s):
1475
- return self._finite(s) # 0**INF == 0.0, 1**INF==1.0
1476
- # neg**frac == complex in Python 3+, but ValueError in 2-
1477
- raise ValueError(_strcomplex(s, b, x)) # PYCHOK no cover
1478
- except Exception as X:
1479
- raise self._ErrorX(X, op, other)
1480
-
1481
- def _pow_3(self, other, mod, op):
1482
- '''(INTERNAL) 3-arg C{pow(B{self}, B{other}, int B{mod} or C{None})}.
1483
- '''
1484
- b, r = self._fprs2 if mod is None else self._fint2
1485
- if r and self._raiser(r, b):
1486
- t = _non_zero_ if mod is None else _integer_
1487
- t = _stresidual(t, r, mod=mod)
1488
- raise self._Error(op, other, ResidualError, txt=t)
1489
-
1490
- try: # b, other, mod all C{int}, unless C{mod} is C{None}
1491
- x = _2scalar(other, _raiser=self._raiser)
1492
- s = pow(b, x, mod)
1493
- if not iscomplex(s):
1494
- return self._finite(s)
1495
- # neg**frac == complex in Python 3+, but ValueError in 2-
1496
- raise ValueError(_strcomplex(s, b, x, mod)) # PYCHOK no cover
1497
- except Exception as X:
1498
- raise self._ErrorX(X, op, other, mod)
1499
-
1500
- def _pow_any(self, other, unused, op):
1545
+ def _pow(self, other, unused, op, **raiser):
1501
1546
  '''Return C{B{self} ** B{other}}.
1502
1547
  '''
1503
1548
  if isinstance(other, Fsum):
1504
1549
  x, r = other._fprs2
1505
- f = self._pow_scalar(x, other, op)
1550
+ if r and self._raiser(r, x, **raiser):
1551
+ raise self._ResidualError(op, other, r)
1552
+ f = self._pow_scalar(x, other, op, **raiser)
1506
1553
  if r:
1507
- if self._raiser(r, x):
1508
- raise self._ResidualError(op, other, r)
1509
- s = self._pow_scalar(r, other, op)
1510
- # s = _2scalar(s) # _raiser = None
1511
- f *= s
1512
- elif isscalar(other):
1554
+ f *= self._pow_scalar(r, other, op, **raiser)
1555
+ elif self._scalar(other, op):
1513
1556
  x = self._finite(other, op)
1514
- f = self._pow_scalar(x, other, op)
1557
+ f = self._pow_scalar(x, other, op, **raiser)
1515
1558
  else:
1516
- raise self._TypeError(op, other) # txt=_invalid_
1559
+ f = self._pow_0_1(0, other)
1517
1560
  return f
1518
1561
 
1519
- def _pow_int(self, x, other, op):
1562
+ def _pow_0_1(self, x, other):
1563
+ '''(INTERNAL) Return B{C{self}**1} or C{B{self}**0 == 1.0}.
1564
+ '''
1565
+ return self if x else (1 if isint(other) and self.is_integer() else _1_0)
1566
+
1567
+ def _pow_2_3(self, b, x, other, op, *mod, **raiser):
1568
+ '''(INTERNAL) 2-arg C{pow(B{b}, scalar B{x})} and 3-arg C{pow(B{b},
1569
+ B{x}, int B{mod} or C{None})}, embellishing errors.
1570
+ '''
1571
+ try:
1572
+ if mod: # b, x, mod all C{int}, unless C{mod} is C{None}
1573
+ m = mod[0]
1574
+ b, r = b._fprs2 if m is None else b._fint2
1575
+ if r and self._raiser(r, b, **raiser):
1576
+ t = _non_zero_ if m is None else _integer_
1577
+ raise ResidualError(_stresidual(t, r, mod=m), txt=None)
1578
+ x = _2scalar(x, _raiser=self._raiser, mod=m)
1579
+ # 0**INF == 0.0, 1**INF == 1.0, -1**2.3 == -(1**2.3)
1580
+ s = pow(b, x, *mod)
1581
+ if iscomplex(s):
1582
+ # neg**frac == complex in Python 3+, but ValueError in 2-
1583
+ raise ValueError(_strcomplex(s, b, x, *mod))
1584
+ return self._finite(s)
1585
+ except Exception as X:
1586
+ raise self._ErrorX(X, op, other, *mod)
1587
+
1588
+ def _pow_int(self, x, other, op, **raiser):
1520
1589
  '''(INTERNAL) Return C{B{self} **= B{x}} for C{int B{x} >= 0}.
1521
1590
  '''
1522
1591
  # assert isint(x) and x >= 0
1523
1592
  ps = self._ps
1524
1593
  if len(ps) > 1:
1525
- f = self
1594
+ _mul_Fsum = Fsum._mul_Fsum
1526
1595
  if x > 4:
1527
- m = 1 # single-bit mask
1528
- if (x & m):
1529
- x -= m # x ^= m
1530
- else:
1531
- f = _Fsum_ps(_1_0)
1532
1596
  p = self
1533
- while x:
1534
- p = p._mul_Fsum(p, op) # p **= 2
1535
- m += m # m <<= 1
1536
- if (x & m):
1537
- x -= m # x ^= m
1538
- f = f._mul_Fsum(p, op) # f *= p
1597
+ f = self if (x & 1) else _Psum_1()
1598
+ m = x >> 1 # // 2
1599
+ while m:
1600
+ p = _mul_Fsum(p, p, op) # p **= 2
1601
+ if (m & 1):
1602
+ f = _mul_Fsum(f, p, op) # f *= p
1603
+ m >>= 1 # //= 2
1539
1604
  elif x > 1: # self**2, 3 or 4
1540
- f = f._mul_Fsum(f, op)
1605
+ f = _mul_Fsum(self, self, op)
1541
1606
  if x > 2: # self**3 or 4
1542
- p = self if x < 4 else f
1543
- f = f._mul_Fsum(p, op)
1607
+ p = self if x < 4 else f
1608
+ f = _mul_Fsum(f, p, op)._2scalar
1544
1609
  else: # self**1 or self**0 == 1 or _1_0
1545
- f = f._pow_0_1(x, other)
1610
+ f = self._pow_0_1(x, other)
1546
1611
  elif ps: # self._ps[0]**x
1547
- f = self._pow_2(ps[0], x, other, op)
1612
+ f = self._pow_2_3(ps[0], x, other, op, **raiser)
1548
1613
  else: # PYCHOK no cover
1549
1614
  # 0**pos_int == 0, but 0**0 == 1
1550
- f = 0 if x else 1 # like ._fprs
1615
+ f = 0 if x else 1
1551
1616
  return f
1552
1617
 
1553
- def _pow_scalar(self, x, other, op):
1618
+ def _pow_scalar(self, x, other, op, **raiser):
1554
1619
  '''(INTERNAL) Return C{self**B{x}} for C{scalar B{x}}.
1555
1620
  '''
1556
1621
  s, r = self._fprs2
@@ -1559,55 +1624,65 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1559
1624
  y = abs(x)
1560
1625
  if y > 1:
1561
1626
  if r:
1562
- f = self._pow_int(y, other, op)
1627
+ f = self._pow_int(y, other, op, **raiser)
1563
1628
  if x > 0: # > 1
1564
1629
  return f
1565
1630
  # assert x < 0 # < -1
1566
1631
  s, r = f._fprs2 if isinstance(f, Fsum) else (f, 0)
1567
1632
  if r:
1568
- return _Fsum_ps(_1_0)._ftruediv(f, op)
1633
+ return _Psum_1()._ftruediv(f, op, **raiser)
1569
1634
  # use **= -1 for the CPython float_pow
1570
1635
  # error if s is zero, and not s = 1 / s
1571
1636
  x = -1
1572
- elif x < 0: # self**-1 == 1 / self
1637
+ elif x < 0: # == -1: self**(-1) == 1 / self
1573
1638
  if r:
1574
- return _Fsum_ps(_1_0)._ftruediv(self, op)
1639
+ return _Psum_1()._ftruediv(self, op, **raiser)
1575
1640
  else: # self**1 or self**0
1576
1641
  return self._pow_0_1(x, other) # self, 1 or 1.0
1577
- elif not isscalar(x): # assert ...
1578
- raise self._TypeError(op, other, txt=_not_scalar_)
1579
- elif r and self._raiser(r, s): # non-zero residual**fractional
1642
+ elif r and self._raiser(r, s, **raiser): # non-zero residual**fractional
1580
1643
  # raise self._ResidualError(op, other, r, fractional_power=x)
1581
1644
  t = _stresidual(_non_zero_, r, fractional_power=x)
1582
1645
  raise self._Error(op, other, ResidualError, txt=t)
1583
1646
  # assert isscalar(s) and isscalar(x)
1584
- return self._pow_2(s, x, other, op)
1647
+ return self._pow_2_3(s, x, other, op, **raiser)
1585
1648
 
1586
- def _ps_1(self, *less):
1587
- '''(INTERNAL) Yield partials, 1-primed and subtract any C{less}.
1649
+ def _ps_acc(self, ps, xs, up=True, **unused):
1650
+ '''(INTERNAL) Accumulate all scalar C{xs} into C{ps}.
1588
1651
  '''
1589
- n = len(self._ps) + len(less) - 4
1590
- if n < 0:
1591
- yield _1_0
1592
- for p in self._ps:
1593
- yield p
1594
- for p in less:
1595
- yield -p
1596
- if n < 0:
1597
- yield _N_1_0
1598
-
1599
- def _ps_mul(self, op, *factors): # see .fmath.Fhorner
1600
- '''(INTERNAL) Yield all C{partials} times each B{C{factor}},
1601
- in total, up to C{len(partials) * len(factors)} items.
1602
- '''
1603
- ps = self._ps # tuple(self._ps)
1604
- if len(ps) < len(factors):
1605
- ps, factors = factors, ps
1606
- _f = _isfinite
1607
- for f in factors:
1608
- for p in ps:
1609
- p *= f
1610
- yield p if _f(p) else self._finite(p, op)
1652
+ n = 0
1653
+ _2s = _2sum
1654
+ for x in (tuple(xs) if xs is ps else xs):
1655
+ # assert isscalar(x) and _isfinite(x)
1656
+ if x:
1657
+ i = 0
1658
+ for p in ps:
1659
+ x, p = _2s(x, p)
1660
+ if p:
1661
+ ps[i] = p
1662
+ i += 1
1663
+ ps[i:] = (x,) if x else ()
1664
+ n += 1
1665
+ if n:
1666
+ self._n += n
1667
+ # Fsum._ps_max = max(Fsum._ps_max, len(ps))
1668
+ if up:
1669
+ self._update()
1670
+ return ps
1671
+
1672
+ def _ps_mul(self, op, *factors):
1673
+ '''(INTERNAL) Multiply this instance' C{partials} with
1674
+ each of the scalar B{C{factors}} and accumulate.
1675
+ '''
1676
+ def _pfs(ps, fs):
1677
+ if len(ps) < len(fs):
1678
+ ps, fs = fs, ps
1679
+ _fin = _isfinite
1680
+ for f in fs:
1681
+ for p in ps:
1682
+ p *= f
1683
+ yield p if _fin(p) else self._finite(p, op)
1684
+
1685
+ return _Psum(self._ps_acc([], _pfs(self._ps, factors)))
1611
1686
 
1612
1687
  @property_RO
1613
1688
  def _ps_neg(self):
@@ -1616,6 +1691,22 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1616
1691
  for p in self._ps:
1617
1692
  yield -p
1618
1693
 
1694
+ def _ps_1primed(self, *less):
1695
+ '''(INTERNAL) Yield partials, 1-primed and subtract any C{less} scalars.
1696
+ '''
1697
+ yield _1_0
1698
+ for p in self._ps:
1699
+ yield p
1700
+ for p in less:
1701
+ yield -p
1702
+ yield _N_1_0
1703
+
1704
+ def _raiser(self, r, s, raiser=True):
1705
+ '''(INTERNAL) Does ratio C{r / s} exceed the RESIDUAL threshold?
1706
+ '''
1707
+ self._ratio = t = fabs(r / s) if s else 0 # _0_0
1708
+ return raiser and (t > self._RESIDUAL)
1709
+
1619
1710
  @property_RO
1620
1711
  def real(self):
1621
1712
  '''Get the C{real} part of this instance (C{float}).
@@ -1638,12 +1729,6 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1638
1729
  '''
1639
1730
  return self._fprs2.residual
1640
1731
 
1641
- def _raiser(self, r, s):
1642
- '''(INTERNAL) Does ratio C{r / s} exceed threshold?
1643
- '''
1644
- self._ratio = t = fabs((r / s) if s else r)
1645
- return t > self._RESIDUAL
1646
-
1647
1732
  def RESIDUAL(self, *threshold):
1648
1733
  '''Get and set this instance' I{ratio} for raising L{ResidualError}s,
1649
1734
  overriding the default from env variable C{PYGEODESY_FSUM_RESIDUAL}.
@@ -1654,11 +1739,11 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1654
1739
  C{PYGEODESY_FSUM_RESIDUAL} or if omitted, keep the
1655
1740
  current setting.
1656
1741
 
1657
- @return: The previous C{RESIDUAL} setting (C{float}), default C{0}.
1742
+ @return: The previous C{RESIDUAL} setting (C{float}), default C{0.}.
1658
1743
 
1659
1744
  @raise ValueError: Negative B{C{threshold}}.
1660
1745
 
1661
- @note: A L{ResidualError} is thrown if the non-zero I{ratio}
1746
+ @note: L{ResidualError}s will be thrown if the non-zero I{ratio}
1662
1747
  C{residual / fsum} exceeds the B{C{threshold}}.
1663
1748
  '''
1664
1749
  r = self._RESIDUAL
@@ -1681,6 +1766,44 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1681
1766
  t = t.replace(_COMMASPACE_R_, _exceeds_R_)
1682
1767
  return self._Error(op, other, ResidualError, txt=t)
1683
1768
 
1769
+ def root(self, root, **raiser):
1770
+ '''Return C{B{self}**(1 / B{root})} as L{Fsum}.
1771
+
1772
+ @arg root: The order (C{scalar} or C{Fsum}), non-zero.
1773
+ @kwarg raiser: Use C{B{raiser}=False} to ignore L{ResidualError}s
1774
+ (C{bool}), see also method L{RESIDUAL}.
1775
+
1776
+ @return: The C{self ** (1 / B{root})} result (L{Fsum}).
1777
+
1778
+ @see: Method L{Fsum.pow}.
1779
+ '''
1780
+ _root_ = self.root.__name__
1781
+ if isinstance(root, Fsum):
1782
+ x = root.__rtruediv__(_1_0, **raiser)
1783
+ else:
1784
+ try:
1785
+ x = _1_0 / _2float(root=root)
1786
+ except Exception as X:
1787
+ E, t = _xError2(X)
1788
+ n = _SPACE_(_1_0, _truediv_op_, _root_)
1789
+ raise E(n, root, txt=t, cause=X)
1790
+ f = self._copy_2(self.root)
1791
+ return f._fpow(x, _root_, **raiser) # == pow(f, x)
1792
+
1793
+ def _scalar(self, other, op, **txt):
1794
+ '''(INTERNAL) Return scalar C{other}.
1795
+ '''
1796
+ if isscalar(other):
1797
+ return other
1798
+ raise self._TypeError(op, other, **txt) # _invalid_
1799
+
1800
+ @property_RO
1801
+ def _2scalar(self):
1802
+ '''(INTERNAL) Get this instance as C{scalar} or C{as-is}.
1803
+ '''
1804
+ s, r = self._fprs2
1805
+ return self if r else s
1806
+
1684
1807
  def signOf(self, res=True):
1685
1808
  '''Determine the sign of this instance.
1686
1809
 
@@ -1689,8 +1812,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1689
1812
 
1690
1813
  @return: The sign (C{int}, -1, 0 or +1).
1691
1814
  '''
1692
- s, r = self._fprs2 if res else (self._fprs, 0)
1693
- return _signOf(s, -r)
1815
+ s, r = self._fprs2
1816
+ return _signOf(s, (-r) if res else 0)
1694
1817
 
1695
1818
  def toRepr(self, **prec_sep_fmt_lenc): # PYCHOK signature
1696
1819
  '''Return this C{Fsum} instance as representation.
@@ -1784,21 +1907,21 @@ class Fsum2Tuple(_NamedTuple):
1784
1907
  _Units_ = (_Float_Int, _Float_Int)
1785
1908
 
1786
1909
  @Property_RO
1787
- def Fsum(self):
1788
- '''Get this L{Fsum2Tuple} as an L{Fsum}.
1910
+ def _Fsum(self):
1911
+ '''(INTERNAL) Get this L{Fsum2Tuple} as an L{Fsum}.
1789
1912
  '''
1790
1913
  s, r = map(float, self)
1791
- return _Fsum_ps(*_2ps(s, r), name=self.name)
1914
+ return _Psum(_2ps(s, r), name=self.name)
1792
1915
 
1793
1916
  def is_exact(self):
1794
1917
  '''Is this L{Fsum2Tuple} considered to be exact? (C{bool}).
1795
1918
  '''
1796
- return self.Fsum.is_exact()
1919
+ return self._Fsum.is_exact()
1797
1920
 
1798
1921
  def is_integer(self):
1799
1922
  '''Is this L{Fsum2Tuple} C{integer}? (C{bool}).
1800
1923
  '''
1801
- return self.Fsum.is_integer()
1924
+ return self._Fsum.is_integer()
1802
1925
 
1803
1926
 
1804
1927
  class ResidualError(_ValueError):
@@ -1810,23 +1933,6 @@ class ResidualError(_ValueError):
1810
1933
  pass
1811
1934
 
1812
1935
 
1813
- def _Fsum_ps(*ps, **name):
1814
- '''(INTERNAL) Return an C{Fsum} from I{ordered} partials C{ps}.
1815
- '''
1816
- f = Fsum(**name) if name else Fsum()
1817
- if ps:
1818
- f._n = len(ps)
1819
- f._ps[:] = ps
1820
- return f
1821
-
1822
-
1823
- def _Fsum_xs(xs, up=False, **name):
1824
- '''(INTERNAL) Return an C{Fsum} from known floats C{xs}.
1825
- '''
1826
- f = Fsum(**name) if name else Fsum()
1827
- return f._facc(xs, up=up)
1828
-
1829
-
1830
1936
  try:
1831
1937
  from math import fsum as _fsum # precision IEEE-754 sum, Python 2.6+
1832
1938
 
@@ -1842,12 +1948,14 @@ try:
1842
1948
  _psum = _fsum # PYCHOK re-def
1843
1949
 
1844
1950
  except ImportError:
1845
- _sum = sum # Fsum(NAN) exception fall-back
1951
+ _sum = sum # Fsum(NAN) exception fall-back, in .elliptic
1846
1952
 
1847
1953
  def _fsum(xs):
1848
1954
  '''(INTERNAL) Precision summation, Python 2.5-.
1849
1955
  '''
1850
- return Fsum(name=_fsum.__name__).fsum(xs) if xs else _0_0
1956
+ f = Fsum()
1957
+ f.name = _fsum.__name__
1958
+ return f.fsum(xs)
1851
1959
 
1852
1960
 
1853
1961
  def fsum(xs, floats=False):
@@ -1855,8 +1963,8 @@ def fsum(xs, floats=False):
1855
1963
 
1856
1964
  @arg xs: Iterable, list, tuple, etc. of values (C{scalar} or L{Fsum}
1857
1965
  instances).
1858
- @kwarg floats: Optionally, use C{B{floats}=True} iff I{all} B{C{xs}}
1859
- are known to be C{float}.
1966
+ @kwarg floats: Use C{B{floats}=True} iff I{all} B{C{xs}} are known
1967
+ to be C{float} scalars (C{bool}).
1860
1968
 
1861
1969
  @return: Precision C{fsum} (C{float}).
1862
1970
 
@@ -1866,8 +1974,8 @@ def fsum(xs, floats=False):
1866
1974
 
1867
1975
  @raise ValueError: Invalid or non-finite B{C{xs}} value.
1868
1976
 
1869
- @note: Exceptions and I{non-finite} handling may differ if not
1870
- based on Python's C{math.fsum}.
1977
+ @note: Exception and I{non-finite} handling may differ if not based
1978
+ on Python's C{math.fsum}.
1871
1979
 
1872
1980
  @see: Class L{Fsum} and methods L{Fsum.fsum} and L{Fsum.fadd}.
1873
1981
  '''
@@ -1879,8 +1987,8 @@ def fsum_(*xs, **floats):
1879
1987
 
1880
1988
  @arg xs: Values to be added (C{scalar} or L{Fsum} instances), all
1881
1989
  positional.
1882
- @kwarg floats: Optionally, use C{B{floats}=True} iff I{all} B{C{xs}}
1883
- are known to be C{float}.
1990
+ @kwarg floats: Use C{B{floats}=True} iff I{all} B{C{xs}} are I{known
1991
+ to be scalar} (C{bool}).
1884
1992
 
1885
1993
  @return: Precision C{fsum} (C{float}).
1886
1994
 
@@ -1891,18 +1999,19 @@ def fsum_(*xs, **floats):
1891
1999
 
1892
2000
 
1893
2001
  def fsumf_(*xs):
1894
- '''Precision floating point summation L{fsum_}C{(*xs, floats=True)}.
2002
+ '''Precision floating point summation, L{fsum_}C{(*B{xs}, floats=True)},
2003
+ but only for C{B{xs}} I{known to be scalar}.
1895
2004
  '''
1896
2005
  return _fsum(xs) if xs else _0_0
1897
2006
 
1898
2007
 
1899
2008
  def fsum1(xs, floats=False):
1900
- '''Precision floating point summation of a few arguments, 1-primed.
2009
+ '''Precision floating point summation, 1-primed.
1901
2010
 
1902
2011
  @arg xs: Iterable, list, tuple, etc. of values (C{scalar} or L{Fsum}
1903
2012
  instances).
1904
- @kwarg floats: Optionally, use C{B{floats}=True} iff I{all} B{C{xs}}
1905
- are known to be C{float}.
2013
+ @kwarg floats: Use C{B{floats}=True} iff I{all} B{C{xs}} are known
2014
+ to be C{float}.
1906
2015
 
1907
2016
  @return: Precision C{fsum} (C{float}).
1908
2017
 
@@ -1912,12 +2021,12 @@ def fsum1(xs, floats=False):
1912
2021
 
1913
2022
 
1914
2023
  def fsum1_(*xs, **floats):
1915
- '''Precision floating point summation of a few arguments, 1-primed.
2024
+ '''Precision floating point summation, 1-primed.
1916
2025
 
1917
2026
  @arg xs: Values to be added (C{scalar} or L{Fsum} instances), all
1918
2027
  positional.
1919
- @kwarg floats: Optionally, use C{B{floats}=True} iff I{all} B{C{xs}}
1920
- are known to be C{float}.
2028
+ @kwarg floats: Use C{B{floats}=True} iff I{all} B{C{xs}} are I{known
2029
+ to be scalar} (C{bool}).
1921
2030
 
1922
2031
  @return: Precision C{fsum} (C{float}).
1923
2032
 
@@ -1928,7 +2037,8 @@ def fsum1_(*xs, **floats):
1928
2037
 
1929
2038
 
1930
2039
  def fsum1f_(*xs):
1931
- '''Precision floating point summation L{fsum1_}C{(*xs, floats=True)}.
2040
+ '''Precision floating point summation, L{fsum1_}C{(*B{xs}, floats=True)},
2041
+ but only for C{B{xs}} I{known to be scalar}.
1932
2042
  '''
1933
2043
  return _fsum(_1primed(xs)) if xs else _0_0
1934
2044
 
@@ -1946,7 +2056,7 @@ if __name__ == '__main__':
1946
2056
  printf(_psum.__name__, end=_COMMASPACE_)
1947
2057
 
1948
2058
  F = Fsum()
1949
- if F.is_math_fsum:
2059
+ if F.is_math_fsum():
1950
2060
  c = (7, 1e100, -7, -1e100, -9e-20, 8e-20) * 10
1951
2061
  for _ in range(n):
1952
2062
  t = list(c)