pygeodesy 24.4.12__py2.py3-none-any.whl → 24.4.24__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/fmath.py CHANGED
@@ -6,17 +6,14 @@ u'''Utilities using precision floating point summation.
6
6
  # make sure int/int division yields float quotient, see .basics
7
7
  from __future__ import division as _; del _ # PYCHOK semicolon
8
8
 
9
- from pygeodesy.basics import _copysign, copysign0, isint, len2
9
+ from pygeodesy.basics import _copysign, copysign0, isbool, isint, isscalar, len2
10
10
  from pygeodesy.constants import EPS0, EPS02, EPS1, NAN, PI, PI_2, PI_4, \
11
- _0_0, _0_125, _0_25, _0_5, _1_0, _1_3rd, \
12
- _1_5, _1_6th, _2_0, _2_3rd, _3_0, \
13
- _copysign_0_0, _isfinite, _over, remainder
11
+ _0_0, _0_125, _1_6th, _0_25, _1_3rd, _0_5, _1_0, \
12
+ _1_5, _copysign_0_0, _isfinite, _over, remainder
14
13
  from pygeodesy.errors import _IsnotError, LenError, _TypeError, _ValueError, \
15
14
  _xError, _xkwds_get, _xkwds_pop2
16
- from pygeodesy.fsums import _2float, Fsum, _fsum, fsum, fsum1_, _pow_op_, \
17
- _1primed, Fmt, unstr
18
- from pygeodesy.interns import MISSING, _few_, _h_, _invokation_, _negative_, \
19
- _not_scalar_, _SPACE_, _too_
15
+ from pygeodesy.fsums import _2float, Fsum, fsum, fsum1_, _1primed, Fmt, unstr
16
+ from pygeodesy.interns import MISSING, _few_, _negative_, _not_scalar_, _too_
20
17
  from pygeodesy.lazily import _ALL_LAZY, _sys_version_info2
21
18
  # from pygeodesy.streprs import Fmt, unstr # from .fsums
22
19
  from pygeodesy.units import Int_, _isHeight, _isRadius, Float_ # PYCHOK for .heights
@@ -25,10 +22,11 @@ from math import fabs, sqrt # pow
25
22
  import operator as _operator # in .datums, .trf, .utm
26
23
 
27
24
  __all__ = _ALL_LAZY.fmath
28
- __version__ = '24.04.04'
25
+ __version__ = '24.04.24'
29
26
 
30
27
  # sqrt(2) <https://WikiPedia.org/wiki/Square_root_of_2>
31
28
  _0_4142 = 0.41421356237309504880 # ... sqrt(2) - 1
29
+ _2_3rd = _1_3rd * 2
32
30
  _h_lt_b_ = 'abs(h) < abs(b)'
33
31
 
34
32
 
@@ -41,8 +39,8 @@ class Fdot(Fsum):
41
39
 
42
40
  @arg a: Iterable, list, tuple, etc. (C{scalar}s).
43
41
  @arg b: Other values (C{scalar}s), all positional.
44
- @kwarg name_RESIDUAL: Optional C{B{name}=NN} and
45
- C{B{RESIDUAL}=None}, see L{Fsum.__init__}.
42
+ @kwarg name_RESIDUAL: Optional C{B{name}=NN} and C{B{RESIDUAL}=None},
43
+ see L{Fsum<Fsum.__init__>}.
46
44
 
47
45
  @raise OverflowError: Partial C{2sum} overflow.
48
46
 
@@ -64,8 +62,8 @@ class Fhorner(Fsum):
64
62
  @arg x: Polynomial argument (C{scalar} or C{Fsum} instance).
65
63
  @arg cs: Polynomial coeffients (C{scalar} or C{Fsum}
66
64
  instances), all positional.
67
- @kwarg name_RESIDUAL: Optional C{B{name}=NN} and
68
- C{B{RESIDUAL}=None}, see L{Fsum.__init__}.
65
+ @kwarg name_RESIDUAL: Optional C{B{name}=NN} and C{B{RESIDUAL}=None},
66
+ see L{Fsum<Fsum.__init__>}.
69
67
 
70
68
  @raise OverflowError: Partial C{2sum} overflow.
71
69
 
@@ -92,32 +90,30 @@ class Fhorner(Fsum):
92
90
  else: # x == 0
93
91
  self._fadd(cs[0], op)
94
92
  else:
95
- self._fset(_0_0)
93
+ self._fset_ps(_0_0)
96
94
 
97
95
 
98
96
  class Fhypot(Fsum):
99
- '''Precision summation and hypotenuse, default C{power=2}.
97
+ '''Precision summation and hypotenuse, default C{root=2}.
100
98
  '''
