pygeodesy 24.4.12__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
@@ -27,14 +27,14 @@ from __future__ import division as _; del _ # PYCHOK semicolon
27
27
 
28
28
  from pygeodesy.basics import iscomplex, isint, isscalar, itemsorted, \
29
29
  signOf, _signOf
30
- from pygeodesy.constants import INT0, _isfinite, isinf, isnan, NEG0, _pos_self, \
30
+ from pygeodesy.constants import INT0, _isfinite, NEG0, _pos_self, \
31
31
  _0_0, _1_0, _N_1_0, Float, Int
32
32
  from pygeodesy.errors import _OverflowError, _TypeError, _ValueError, _xError, \
33
33
  _xError2, _xkwds_get, _ZeroDivisionError
34
34
  from pygeodesy.interns import NN, _arg_, _COMMASPACE_, _DASH_, _DOT_, _EQUAL_, \
35
35
  _exceeds_, _from_, _iadd_op_, _LANGLE_, _negative_, \
36
- _NOTEQUAL_, _not_finite_, _not_scalar_, _PERCENT_, \
37
- _PLUS_, _R_, _RANGLE_, _SLASH_, _SPACE_, _STAR_, _UNDER_
36
+ _NOTEQUAL_, _not_finite_, _PERCENT_, _PLUS_, _R_, \
37
+ _RANGLE_, _SLASH_, _SPACE_, _STAR_, _UNDER_
38
38
  from pygeodesy.lazily import _ALL_LAZY, _getenv, _sys_version_info2
39
39
  from pygeodesy.named import _Named, _NamedTuple, _NotImplemented, Fmt, unstr
40
40
  from pygeodesy.props import _allPropertiesOf_n, deprecated_property_RO, \
@@ -45,7 +45,7 @@ from pygeodesy.props import _allPropertiesOf_n, deprecated_property_RO, \
45
45
  from math import ceil as _ceil, fabs, floor as _floor # PYCHOK used! .ltp
46
46
 
47
47
  __all__ = _ALL_LAZY.fsums
48
- __version__ = '24.04.09'
48
+ __version__ = '24.04.18'
49
49
 
50
50
  _add_op_ = _PLUS_ # in .auxilats.auxAngle
51
51
  _eq_op_ = _EQUAL_ * 2 # _DEQUAL_
@@ -72,7 +72,7 @@ _isub_op_ = _sub_op_ + _fset_op_ # in .auxilats.auxAngle, .fsums
72
72
 
73
73
 
74
74
  def _2delta(*ab):
75
- '''(INTERNAL) Helper for C{Fsum.fsum2f_}.
75
+ '''(INTERNAL) Helper for C{Fsum._fsum2}.
76
76
  '''
77
77
  try:
78
78
  a, b = _2sum(*ab)
@@ -121,6 +121,18 @@ def _2floats(xs, origin=0, _X=_X_ps, _x=float):
121
121
  raise _xError(X, Fmt.INDEX(xs=i), x)
122
122
 
123
123
 
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
+
129
+
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
+
124
136
  def _2halfeven(s, r, p):
125
137
  '''(INTERNAL) Round half-even.
126
138
  '''
@@ -173,20 +185,20 @@ def _psum(ps): # PYCHOK used!
173
185
  def _Psum(ps, **name):
174
186
  '''(INTERNAL) Return an C{Fsum} from I{ordered} partials C{ps}.
175
187
  '''
176
- f = Fsum(**name) if name else Fsum()
188
+ F = Fsum(**name) if name else Fsum()
177
189
  if ps:
178
- f._ps[:] = ps
179
- f._n = len(f._ps)
180
- return f
190
+ F._ps[:] = ps
191
+ F._n = len(F._ps)
192
+ return F
181
193
 
182
194
 
183
195
  def _Psum_1(p=_1_0, **name):
184
196
  '''(INTERNAL) Return an C{Fsum} from a single partial C{p}.
185
197
  '''
186
- f = Fsum(**name) if name else Fsum()
187
- f._ps[:] = p,
188
- f._n = 1 # len(f._ps)
189
- return f
198
+ F = Fsum(**name) if name else Fsum()
199
+ F._ps[:] = p,
200
+ F._n = 1 # len(F._ps)
201
+ return F
190
202
 
191
203
 
192
204
  def _2scalar(other, _raiser=None, **mod):
@@ -233,13 +245,13 @@ def _2sum(a, b): # by .testFmath
233
245
  '''(INTERNAL) Return C{a + b} as 2-tuple (sum, residual).
234
246
  '''
235
247
  s = a + b
236
- if not _isfinite(s):
237
- u = unstr(_2sum, a, b)
238
- t = Fmt.PARENSPACED(_not_finite_, s)
239
- raise _OverflowError(u, txt=t)
240
- if fabs(a) < fabs(b):
241
- a, b = b, a
242
- return s, (b - (s - a))
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)
243
255
 
244
256
 
245
257
  class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
@@ -266,7 +278,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
266
278
  _n = 0
267
279
  # _ps = [] # partial sums
268
280
  # _ps_max = 0 # max(Fsum._ps_max, len(Fsum._ps))
269
- _ratio = None
281
+ _ratio = None # see method _raiser
270
282
  _recursive = bool(_getenv('PYGEODESY_FSUM_RECURSIVE', NN))
271
283
  _RESIDUAL = max(float(_getenv('PYGEODESY_FSUM_RESIDUAL', _0_0)), _0_0)
272
284
 
@@ -289,12 +301,12 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
289
301
  self.RESIDUAL(r) # ... ResidualError
290
302
  self._ps = [] # [_0_0], see L{Fsum._fprs}
291
303
  if xs:
292
- self._facc_any(xs, origin=1, up=False)
304
+ self._facc(xs, origin=1, up=False)
293
305
 
294
306
  def __abs__(self):
295
307
  '''Return this instance' absolute value as an L{Fsum}.