101
- def __init__(self, *xs, **power_name_RESIDUAL):
102
- '''New L{Fhypot} hypotenuse of (the I{power} of) several components.
99
+ def __init__(self, *xs, **root_name_RESIDUAL_raiser):
100
+ '''New L{Fhypot} hypotenuse of (the I{root} of) several components.
103
101
 
104
- @arg xs: One or more components (each a C{scalar} or an C{Fsum}
105
- instance).
106
- @kwarg power_name_RESIDUAL: Optional, C{scalar} exponent and
107
- root order C{B{power}=2}, a C{B{name}=NN} and
108
- C{B{RESIDUAL}=None}, see L{Fsum.__init__}.
102
+ @arg xs: One or more components (each a C{scalar} or an C{Fsum} instance).
103
+ @kwarg root_name_RESIDUAL_raiser: Optional, exponent and C{B{root}=2} order,
104
+ C{B{name}=NN}, C{B{RESIDUAL}=None} and C{B{raiser}=True}, see
105
+ class L{Fsum<Fsum.__init__>} and method L{root<Fsum.root>}.
109
106
  '''
107
+ r = None # _xkwds_pop2 error
110
108
  try:
111
- p, kwds = _xkwds_pop2(power_name_RESIDUAL, power=2)
112
- Fsum.__init__(self, **kwds)
109
+ r, kwds = _xkwds_pop2(root_name_RESIDUAL_raiser, root=2)
110
+ r, kwds = _xkwds_pop2(kwds, power=r) # for backward compatibility
111
+ raiser = _Fsum__init__(self, **kwds)
113
112
  if xs:
114
- r = _1_0 / p
115
- self._facc_power(p, xs, Fhypot)
116
- self._fpow(r, _pow_op_)
117
- else:
118
- self._fset(_0_0)
119
- except Exception as x:
120
- raise self._ErrorXs(x, xs, power=p)
113
+ self._facc_power(r, xs, Fhypot, **raiser)
114
+ self._fset(self.root(r, **raiser))
115
+ except Exception as X:
116
+ raise self._ErrorXs(X, xs, root=r)
121
117
 
122
118
 
123
119
  class Fpolynomial(Fsum):
@@ -128,10 +124,10 @@ class Fpolynomial(Fsum):
128
124
  M{sum(cs[i] * x**i for i=0..len(cs)-1)}.
129
125
 
130
126
  @arg x: Polynomial argument (C{scalar} or L{Fsum}).
131
- @arg cs: Polynomial coeffients (each a C{scalar} or
132
- an L{Fsum} instance), all positional.
133
- @kwarg name_RESIDUAL: Optional C{B{name}=NN} and
134
- C{B{RESIDUAL}=None}, see L{Fsum.__init__}.
127
+ @arg cs: Polynomial coeffients (each a C{scalar} or an L{Fsum} instance),
128
+ all positional.
129
+ @kwarg name_RESIDUAL: Optional C{B{name}=NN} and C{B{RESIDUAL}=None},
130
+ see L{Fsum<Fsum.__init__>}.
135
131
 
136
132
  @raise OverflowError: Partial C{2sum} overflow.
137
133
 
@@ -147,83 +143,85 @@ class Fpolynomial(Fsum):
147
143
  if n > 0:
148
144
  self.fadd(_1map_mul(cs[1:], _powers(x, n)))
149
145
  elif n < 0:
150
- self._fset(_0_0)
146
+ self._fset_ps(_0_0)
151
147
 
152
148
 
153
149
  class Fpowers(Fsum):
154
150
  '''Precision summation of powers, optimized for C{power=2, 3 and 4}.
155
151
  '''
156
- def __init__(self, power, *xs, **name_RESIDUAL):
152
+ def __init__(self, power, *xs, **name_RESIDUAL_raiser):
157
153
  '''New L{Fpowers} sum of (the I{power} of) several values.
158
154
 
159
155
  @arg power: The exponent (C{scalar} or L{Fsum}).
160
- @arg xs: One or more values (each a C{scalar} or an
161
- C{Fsum} instance).
162
- @kwarg name_RESIDUAL: Optional C{B{name}=NN} and
163
- C{B{RESIDUAL}=None}, see L{Fsum.__init__}.
156
+ @arg xs: One or more values (each a C{scalar} or an C{Fsum} instance).
157
+ @kwarg name_RESIDUAL_raiser: Optional C{B{name}=NN}, C{B{RESIDUAL}=None} and
158
+ C{B{raiser}=True}, see L{Fsum<Fsum.__init__>} and L{fpow<Fsum.fpow>}.
164
159
  '''
165
160
  try:
166
- Fsum.__init__(self, **name_RESIDUAL)
161
+ raiser = _Fsum__init__(self, **name_RESIDUAL_raiser)
167
162
  if xs:
168
- self._facc_power(power, xs, Fpowers) # x**0 == 1
169
- else:
170
- self._fset(_0_0)
171
- except Exception as x:
172
- raise self._ErrorXs(x, xs, power=power)
163
+ self._facc_power(power, xs, Fpowers, **raiser) # x**0 == 1
164
+ except Exception as X:
165
+ raise self._ErrorXs(X, xs, power=power)
173
166
 
174
167
 
175
- class Fn_rt(Fsum):
176
- '''N-th root of a precision summation.
168
+ class Froot(Fsum):
169
+ '''The root of a precision summation.
177
170
  '''
178
- def __init__(self, root, *xs, **name_RESIDUAL):
179
- '''New L{Fn_rt} root of a precision sum.
171
+ def __init__(self, root, *xs, **name_RESIDUAL_raiser):
172
+ '''New L{Froot} root of a precision sum.
180
173
 
181
- @arg root: The order (C{scalar} or C{Fsum}),
182
- non-zero.
183
- @arg xs: Values to summate (each a C{scalar} or
184
- an C{Fsum} instance).
185
- @kwarg name_RESIDUAL: See L{Fsum.__init__}.
174
+ @arg root: The order (C{scalar} or C{Fsum}), non-zero.
175
+ @arg xs: Values to summate (each a C{scalar} or an C{Fsum} instance).
176
+ @kwarg name_RESIDUAL_raiser: Optional C{B{name}=NN}, C{B{RESIDUAL}=None} and
177
+ C{B{raiser}=True}, see L{Fsum<Fsum.__init__>} and L{fpow<Fsum.fpow>}.
186
178
  '''
187
179
  try:
188
- Fsum.__init__(self, **name_RESIDUAL)
180
+ raiser = _Fsum__init__(self, **name_RESIDUAL_raiser)
189
181
  if xs:
190
- r = _1_0 / root
191
- self. fadd(xs)
192
- self._fpow(r, _pow_op_) # self **= r
193
- else:
194
- self._fset(_0_0)
195
- except Exception as x:
196
- raise self._ErrorXs(x, xs, root=root)
182
+ self.fadd(xs)
183
+ self._fset(self.root(root, **raiser))
184
+ except Exception as X:
185
+ raise self._ErrorXs(X, xs, root=root)
197
186
 
198
187
 
199
- class Fcbrt(Fn_rt):
188
+ class Fcbrt(Froot):
200
189
  '''Cubic root of a precision summation.
201
190
  '''
202
- def __init__(self, *xs, **name_RESIDUAL):
191
+ def __init__(self, *xs, **name_RESIDUAL_raiser):
203
192
  '''New L{Fcbrt} cubic root of a precision sum.