296
308
  '''
297
- s = _fsum(self._ps_1()) # == self._cmp_0(0, ...)
309
+ s = _fsum(self._ps_1primed()) # == self._cmp_0(0, ...)
298
310
  return (-self) if s < 0 else self._copy_2(self.__abs__)
299
311
 
300
312
  def __add__(self, other):
@@ -478,13 +490,15 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
478
490
  # Luciano Ramalho, "Fluent Python", O'Reilly, 2nd Ed, 2022 p. 567
479
491
  return _NotImplemented(self)
480
492
 
481
- def __ipow__(self, other, *mod): # PYCHOK 2 vs 3 args
493
+ def __ipow__(self, other, *mod, **raiser): # PYCHOK 2 vs 3 args
482
494
  '''Apply C{B{self} **= B{other}} to this instance.
483
495
 
484
496
  @arg other: The exponent (L{Fsum} or C{scalar}).
485
497
  @arg mod: Optional modulus (C{int} or C{None}) for the
486
498
  3-argument C{pow(B{self}, B{other}, B{mod})}
487
499
  version.
500
+ @kwarg raiser: Use C{B{raiser}=False} to ignore L{ResidualError}s
501
+ (C{bool}), see also method L{RESIDUAL}.
488
502
 
489
503
  @return: This instance, updated (L{Fsum}).
490
504
 
@@ -513,7 +527,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
513
527
  @see: CPython function U{float_pow<https://GitHub.com/
514
528
  python/cpython/blob/main/Objects/floatobject.c>}.
515
529
  '''
516
- return self._fpow(other, _pow_op_ + _fset_op_, *mod)
530
+ return self._fpow(other, _pow_op_ + _fset_op_, *mod, **raiser)
517
531
 
518
532
  def __isub__(self, other):
519
533
  '''Apply C{B{self} -= B{other}} to this instance.
@@ -533,10 +547,12 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
533
547
  '''
534
548
  return iter(self.partials)
535
549
 
536
- def __itruediv__(self, other):
550
+ def __itruediv__(self, other, **raiser):
537
551
  '''Apply C{B{self} /= B{other}} to this instance.
538
552
 
539
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}.
540
556
 
541
557
  @return: This instance, updated (L{Fsum}).
542
558
 
@@ -553,7 +569,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
553
569
 
554
570
  @see: Method L{Fsum.__ifloordiv__}.
555
571
  '''
556
- return self._ftruediv(other, _truediv_op_ + _fset_op_)
572
+ return self._ftruediv(other, _truediv_op_ + _fset_op_, **raiser)
557
573
 
558
574
  def __le__(self, other):
559
575
  '''Compare this with an other instance or C{scalar}.
@@ -689,13 +705,13 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
689
705
  f = self._copy_2r(other, self.__rsub__)
690
706
  return f._fsub(self, _sub_op_)
691
707
 
692
- def __rtruediv__(self, other):
708
+ def __rtruediv__(self, other, **raiser):
693
709
  '''Return C{B{other} / B{self}} as an L{Fsum}.
694
710
 
695
711
  @see: Method L{Fsum.__itruediv__}.
696
712
  '''
697
713
  f = self._copy_2r(other, self.__rtruediv__)
698
- return f._ftruediv(self, _truediv_op_)
714
+ return f._ftruediv(self, _truediv_op_, **raiser)
699
715
 
700
716
  def __str__(self):
701
717
  '''Return the default C{str(self)}.
@@ -714,17 +730,19 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
714
730
  f = self._copy_2(self.__sub__)
715
731
  return f._fsub(other, _sub_op_)
716
732
 
717
- def __truediv__(self, other):
733
+ def __truediv__(self, other, **raiser):
718
734
  '''Return C{B{self} / B{other}} as an L{Fsum}.
719
735
 
720
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}.
721
739
 
722
740
  @return: The quotient (L{Fsum}).
723
741
 
724
742
  @see: Method L{Fsum.__itruediv__}.
725
743
  '''
726
744
  f = self._copy_2(self.__truediv__)
727
- return f._ftruediv(other, _truediv_op_)
745
+ return f._ftruediv(other, _truediv_op_, **raiser)
728
746
 
729
747
  __trunc__ = __int__
730
748
 
@@ -773,15 +791,12 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
773
791
  '''(INTERNAL) Return C{scalar(self - B{other})} for 0-comparison.
774
792
  '''
775
793
  if isinstance(other, Fsum):
776
- s = _fsum(self._ps_1(*other._ps))
777
- elif isscalar(other):
778
- if other:
779
- s = _fsum(self._ps_1(other))
780
- else:
781
- s, r = self._fprs2
782
- 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))
783
797
  else:
784
- raise self._TypeError(op, other) # txt=_invalid_
798
+ s, r = self._fprs2
799
+ s = _signOf(s, -r)
785
800
  return s
786
801
 
787
802
  def copy(self, deep=False, name=NN):
@@ -790,8 +805,10 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
790
805
  @return: The copy (L{Fsum}).
791
806
  '''
792
807
  f = _Named.copy(self, deep=deep, name=name)
793
- f._ps = list(self._ps) # separate list
794
- f._n = self._n if deep else 1
808
+ if f._ps is self._ps:
809
+ f._ps = list(self._ps) # separate list
810
+ if not deep:
811
+ f._n = 1
795
812
  return f