204
193
 
205
- @see: Class L{Fn_rt} for further details.
194
+ @see: Class L{Froot} for further details.
206
195
  '''
207
- Fn_rt.__init__(self, _3_0, *xs, **name_RESIDUAL)
196
+ Froot.__init__(self, 3, *xs, **name_RESIDUAL_raiser)
208
197
 
209
198
 
210
- class Fsqrt(Fn_rt):
199
+ class Fsqrt(Froot):
211
200
  '''Square root of a precision summation.
212
201
  '''
213
- def __init__(self, *xs, **name_RESIDUAL):
202
+ def __init__(self, *xs, **name_RESIDUAL_raiser):
214
203
  '''New L{Fsqrt} square root of a precision sum.
215
204
 
216
- @see: Class L{Fn_rt} for further details.
205
+ @see: Class L{Froot} for further details.
217
206
  '''
218
- Fn_rt.__init__(self, _2_0, *xs, **name_RESIDUAL)
207
+ Froot.__init__(self, 2, *xs, **name_RESIDUAL_raiser)
208
+
209
+
210
+ def _Fsum__init__(inst, raiser=MISSING, **name_RESIDUAL):
211
+ '''(INTERNAL) Init an C{F...} instance above.
212
+ '''
213
+ Fsum.__init__(inst, **name_RESIDUAL) # PYCHOK self
214
+ inst._fset_ps(_0_0)
215
+ return {} if raiser is MISSING else dict(raiser=raiser)
219
216
 
220
217
 
221
218
  def bqrt(x):
222
- '''Return the 4-th, I{bi-quadratic} or I{quartic} root, M{x**(1 / 4)}.
219
+ '''Return the 4-th, I{bi-quadratic} or I{quartic} root, M{x**(1 / 4)},
220
+ preserving C{type(B{x})}.
223
221
 
224
- @arg x: Value (C{scalar}).
222
+ @arg x: Value (C{scalar} or L{Fsum} instance).
225
223
 
226
- @return: I{Quartic} root (C{float}).
224
+ @return: I{Quartic} root (C{float} or L{Fsum}).
227
225
 
228
226
  @raise ValueError: Negative B{C{x}}.
229
227
 
@@ -233,70 +231,76 @@ def bqrt(x):
233
231
 
234
232
 
235
233
  try:
236
- from math import cbrt # Python 3.11+
237
-
238
- def cbrt2(x):
239
- '''Compute the cube root I{squared} M{x**(2/3)}.
240
- '''
241
- return cbrt(x)**2 # cbrt(-0.0*2) == -0.0
234
+ from math import cbrt as _cbrt # Python 3.11+
242
235
 
243
236
  except ImportError: # Python 3.10-
244
237
 
245
- def cbrt(x):
246
- '''Compute the cube root M{x**(1/3)}.
247
-
248
- @arg x: Value (C{scalar}).
249
-
250
- @return: Cubic root (C{float}).
251
-
252
- @see: Functions L{cbrt2} and L{sqrt3}.
238
+ def _cbrt(x):
239
+ '''(INTERNAL) Compute the I{signed}, cube root M{x**(1/3)}.
253
240
  '''
254
241
  # <https://archive.lib.MSU.edu/crcmath/math/math/r/r021.htm>
255
242
  # simpler and more accurate than Ken Turkowski's CubeRoot, see
256
243
  # <https://People.FreeBSD.org/~lstewart/references/apple_tr_kt32_cuberoot.pdf>
257
- return _copysign(pow(fabs(x), _1_3rd), x) # cbrt(-0.0) == -0.0
244
+ return _copysign(pow(fabs(x), _1_3rd), x) # to avoid complex
258
245
 
259
- def cbrt2(x): # PYCHOK attr
260
- '''Compute the cube root I{squared} M{x**(2/3)}.
261
246
 
262
- @arg x: Value (C{scalar}).
247
+ def cbrt(x):
248
+ '''Compute the cube root M{x**(1/3)}, preserving C{type(B{x})}.
263
249
 