796
813
 
797
814
  def _copy_2(self, which, name=NN):
@@ -817,11 +834,13 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
817
834
  # if R is not Fsum._RESIDUAL:
818
835
  # self._RESIDUAL = R
819
836
 
820
- def divmod(self, other):
837
+ def divmod(self, other, **raiser):
821
838
  '''Return C{divmod(B{self}, B{other})} as 2-tuple C{(quotient,
822
839
  remainder)}.
823
840
 
824
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}.
825
844
 
826
845
  @return: A L{DivMod2Tuple}C{(div, mod)}, with quotient C{div}
827
846
  an C{int} in Python 3+ or C{float} in Python 2- and
@@ -830,7 +849,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
830
849
  @see: Method L{Fsum.__itruediv__}.
831
850
  '''
832
851
  f = self._copy_2(self.divmod)
833
- return f._fdivmod2(other, _divmod_op_)
852
+ return f._fdivmod2(other, _divmod_op_, **raiser)
834
853
 
835
854
  def _Error(self, op, other, Error, **txt_cause):
836
855
  '''(INTERNAL) Format an B{C{Error}} for C{{self} B{op} B{other}}.
@@ -852,66 +871,91 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
852
871
  n = unstr(self.named3, *xs[:3], _ELLIPSIS=len(xs) > 3, **kwds)
853
872
  return E(n, txt=t, cause=X)
854
873
 
855
- def _facc(self, xs, **up):
856
- '''(INTERNAL) Accumulate all C{xs}, known to be scalar.
857
- '''
858
- self._ps_acc(self._ps, xs, **up)
859
- return self
860
-
861
- def _facc_(self, *xs, **up):
862
- '''(INTERNAL) Accumulate all positional C{xs}, known to be scalar.
874
+ def _facc(self, xs, up=True, **origin_X_x):
875
+ '''(INTERNAL) Accumulate more C{scalars} or L{Fsum}s.
863
876
  '''
864
877
  if xs:
865
- self._ps_acc(self._ps, xs, **up)
878
+ _x = _2floats(xs, **origin_X_x) # PYCHOK yield
879
+ ps = self._ps
880
+ ps[:] = self._ps_acc(list(ps), _x, up=up)
866
881
  return self
867
882
 
868
- def _facc_any(self, xs, up=True, **origin_X_x):
869
- '''(INTERNAL) Accumulate more C{scalars} or L{Fsum}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.
870
886
  '''
871
- self._ps[:] = self._ps_acc(list(self._ps),
872
- _2floats(xs, **origin_X_x), up=up) # PYCHOK yield
873
- return 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)
874
890
 
875
- def _facc_any_neg(self, xs, up=True, **origin):
891
+ def _facc_neg(self, xs, up=True, **origin):
876
892
  '''(INTERNAL) Accumulate more C{scalars} or L{Fsum}s, negated.
877
893
  '''
878
- def _neg(x):
879
- return -x
894
+ if xs:
895
+ def _neg(x):
896
+ return -x
880
897
 
881
- self._ps[:] = self._ps_acc(list(self._ps), map(_neg,
882
- _2floats(xs, **origin)), up=up) # PYCHOK yield
898
+ _x = _2floats(xs, **origin) # PYCHOK yield
899
+ ps = self._ps
900
+ ps[:] = self._ps_acc(list(ps), map(_neg, _x), up=up)
883
901
  return self
884
902
 
885
- def _facc_power(self, power, xs, which): # in .fmath
903
+ def _facc_power(self, power, xs, which, **raiser): # in .fmath
886
904
  '''(INTERNAL) Add each C{xs} as C{float(x**power)}.
887
905
  '''
888
- p = power
889
- if isinstance(p, Fsum):
890
- if p.is_exact:
891
- return self._facc_power(p._fprs, xs, which)
892
- _Pow = Fsum._pow_any
893
- elif isint(p, both=True) and p >= 0:
894
- _Pow, p = Fsum._pow_int, int(p)
895
- else:
896
- _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
897
920
 
898
- if p:
899
- from math import pow as _pow
900
- op = which.__name__
901
- _Fs = Fsum
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__
902
927
 
903
928
  def _X(X):
904
- f = _Pow(X, p, power, op)
929
+ f = _Pow(X, p, power, op, **raiser)
905
930
  return f._ps if isinstance(f, _Fs) else (f,)
906
931
 
907
932
  def _x(x):
908
- 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
909
939
 
910
- f = self._facc_any(xs, origin=1, _X=_X, _x=_x)
940
+ f = self._facc(xs, origin=1, _X=_X, _x=_x)
911
941
  else:
912
- f = self._facc_(float(len(xs))) # x**0 == 1
942
+ f = self._facc_scalar_(float(len(xs))) # x**0 == 1
913
943
  return f
914
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)
957
+ return self
958
+
915
959
  # def _facc_up(self, up=True):
916
960
  # '''(INTERNAL) Update the C{partials}, by removing
917
961
  # and re-accumulating the final C{partial}.
@@ -920,7 +964,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
920
964
  # p = self._ps.pop()
921
965
  # if p:
922
966
  # n = self._n
923
- # self._facc_(p, up=False)
967
+ # self._facc_scalar_(p, up=False)
924
968
  # self._n = n
925
969
  # break
926
970
  # return self._update() if up else self # ._fpsqz()
@@ -942,11 +986,11 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
942
986
  @raise ValueError: Invalid or non-finite B{C{xs}} value.
943
987
  '''
944
988
  if isinstance(xs, Fsum):
945
- self._facc(xs._ps) # tuple
989
+ self._facc_scalar(xs._ps) # tuple
946
990
  elif isscalar(xs): # for backward compatibility
947
- self._facc_(_2float(x=xs)) # PYCHOK no cover
948
- elif xs:
949
- self._facc_any(xs)
991
+ self._facc_scalar_(_2float(x=xs)) # PYCHOK no cover
992
+ elif xs: # assert isiterable(xs)
993
+ self._facc(xs)
950
994
  return self
951
995
 
952
996
  def fadd_(self, *xs):
@@ -965,30 +1009,29 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
965
1009
 
966
1010
  @raise ValueError: Invalid or non-finite B{C{xs}} value.
967
1011
  '''
968
- return self._facc_any(xs, origin=1)
1012
+ return self._facc_1(xs)
969
1013
 
970
1014
  def _fadd(self, other, op, **up): # in .fmath.Fhorner
971
1015
  '''(INTERNAL) Apply C{B{self} += B{other}}.
972
1016
  '''
973
1017
  if isinstance(other, Fsum):
974
- self._facc(other._ps, **up) # tuple
975
- elif not isscalar(other):
976
- raise self._TypeError(op, other) # txt=_invalid_
977
- elif other:
978
- self._facc_(other, **up)
1018
+ self._facc_scalar(other._ps, **up) # tuple
1019
+ elif self._scalar(other, op):
1020
+ self._facc_scalar_(other, **up)
979
1021
  return self
980
1022
 
981
1023
  fcopy = copy # for backward compatibility
982
1024
  fdiv = __itruediv__ # for backward compatibility
983
1025
  fdivmod = __divmod__ # for backward compatibility
984
1026
 
985
- def _fdivmod2(self, other, op):
1027
+ def _fdivmod2(self, other, op, **raiser):
986
1028
  '''(INTERNAL) Apply C{B{self} %= B{other}} and return a L{DivMod2Tuple}.
987
1029
  '''
988
1030
  # result mostly follows CPython function U{float_divmod
989
1031
  # <https://GitHub.com/python/cpython/blob/main/Objects/floatobject.c>},
990
1032
  # but at least divmod(-3, 2) equals Cpython's result (-2, 1).
991
- 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
992
1035
  if q: # == float // other == floor(float / other)
993
1036
  self -= other * q
994
1037
 
@@ -1012,8 +1055,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1012
1055
  def fint(self, raiser=True, **name):
1013
1056
  '''Return this instance' current running sum as C{integer}.
1014
1057
 
1015
- @kwarg raiser: If C{True} throw a L{ResidualError} if the
1016
- I{integer} residual is non-zero (C{bool}).
1058
+ @kwarg raiser: Use C{B{raiser}=False} to ignore L{ResidualError}s
1059
+ (C{bool}), see also method L{RESIDUAL}.
1017
1060
  @kwarg name: Optional name (C{str}), overriding C{"fint"}.
1018
1061
 
1019
1062
  @return: The C{integer} (L{Fsum}).
@@ -1047,7 +1090,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1047
1090
  '''
1048
1091
  s, r = self._fprs2
1049
1092
  i = int(s)
1050
- r = _fsum(self._ps_1(i)) if r else float(s - i)
1093
+ r = _fsum(self._ps_1primed(i)) if r else float(s - i)
1051
1094
  return i, (r or INT0) # Fsum2Tuple?
1052
1095
 
1053
1096
  @deprecated_property_RO
@@ -1073,10 +1116,10 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1073
1116
 
1074
1117
  # floordiv = __floordiv__ # for naming consistency
1075
1118
 
1076
- def _floordiv(self, other, op): # rather _ffloordiv?
1119
+ def _floordiv(self, other, op, **raiser): # rather _ffloordiv?
1077
1120
  '''Apply C{B{self} //= B{other}}.
1078
1121
  '''
1079
- q = self._ftruediv(other, op) # == self
1122
+ q = self._ftruediv(other, op, **raiser) # == self
1080
1123
  return self._fset(q.floor) # floor(q)
1081
1124
 
1082
1125
  fmul = __imul__ # for backward compatibility
@@ -1091,41 +1134,42 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1091
1134
  f = other._mul_scalar(self._ps[0], op)
1092
1135
  else: # len(other._ps) == len(self._ps) == 1
1093
1136
  f = self._finite(self._ps[0] * other._ps[0])
1094
- elif isscalar(other):
1095
- f = self._mul_scalar(other, op) if other != _1_0 else self
1096
1137
  else:
1097
- raise self._TypeError(op, other) # txt=_invalid_
1138
+ s = self._scalar(other, op)
1139
+ f = self._mul_scalar(s, op)
1098
1140
  return self._fset(f) # n=len(self) + 1
1099
1141
 
1100
- def fover(self, over):
1142
+ def fover(self, over, **raiser):
1101
1143
  '''Apply C{B{self} /= B{over}} and summate.
1102
1144
 
1103
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}.
1104
1148
 
1105
1149
  @return: Precision running sum (C{float}).
1106
1150
 
1107
1151
  @see: Methods L{Fsum.fsum} and L{Fsum.__itruediv__}.
1108
1152
  '''
1109
- return float(self.fdiv(over)._fprs)
1153
+ return float(self.fdiv(over, **raiser)._fprs)
1110
1154
 
1111
1155
  fpow = __ipow__ # for backward compatibility
1112
1156
 
1113
- def _fpow(self, other, op, *mod):
1157
+ def _fpow(self, other, op, *mod, **raiser):
1114
1158
  '''Apply C{B{self} **= B{other}}, optional B{C{mod}} or C{None}.
1115
1159
  '''