264
- @return: Cube root I{squared} (C{float}).
250
+ @arg x: Value (C{scalar} or L{Fsum} instance).
265
251
 
266
- @see: Functions L{cbrt} and L{sqrt3}.
267
- '''
268
- return pow(fabs(x), _2_3rd) # XXX pow(fabs(x), _1_3rd)**2
252
+ @return: Cubic root (C{float} or L{Fsum}).
253
+
254
+ @see: Functions L{cbrt2} and L{sqrt3}.
255
+ '''
256
+ if isinstance(x, Fsum):
257
+ r = (-(-x).pow(_1_3rd)) if x < 0 else x.pow(_1_3rd)
258
+ else:
259
+ r = _cbrt(x)
260
+ return r # cbrt(-0.0) == -0.0
261
+
262
+
263
+ def cbrt2(x): # PYCHOK attr
264
+ '''Compute the cube root I{squared} M{x**(2/3)}, preserving C{type(B{x})}.
265
+
266
+ @arg x: Value (C{scalar} or L{Fsum} instance).
267
+
268
+ @return: Cube root I{squared} (C{float} or L{Fsum}).
269
+
270
+ @see: Functions L{cbrt} and L{sqrt3}.
271
+ '''
272
+ return abs(x).pow(_2_3rd) if isinstance(x, Fsum) else _cbrt(x**2)
269
273
 
270
274
 
271
275
  def euclid(x, y):
272
276
  '''I{Appoximate} the norm M{sqrt(x**2 + y**2)} by
273
277
  M{max(abs(x), abs(y)) + min(abs(x), abs(y)) * 0.4142...}.
274
278
 
275
- @arg x: X component (C{scalar}).
276
- @arg y: Y component (C{scalar}).
279
+ @arg x: X component (C{scalar} or L{Fsum} instance).
280
+ @arg y: Y component (C{scalar} or L{Fsum} instance).
277
281
 
278
- @return: Appoximate norm (C{float}).
282
+ @return: Appoximate norm (C{float} or L{Fsum}).
279
283
 
280
284
  @see: Function L{euclid_}.
281
285
  '''
282
- x, y = fabs(x), fabs(y)
286
+ x, y = abs(x), abs(y) # NOT fabs!
283
287
  if x < y:
284
288
  x, y = y, x
285
289
  return x + y * _0_4142 # XXX * _0_5 before 20.10.02
286
290
 
287
291
 
288
292
  def euclid_(*xs):
289
- '''I{Appoximate} the norm M{sqrt(sum(x**2 for x in xs))}
290
- by cascaded L{euclid}.
293
+ '''I{Appoximate} the norm M{sqrt(sum(x**2 for x in xs))} by
294
+ cascaded L{euclid}.
291
295
 
292
- @arg xs: X arguments, positional (C{scalar}s).
296
+ @arg xs: X arguments, positional (C{scalar}s or L{Fsum} instances).
293
297
 
294
- @return: Appoximate norm (C{float}).
298
+ @return: Appoximate norm (C{float} or L{Fsum}).
295
299
 
296
300
  @see: Function L{euclid}.
297
301
  '''
298
302
  e = _0_0
299
- for x in sorted(map(fabs, xs)): # XXX not reverse=True
303
+ for x in sorted(map(abs, xs)): # NOT fabs, reverse=True!
300
304
  # e = euclid(x, e)
301
305
  if e < x:
302
306
  e, x = x, e
@@ -389,8 +393,8 @@ def fatan2(y, x):
389
393
  def favg(v1, v2, f=_0_5):
390
394
  '''Return the average of two values.
391
395
 
392
- @arg v1: One value (C{scalar}).
393
- @arg v2: Other value (C{scalar}).
396
+ @arg v1: One value (C{scalar} or L{Fsum} instance).
397
+ @arg v2: Other value (C{scalar} or L{Fsum} instance).
394
398
  @kwarg f: Optional fraction (C{float}).
395
399
 
396
400
  @return: M{v1 + f * (v2 - v1)} (C{float}).