1116
1160
  if mod:
1117
1161
  if mod[0] is not None: # == 3-arg C{pow}
1118
- f = self._pow_2_3(self, other, other, op, *mod)
1162
+ f = self._pow_2_3(self, other, other, op, *mod, **raiser)
1119
1163
  elif self.is_integer():
1120
1164
  # return an exact C{int} for C{int}**C{int}
1121
1165
  i, _ = self._fint2 # assert _ == 0
1122
1166
  x = _2scalar(other) # C{int}, C{float} or other
1123
- f = self._pow_2_3(i, x, other, op) if isscalar(x) else \
1124
- _Psum_1(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
1125
1169
  else: # mod[0] is None, power(self, other)
1126
- f = self._pow_any(other, other, op)
1127
- else: # pow(self, other) == pow(self, other, None)
1128
- 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)
1129
1173
  return self._fset(f, asis=isint(f)) # n=max(len(self), 1)
1130
1174
 
1131
1175
  @Property_RO
@@ -1149,7 +1193,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1149
1193
  s = _psum(ps)
1150
1194
  n = len(ps) - 2
1151
1195
  if n > 0:
1152
- r = _fsum(self._ps_1(s)) or INT0
1196
+ r = _fsum(self._ps_1primed(s)) or INT0
1153
1197
  return Fsum2Tuple(s, r)
1154
1198
  if n == 0: # len(ps) == 2
1155
1199
  ps[:] = _2ps(*_2sum(*ps))
@@ -1187,7 +1231,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1187
1231
  '''(INTERNAL) Overwrite this instance with an other or a C{scalar}.
1188
1232
  '''
1189
1233
  if other is self:
1190
- pass # from ._fmul, ._ftruediv and ._pow_scalar
1234
+ pass # from ._fmul, ._ftruediv and ._pow_0_1
1191
1235
  elif isinstance(other, Fsum):
1192
1236
  self._ps[:] = other._ps
1193
1237
  self._n = n or other._n
@@ -1206,7 +1250,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1206
1250
  # Property's _fset zaps the value just set by the @setter
1207
1251
  self.__dict__.update(_fint2=t, _fprs=s, _fprs2=Fsum2Tuple(s, INT0))
1208
1252
  else: # PYCHOK no cover
1209
- raise self._TypeError(_fset_op_, other) # txt=_invalid_
1253
+ raise self._TypeError(_fset_op_, other) # AssertionError
1210
1254
  return self
1211
1255
 
1212
1256
  def _fset_ps(self, other, n=0): # in .fmath
@@ -1220,6 +1264,13 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1220
1264
  self._n = n or 1
1221
1265
  return self
1222
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
1273
+
1223
1274
  def fsub(self, xs=()):
1224
1275
  '''Subtract an iterable of C{scalar} or L{Fsum} instances from
1225
1276
  this instance.
@@ -1231,7 +1282,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1231
1282
 
1232
1283
  @see: Method L{Fsum.fadd}.
1233
1284
  '''
1234
- return self._facc_any_neg(xs) if xs else self
1285
+ return self._facc_neg(xs)
1235
1286
 
1236
1287
  def fsub_(self, *xs):
1237
1288
  '''Subtract all positional C{scalar} or L{Fsum} instances from
@@ -1244,7 +1295,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1244
1295
 
1245
1296
  @see: Method L{Fsum.fadd}.
1246
1297
  '''
1247
- return self._facc_any_neg(xs, origin=1) if xs else self
1298
+ return self._fsub(xs[0], _sub_op_) if len(xs) == 1 else \
1299
+ self._facc_neg(xs, origin=1)
1248
1300
 
1249
1301
  def _fsub(self, other, op):
1250
1302
  '''(INTERNAL) Apply C{B{self} -= B{other}}.
@@ -1253,11 +1305,9 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1253
1305
  if other is self: # or other._fprs2 == self._fprs2:
1254
1306
  self._fset(_0_0) # n=len(self) * 2, self -= self
1255
1307
  elif other._ps:
1256
- self._facc(other._ps_neg)
1257
- elif not isscalar(other):
1258
- raise self._TypeError(op, other) # txt=_invalid_
1259
- elif self._finite(other, op):
1260
- self._facc_(-other)
1308
+ self._facc_scalar(other._ps_neg)
1309
+ elif self._scalar(other, op):
1310
+ self._facc_scalar_(-self._finite(other, op))
1261
1311
  return self
1262
1312
 
1263
1313
  def fsum(self, xs=()):
@@ -1272,8 +1322,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1272
1322
 
1273
1323
  @note: Accumulation can continue after summation.
1274
1324
  '''
1275
- f = self._facc_any(xs) if xs else self
1276
- return f._fprs
1325
+ return self._facc(xs)._fprs
1277
1326
 
1278
1327
  def fsum_(self, *xs):
1279
1328
  '''Add all positional C{scalar} or L{Fsum} instances and summate.
@@ -1285,15 +1334,14 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1285
1334
 
1286
1335
  @see: Methods L{Fsum.fsum}, L{Fsum.Fsum_} and L{Fsum.fsumf_}.
1287
1336
  '''
1288
- f = self._facc_any(xs, origin=1) if xs else self
1289
- return f._fprs
1337
+ return self._facc_1(xs)._fprs
1290
1338
 
1291
1339
  def Fsum_(self, *xs):
1292
1340
  '''Like method L{Fsum.fsum_} but returning an L{Fsum}.
1293
1341
 
1294
1342
  @return: Current, precision running sum (L{Fsum}).
1295
1343
  '''