@@ -607,6 +611,39 @@ except ImportError:
607
611
  return freduce(_operator.mul, xs, start)
608
612
 
609
613
 
614
+ def frandoms(n, seeded=None):
615
+ '''Generate C{n} (long) lists of random C{floats}.
616
+
617
+ @arg n: Number of lists to generate (C{int}, non-negative).
618
+ @kwarg seeded: If C{scalar}, use C{random.seed(B{seeded})} or
619
+ if C{True}, seed using today's C{year-day}.
620
+
621
+ @see: U{Hettinger<https://GitHub.com/ActiveState/code/tree/master/recipes/
622
+ Python/393090_Binary_floating_point_summatiaccurate_full/recipe-393090.py>}.
623
+ '''
624
+ from random import gauss, random, seed, shuffle
625
+
626
+ if seeded is None:
627
+ pass
628
+ elif seeded and isbool(seeded):
629
+ from time import localtime
630
+ seed(localtime().tm_yday)
631
+ elif isscalar(seeded):
632
+ seed(seeded)
633
+
634
+ c = (7, 1e100, -7, -1e100, -9e-20, 8e-20) * 7
635
+ for _ in range(n):
636
+ s = 0
637
+ t = list(c)
638
+ _a = t.append
639
+ for _ in range(n * 8):
640
+ v = gauss(0, random())**7 - s
641
+ _a(v)
642
+ s += v
643
+ shuffle(t)
644
+ yield t
645
+
646
+
610
647
  def frange(start, number, step=1):
611
648
  '''Generate a range of C{float}s.
612
649
 
@@ -716,8 +753,8 @@ if _sys_version_info2 < (3, 8): # PYCHOK no cover
716
753
  computed as M{hypot_(*((c1 - c2) for c1, c2 in zip(p1, p2)))},
717
754
  provided I{p1} and I{p2} have the same, non-zero length I{n}.
718
755
  '''
719
- h, x2 = _h_x2(xs, hypot_)
720
- return (h * sqrt(x2)) if x2 else _0_0
756
+ _, R = _h_xs2(xs, True, hypot_)
757
+ return float(R)
721
758
 
722
759
  elif _sys_version_info2 < (3, 10):
723
760
  # In Python 3.8 and 3.9 C{math.hypot} is inaccurate, see
@@ -733,13 +770,8 @@ elif _sys_version_info2 < (3, 10):
733
770
 
734
771
  @return: C{sqrt(B{x}**2 + B{y}**2)} (C{float}).
735
772
  '''
736
- if x:
737
- h = sqrt(x**2 + y**2) if y else fabs(x)
738
- elif y:
739
- h = fabs(y)
740
- else:
741
- h = _0_0
742
- return h
773
+ return (float(Fhypot(x, y, raiser=False)) if y else
774
+ fabs(x)) if x else fabs(y)
743
775
 
744
776
  from math import hypot as hypot_ # PYCHOK in Python 3.8 and 3.9
745
777
  else:
@@ -747,29 +779,32 @@ else:
747
779
  hypot_ = hypot
748
780
 
749
781
 
750
- def _h_x2(xs, which):
782
+ def _h_xs2(xs, pot_, which):
751
783
  '''(INTERNAL) Helper for L{hypot_} and L{hypot2_}.
752
784
  '''
753
785
  n, xs = len2(xs)
754
786
  if n > 0:
755
- h = float(max(map(fabs, xs)))
787
+ h = float(max(map(abs, xs))) # NOT fabs!
756
788
  if h < EPS0:
757
- x2 = _0_0
789
+ R = _0_0
758
790
  elif n > 1:
759
- _h = (_1_0 / h) if h != _1_0 else _1_0
760
- x2 = _fsum(_1primed((x * _h)**2 for x in xs))
791
+ if pot_:
792
+ if h != _1_0:
793
+ xs = ((x / h) for x in xs)
794
+ R = Fhypot(*xs, raiser=False) * h
795
+ else:
796
+ R = Fpowers(2, *xs)
761
797
  else:
762
- x2 = _1_0
763
- return h, x2
798
+ R = h if pot_ else (h**2)
799
+ return h, R
764
800
 
765
- t = Fmt.PAREN(which.__name__, xs)
766
- raise _ValueError(t, txt=_too_(_few_))
801
+ raise _ValueError(unstr(which, xs), txt=_too_(_few_))
767
802
 
768
803
 
769
804
  def hypot1(x):
770
805
  '''Compute the norm M{sqrt(1 + x**2)}.