1296
- return self._facc_any(xs, origin=1)._copy_2(self.Fsum_)
1344
+ return self._facc_1(xs)._copy_2(self.Fsum_)
1297
1345
 
1298
1346
  def fsum2(self, xs=(), name=NN):
1299
1347
  '''Add more C{scalar} or L{Fsum} instances and return the
@@ -1311,11 +1359,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1311
1359
 
1312
1360
  @see: Methods L{Fsum.fint2}, L{Fsum.fsum} and L{Fsum.fsum2_}
1313
1361
  '''
1314
- f = self._facc_any(xs) if xs else self
1315
- t = f._fprs2
1316
- if name:
1317
- t = t.dup(name=name)
1318
- return t
1362
+ t = self._facc(xs)._fprs2
1363
+ return t.dup(name=name) if name else t
1319
1364
 
1320
1365
  def fsum2_(self, *xs):
1321
1366
  '''Add any positional C{scalar} or L{Fsum} instances and return
@@ -1330,62 +1375,58 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1330
1375
 
1331
1376
  @see: Methods L{Fsum.fsum_} and L{Fsum.fsum}.
1332
1377
  '''
1333
- return self._fsum2f_any(xs, self._facc_any, origin=1)
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
1384
+ if xs:
1385
+ s, r = _f(xs, **origin)._fprs2
1386
+ return s, _2delta(s - p, r - q) # _fsum(_1primed((s, -p, r, -q))
1387
+ else:
1388
+ return p, _0_0
1334
1389
 
1335
1390
  def fsumf_(self, *xs):
1336
- '''Like method L{Fsum.fsum_} but only for I{known} C{float B{xs}}.
1391
+ '''Like method L{Fsum.fsum_} but only for C{B{xs}}, I{known to be scalar}.
1337
1392
  '''
1338
- f = self._facc(xs) if xs else self
1339
- return f._fprs
1393
+ return self._facc_scalar(xs)._fprs
1340
1394
 
1341
1395
  def Fsumf_(self, *xs):
1342
- '''Like method L{Fsum.Fsum_} but only for I{known} C{float B{xs}}.
1396
+ '''Like method L{Fsum.Fsum_} but only for C{B{xs}}, I{known to be scalar}.
1343
1397
  '''
1344
- return self._facc(xs)._copy_2(self.Fsumf_)
1398
+ return self._facc_scalar(xs)._copy_2(self.Fsumf_)
1345
1399
 
1346
1400
  def fsum2f_(self, *xs):
1347
- '''Like method L{Fsum.fsum2_} but only for I{known} C{float B{xs}}.
1401
+ '''Like method L{Fsum.fsum2_} but only for C{B{xs}}, I{known to be scalar}.
1348
1402
  '''
1349
- return self._fsum2f_any(xs, self._facc)
1350
-
1351
- def _fsum2f_any(self, xs, _facc, **origin):
1352
- '''(INTERNAL) Helper for L{Fsum.fsum2_} and L{Fsum.fsum2f_}.
1353
- '''
1354
- p, q = self._fprs2
1355
- if xs:
1356
- s, r = _facc(xs, **origin)._fprs2
1357
- return s, _2delta(s - p, r - q) # _fsum(_1primed((s, -p, r, -q))
1358
- else:
1359
- return p, _0_0
1403
+ return self._fsum2(xs, self._facc_scalar, origin=1)
1360
1404
 
1361
1405
  # ftruediv = __itruediv__ # for naming consistency?
1362
1406
 
1363
- def _ftruediv(self, other, op):
1407
+ def _ftruediv(self, other, op, **raiser):
1364
1408
  '''(INTERNAL) Apply C{B{self} /= B{other}}.
1365
1409
  '''
1366
1410
  n = _1_0
1367
1411
  if isinstance(other, Fsum):
1368
1412
  if other is self or other == self:
1369
- return self._fset(_1_0) # n=len(self)
1413
+ return self._fset(n) # n=len(self)
1370
1414
  d, r = other._fprs2
1371
1415
  if r:
1372
1416
  if d:
1373
- if self._raiser(r, d):
1417
+ if self._raiser(r, d, **raiser):
1374
1418
  raise self._ResidualError(op, other, r)
1375
1419
  d, n = other.as_integer_ratio()
1376
1420
  else: # PYCHOK no cover
1377
1421
  d = r
1378
- elif isscalar(other):
1379
- d = other
1380
- else: # PYCHOK no cover
1381
- raise self._TypeError(op, other) # txt=_invalid_
1422
+ else:
1423
+ d = self._scalar(other, op)
1382
1424
  try:
1383
- s = 0 if isinf(d) else (
1384
- d if isnan(d) else self._finite(n / d))
1425
+ s = n / d
1385
1426
  except Exception as X:
1386
1427
  raise self._ErrorX(X, op, other)
1387
- f = self._mul_scalar(s, _mul_op_) # handles 0, NAN, etc.
1388
- 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
1389
1430
 
1390
1431
  @property_RO
1391
1432
  def imag(self):
@@ -1399,7 +1440,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1399
1440
  '''Return this instance' current running sum as C{int} or C{float}.
1400
1441
 
1401
1442
  @kwarg raiser: If C{True} throw a L{ResidualError} if the
1402
- residual is non-zero.
1443
+ residual is non-zero (C{bool}).
1403
1444
 
1404
1445
  @return: This C{integer} sum if this instance C{is_integer},
1405
1446
  otherwise return the C{float} sum if the residual
@@ -1479,12 +1520,14 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1479
1520
  '''
1480
1521
  return tuple(self._ps)
1481
1522
 
1482
- def pow(self, x, *mod):
1523
+ def pow(self, x, *mod, **raiser):
1483
1524
  '''Return C{B{self}**B{x}} as L{Fsum}.