771
806
 
772
- @arg x: Argument (C{scalar}).
807
+ @arg x: Argument (C{scalar} or L{Fsum} instance).
773
808
 
774
809
  @return: Norm (C{float}).
775
810
  '''
@@ -779,12 +814,12 @@ def hypot1(x):
779
814
  def hypot2(x, y):
780
815
  '''Compute the I{squared} norm M{x**2 + y**2}.
781
816
 
782
- @arg x: X argument (C{scalar}).
783
- @arg y: Y argument (C{scalar}).
817
+ @arg x: X argument (C{scalar} or L{Fsum} instance).
818
+ @arg y: Y argument (C{scalar} or L{Fsum} instance).
784
819
 
785
- @return: C{B{x}**2 + B{y}**2} (C{float}).
820
+ @return: C{B{x}**2 + B{y}**2} (C{float} or L{Fsum}).
786
821
  '''
787
- if fabs(x) < fabs(y):
822
+ if abs(x) < abs(y): # NOT fabs!
788
823
  x, y = y, x
789
824
  if x:
790
825
  h2 = x**2
@@ -796,9 +831,10 @@ def hypot2(x, y):
796
831
 
797
832
 
798
833
  def hypot2_(*xs):
799
- '''Compute the I{squared} norm C{sum(x**2 for x in B{xs})}.
834
+ '''Compute the I{squared} norm C{fsum(x**2 for x in B{xs})}.
800
835
 
801
- @arg xs: X arguments (C{scalar}s), all positional.
836
+ @arg xs: X arguments (C{scalar}s or L{Fsum} instances),
837
+ all positional.
802
838
 
803
839
  @return: Squared norm (C{float}).
804
840
 
@@ -808,8 +844,8 @@ def hypot2_(*xs):
808
844
 
809
845
  @see: Function L{hypot_}.
810
846
  '''
811
- h, x2 = _h_x2(xs, hypot2_)
812
- return (h**2 * x2) if x2 else _0_0
847
+ _, R = _h_xs2(xs, False, hypot2_)
848
+ return float(R)
813
849
 
814
850
 
815
851
  def _map_mul(a, b, where):
@@ -818,7 +854,7 @@ def _map_mul(a, b, where):
818
854
  n = len(b)
819
855
  if len(a) != n: # PYCHOK no cover
820
856
  raise LenError(where, a=len(a), b=n)
821
- return map(_operator.mul, a, b) if n > 3 else _1map_mul(a, b)
857
+ return _1map_mul(a, b) if n < 4 else map(_operator.mul, a, b)
822
858
 
823
859
 
824
860
  def _1map_mul(a, b):
@@ -861,12 +897,13 @@ def norm_(*xs):
861
897
  or zero norm.
862
898
  '''
863
899
  try:
900
+ i = x = h = None
864
901
  h = hypot_(*xs)
865
902
  _h = (_1_0 / h) if h else _0_0
866
903
  for i, x in enumerate(xs):
867
904
  yield x * _h
868
- except Exception as e:
869
- raise _xError(e, Fmt.SQUARE(xs=i), x, _h_, h)
905
+ except Exception as X:
906
+ raise _xError(X, Fmt.SQUARE(xs=i), x, h=h)
870
907
 
871
908
 
872
909
  def _powers(x, n):
@@ -881,34 +918,40 @@ def _powers(x, n):
881
918
  def _root(x, p, where):
882
919
  '''(INTERNAL) Raise C{x} to power C{0 < p < 1}.