1484
1525
 
1485
1526
  @arg x: The exponent (L{Fsum} or C{scalar}).
1486
1527
  @arg mod: Optional modulus (C{int} or C{None}) for the 3-argument
1487
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}.
1488
1531
 
1489
1532
  @return: The C{pow(self, B{x})} or C{pow(self, B{x}, *B{mod})}
1490
1533
  result (L{Fsum}).
@@ -1493,17 +1536,35 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1493
1536
  C{integer} L{Fsum} provided this instance C{is_integer}
1494
1537
  or set to C{integer} by an L{Fsum.fint} call.
1495
1538
 
1496
- @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}.
1497
1541
  '''
1498
1542
  f = self._copy_2(self.pow)
1499
- 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)
1544
+
1545
+ def _pow(self, other, unused, op, **raiser):
1546
+ '''Return C{B{self} ** B{other}}.
1547
+ '''
1548
+ if isinstance(other, Fsum):
1549
+ x, r = other._fprs2
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)
1553
+ if r:
1554
+ f *= self._pow_scalar(r, other, op, **raiser)
1555
+ elif self._scalar(other, op):
1556
+ x = self._finite(other, op)
1557
+ f = self._pow_scalar(x, other, op, **raiser)
1558
+ else:
1559
+ f = self._pow_0_1(0, other)
1560
+ return f
1500
1561
 
1501
1562
  def _pow_0_1(self, x, other):
1502
1563
  '''(INTERNAL) Return B{C{self}**1} or C{B{self}**0 == 1.0}.
1503
1564
  '''
1504
1565
  return self if x else (1 if isint(other) and self.is_integer() else _1_0)
1505
1566
 
1506
- def _pow_2_3(self, b, x, other, op, *mod):
1567
+ def _pow_2_3(self, b, x, other, op, *mod, **raiser):
1507
1568
  '''(INTERNAL) 2-arg C{pow(B{b}, scalar B{x})} and 3-arg C{pow(B{b},
1508
1569
  B{x}, int B{mod} or C{None})}, embellishing errors.
1509
1570
  '''
@@ -1511,7 +1572,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1511
1572
  if mod: # b, x, mod all C{int}, unless C{mod} is C{None}
1512
1573
  m = mod[0]
1513
1574
  b, r = b._fprs2 if m is None else b._fint2
1514
- if r and self._raiser(r, b):
1575
+ if r and self._raiser(r, b, **raiser):
1515
1576
  t = _non_zero_ if m is None else _integer_
1516
1577
  raise ResidualError(_stresidual(t, r, mod=m), txt=None)
1517
1578
  x = _2scalar(x, _raiser=self._raiser, mod=m)
@@ -1524,24 +1585,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1524
1585
  except Exception as X:
1525
1586
  raise self._ErrorX(X, op, other, *mod)
1526
1587
 
1527
- def _pow_any(self, other, unused, op):
1528
- '''Return C{B{self} ** B{other}}.
1529
- '''
1530
- if isinstance(other, Fsum):
1531
- x, r = other._fprs2
1532
- if r and self._raiser(r, x):
1533
- raise self._ResidualError(op, other, r)
1534
- f = self._pow_scalar(x, other, op)
1535
- if r:
1536
- f *= self._pow_scalar(r, other, op)
1537
- elif isscalar(other):
1538
- x = self._finite(other, op)
1539
- f = self._pow_scalar(x, other, op)
1540
- else:
1541
- raise self._TypeError(op, other) # txt=_invalid_
1542
- return f
1543
-
1544
- def _pow_int(self, x, other, op):
1588
+ def _pow_int(self, x, other, op, **raiser):
1545
1589
  '''(INTERNAL) Return C{B{self} **= B{x}} for C{int B{x} >= 0}.
1546
1590
  '''
1547
1591
  # assert isint(x) and x >= 0
@@ -1565,13 +1609,13 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1565
1609
  else: # self**1 or self**0 == 1 or _1_0
1566
1610
  f = self._pow_0_1(x, other)
1567
1611
  elif ps: # self._ps[0]**x
1568
- f = self._pow_2_3(ps[0], x, other, op)
1612
+ f = self._pow_2_3(ps[0], x, other, op, **raiser)
1569
1613
  else: # PYCHOK no cover
1570
1614
  # 0**pos_int == 0, but 0**0 == 1
1571
1615
  f = 0 if x else 1
1572
1616
  return f
1573
1617
 
1574
- def _pow_scalar(self, x, other, op):
1618
+ def _pow_scalar(self, x, other, op, **raiser):
1575
1619
  '''(INTERNAL) Return C{self**B{x}} for C{scalar B{x}}.
1576
1620
  '''
1577
1621
  s, r = self._fprs2
@@ -1580,41 +1624,29 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1580
1624
  y = abs(x)
1581
1625
  if y > 1:
1582
1626
  if r:
1583
- f = self._pow_int(y, other, op)
1627
+ f = self._pow_int(y, other, op, **raiser)
1584
1628
  if x > 0: # > 1
1585
1629
  return f
1586
1630
  # assert x < 0 # < -1
1587
1631
  s, r = f._fprs2 if isinstance(f, Fsum) else (f, 0)
1588
1632
  if r:
1589
- return _Psum_1()._ftruediv(f, op)
1633
+ return _Psum_1()._ftruediv(f, op, **raiser)
1590
1634
  # use **= -1 for the CPython float_pow
1591
1635
  # error if s is zero, and not s = 1 / s
1592
1636
  x = -1
1593
1637
  elif x < 0: # == -1: self**(-1) == 1 / self
1594
1638
  if r:
1595
- return _Psum_1()._ftruediv(self, op)
1639
+ return _Psum_1()._ftruediv(self, op, **raiser)
1596
1640
  else: # self**1 or self**0
1597
1641
  return self._pow_0_1(x, other) # self, 1 or 1.0
1598
- elif not isscalar(x): # assert ...
1599
- raise self._TypeError(op, other, txt=_not_scalar_)
1600
- elif r and self._raiser(r, s): # non-zero residual**fractional
1642
+ elif r and self._raiser(r, s, **raiser): # non-zero residual**fractional
1601
1643
  # raise self._ResidualError(op, other, r, fractional_power=x)
1602
1644
  t = _stresidual(_non_zero_, r, fractional_power=x)
1603
1645
  raise self._Error(op, other, ResidualError, txt=t)
1604
1646
  # assert isscalar(s) and isscalar(x)
1605
- return self._pow_2_3(s, x, other, op)
1647
+ return self._pow_2_3(s, x, other, op, **raiser)
1606
1648
 
1607
- def _ps_1(self, *less):
1608
- '''(INTERNAL) Yield partials, 1-primed and subtract any C{less}.
1609
- '''
1610
- yield _1_0
1611
- for p in self._ps:
1612
- yield p
1613
- for p in less:
1614
- yield -p
1615
- yield _N_1_0
1616
-
1617
- def _ps_acc(self, ps, xs, up=True):
1649
+ def _ps_acc(self, ps, xs, up=True, **unused):
1618
1650
  '''(INTERNAL) Accumulate all scalar C{xs} into C{ps}.
1619
1651
  '''
1620
1652
  n = 0
@@ -1639,7 +1671,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1639
1671
 
1640
1672
  def _ps_mul(self, op, *factors):
1641
1673
  '''(INTERNAL) Multiply this instance' C{partials} with
1642
- each of the B{C{factors}}, all known to be scalar.
1674
+ each of the scalar B{C{factors}} and accumulate.
1643
1675
  '''
1644
1676
  def _pfs(ps, fs):
1645
1677
  if len(ps) < len(fs):
@@ -1659,11 +1691,21 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1659
1691
  for p in self._ps:
1660
1692
  yield -p
1661
1693
 
1662
- def _raiser(self, r, s):
1663
- '''(INTERNAL) Does ratio C{r / s} exceed threshold?
1694
+ def _ps_1primed(self, *less):
1695
+ '''(INTERNAL) Yield partials, 1-primed and subtract any C{less} scalars.
1664
1696
  '''
1665
- self._ratio = t = fabs((r / s) if s else r)
1666
- return t > self._RESIDUAL
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)
1667
1709
 
1668
1710
  @property_RO
1669
1711
  def real(self):
@@ -1697,7 +1739,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1697
1739
  C{PYGEODESY_FSUM_RESIDUAL} or if omitted, keep the
1698
1740
  current setting.
1699
1741
 
1700
- @return: The previous C{RESIDUAL} setting (C{float}), default C{0}.
1742
+ @return: The previous C{RESIDUAL} setting (C{float}), default C{0.}.
1701
1743
 
1702
1744
  @raise ValueError: Negative B{C{threshold}}.
1703
1745
 
@@ -1724,6 +1766,37 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
1724
1766
  t = t.replace(_COMMASPACE_R_, _exceeds_R_)
1725
1767
  return self._Error(op, other, ResidualError, txt=t)
1726
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
+
1727
1800
  @property_RO
1728
1801
  def _2scalar(self):
1729
1802
  '''(INTERNAL) Get this instance as C{scalar} or C{as-is}.
@@ -1914,8 +1987,8 @@ def fsum_(*xs, **floats):
1914
1987
 
1915
1988
  @arg xs: Values to be added (C{scalar} or L{Fsum} instances), all
1916
1989
  positional.
1917
- @kwarg floats: Use C{B{floats}=True} iff I{all} B{C{xs}} are known
1918
- to be C{float} scalars (C{bool}).
1990
+ @kwarg floats: Use C{B{floats}=True} iff I{all} B{C{xs}} are I{known
1991
+ to be scalar} (C{bool}).
1919
1992
 
1920
1993
  @return: Precision C{fsum} (C{float}).
1921
1994
 
@@ -1926,7 +1999,8 @@ def fsum_(*xs, **floats):
1926
1999
 
1927
2000
 
1928
2001
  def fsumf_(*xs):
1929
- '''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}.
1930
2004
  '''
1931
2005
  return _fsum(xs) if xs else _0_0
1932
2006
 
@@ -1951,8 +2025,8 @@ def fsum1_(*xs, **floats):
1951
2025
 
1952
2026
  @arg xs: Values to be added (C{scalar} or L{Fsum} instances), all
1953
2027
  positional.
1954
- @kwarg floats: Use C{B{floats}=True} iff I{all} B{C{xs}} are known
1955
- to be C{float} scalars (C{bool}).
2028
+ @kwarg floats: Use C{B{floats}=True} iff I{all} B{C{xs}} are I{known
2029
+ to be scalar} (C{bool}).
1956
2030
 
1957
2031
  @return: Precision C{fsum} (C{float}).
1958
2032
 
@@ -1963,7 +2037,8 @@ def fsum1_(*xs, **floats):
1963
2037
 
1964
2038
 
1965
2039
  def fsum1f_(*xs):
1966
- '''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}.
1967
2042
  '''
1968
2043
  return _fsum(_1primed(xs)) if xs else _0_0
1969
2044