883
920
  '''
884
- if x < 0:
885
- t = _SPACE_(_invokation_, where.__name__)
886
- raise _ValueError(unstr(t, x), txt=_negative_)
887
- return pow(x, p) if x else _0_0
921
+ try:
922
+ if x > 0:
923
+ return pow(x, p)
924
+ elif x < 0:
925
+ raise ValueError(_negative_)
926
+ except Exception as X:
927
+ raise _xError(X, unstr(where, x))
928
+ return _0_0
888
929
 
889
930
 
890
931
  def sqrt0(x, Error=None):
891
- '''Return the square root iff C{B{x} >} L{EPS02}.
932
+ '''Return the square root C{sqrt(B{x})} iff C{B{x} > }L{EPS02},
933
+ preserving C{type(B{x})}.
892
934
 
893
- @arg x: Value (C{scalar}).
935
+ @arg x: Value (C{scalar} or L{Fsum} instance).
894
936
  @kwarg Error: Error to raise for negative B{C{x}}.
895
937
 
896
- @return: Square root (C{float}) or C{0.0}.
938
+ @return: Square root (C{float} or L{Fsum}) or C{0.0}.
897
939
 
898
940
  @note: Any C{B{x} < }L{EPS02} I{including} C{B{x} < 0}
899
941
  returns C{0.0}.
900
942
  '''
901
943
  if Error and x < 0:
902
- raise Error(Fmt.PAREN(sqrt=x))
903
- return sqrt(x) if x > EPS02 else (_0_0 if x < EPS02 else EPS0)
944
+ raise Error(unstr(sqrt0, x))
945
+ return _root(x, _0_5, sqrt0) if x > EPS02 else (_0_0 if x < EPS02 else EPS0)
904
946
 
905
947
 
906
948
  def sqrt3(x):
907
- '''Return the square root, I{cubed} M{sqrt(x)**3} or M{sqrt(x**3)}.
949
+ '''Return the square root, I{cubed} M{sqrt(x)**3} or M{sqrt(x**3)},
950
+ preserving C{type(B{x})}.
908
951
 
909
- @arg x: Value (C{scalar}).
952
+ @arg x: Value (C{scalar} or L{Fsum} instance).
910
953
 
911
- @return: Square root I{cubed} (C{float}).
954
+ @return: Square root I{cubed} (C{float} or L{Fsum}).
912
955
 
913
956
  @raise ValueError: Negative B{C{x}}.
914
957
 
@@ -957,11 +1000,12 @@ def sqrt_a(h, b):
957
1000
 
958
1001
 
959
1002
  def zcrt(x):
960
- '''Return the 6-th, I{zenzi-cubic} root, M{x**(1 / 6)}.
1003
+ '''Return the 6-th, I{zenzi-cubic} root, M{x**(1 / 6)},
1004
+ preserving C{type(B{x})}.
961
1005
 
962
- @arg x: Value (C{scalar}).
1006
+ @arg x: Value (C{scalar} or L{Fsum} instance).
963
1007
 
964
- @return: I{Zenzi-cubic} root (C{float}).
1008
+ @return: I{Zenzi-cubic} root (C{float} or L{Fsum}).
965
1009
 
966
1010
  @see: Functions L{bqrt} and L{zqrt}.
967
1011
 
@@ -971,11 +1015,12 @@ def zcrt(x):
971
1015
 
972
1016
 
973
1017
  def zqrt(x):
974
- '''Return the 8-th, I{zenzi-quartic} or I{squared-quartic} root, M{x**(1 / 8)}.
1018
+ '''Return the 8-th, I{zenzi-quartic} or I{squared-quartic} root,
1019
+ M{x**(1 / 8)}, preserving C{type(B{x})}.
975
1020
 
976
- @arg x: Value (C{scalar}).
1021
+ @arg x: Value (C{scalar} or L{Fsum} instance).
977
1022
 
978
- @return: I{Zenzi-quartic} root (C{float}).
1023
+ @return: I{Zenzi-quartic} root (C{float} or L{Fsum}).
979
1024
 
980
1025
  @see: Functions L{bqrt} and L{zcrt}.
981
1026