pygeodesy 24.3.24__py2.py3-none-any.whl → 24.4.4__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
@@ -8,13 +8,13 @@ from __future__ import division as _; del _ # PYCHOK semicolon
8
8
 
9
9
  from pygeodesy.basics import _copysign, copysign0, isint, 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, _N_1_0, \
12
- _1_3rd, _1_5, _1_6th, _2_0, _2_3rd, _3_0, \
13
- _isfinite, isnear0, isnear1, _over, remainder
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
14
14
  from pygeodesy.errors import _IsnotError, LenError, _TypeError, _ValueError, \
15
15
  _xError, _xkwds_get, _xkwds_pop2
16
- from pygeodesy.fsums import _2float, _Powers, Fsum, _fsum, fsum, fsum1_, \
17
- _pow_op_, Fmt, unstr
16
+ from pygeodesy.fsums import _2float, Fsum, _fsum, fsum, fsum1_, _pow_op_, \
17
+ _1primed, Fmt, unstr
18
18
  from pygeodesy.interns import MISSING, _few_, _h_, _invokation_, _negative_, \
19
19
  _not_scalar_, _SPACE_, _too_
20
20
  from pygeodesy.lazily import _ALL_LAZY, _sys_version_info2
@@ -25,22 +25,24 @@ from math import fabs, sqrt # pow
25
25
  import operator as _operator # in .datums, .trf, .utm
26
26
 
27
27
  __all__ = _ALL_LAZY.fmath
28
- __version__ = '24.03.14'
28
+ __version__ = '24.04.04'
29
29
 
30
30
  # sqrt(2) <https://WikiPedia.org/wiki/Square_root_of_2>
31
- _0_4142 = 0.41421356237309504880 # ... sqrt(2) - 1
31
+ _0_4142 = 0.41421356237309504880 # ... sqrt(2) - 1
32
+ _h_lt_b_ = 'abs(h) < abs(b)'
32
33
 
33
34
 
34
35
  class Fdot(Fsum):
35
36
  '''Precision dot product.
36
37
  '''
37
- def __init__(self, a, *b, **name):
38
+ def __init__(self, a, *b, **name_RESIDUAL):
38
39
  '''New L{Fdot} precision dot product M{sum(a[i] * b[i]
39
- for i=0..len(a))}.
40
+ for i=0..len(a)-1)}.
40
41
 
41
42
  @arg a: Iterable, list, tuple, etc. (C{scalar}s).
42
43
  @arg b: Other values (C{scalar}s), all positional.
43
- @kwarg name: Optional name (C{str}).
44
+ @kwarg name_RESIDUAL: Optional C{B{name}=NN} and
45
+ C{B{RESIDUAL}=None}, see L{Fsum.__init__}.
44
46
 
45
47
  @raise OverflowError: Partial C{2sum} overflow.
46
48
 
@@ -48,21 +50,22 @@ class Fdot(Fsum):
48
50
 
49
51
  @see: Function L{fdot} and method L{Fsum.fadd}.
50
52
  '''
51
- Fsum.__init__(self, **name)
53
+ Fsum.__init__(self, **name_RESIDUAL)
52
54
  self.fadd(_map_mul(a, b, Fdot))
53
55
 
54
56
 
55
57
  class Fhorner(Fsum):
56
58
  '''Precision polynomial evaluation using the Horner form.
57
59
  '''
58
- def __init__(self, x, *cs, **name):
59
- '''New L{Fhorner} evaluation of the polynomial
60
- M{sum(cs[i] * x**i for i=0..len(cs))}.
60
+ def __init__(self, x, *cs, **name_RESIDUAL):
61
+ '''New L{Fhorner} evaluation of polynomial M{sum(cs[i] * x**i
62
+ for i=0..len(cs)-1)}.
61
63
 
62
- @arg x: Polynomial argument (C{scalar}).
64
+ @arg x: Polynomial argument (C{scalar} or C{Fsum} instance).
63
65
  @arg cs: Polynomial coeffients (C{scalar} or C{Fsum}
64
66
  instances), all positional.
65
- @kwarg name: Optional name (C{str}).
67
+ @kwarg name_RESIDUAL: Optional C{B{name}=NN} and
68
+ C{B{RESIDUAL}=None}, see L{Fsum.__init__}.
66
69
 
67
70
  @raise OverflowError: Partial C{2sum} overflow.
68
71
 
@@ -70,55 +73,65 @@ class Fhorner(Fsum):
70
73
 
71
74
  @raise ValueError: Non-finite B{C{x}}.
72
75
 
73
- @see: Function L{fhorner} and methods L{Fsum.fadd} and L{Fsum.fmul}.
76
+ @see: Function L{fhorner} and methods L{Fsum.fadd} and
77
+ L{Fsum.fmul}.
74
78
  '''
75
- Fsum.__init__(self, *cs[-1:], **name)
76
- if len(cs) > 1:
77
- x = _2float(x=x)
78
- _a = self._fadd # (other, op)
79
- _f = self._finite # (other, op)
80
- op = Fhorner.__name__
81
- ps = self._ps
82
- for c in reversed(cs[:-1]): # multiply-accumulate
83
- ps[:] = [_f(p * x, op) for p in ps]
84
- _a(c, op)
85
- # assert self._ps is ps
79
+ Fsum.__init__(self, **name_RESIDUAL)
80
+ if cs:
81
+ if isinstance(x, Fsum):
82
+ _mul = self._mul_Fsum
83
+ else:
84
+ _mul = self._mul_scalar
85
+ x = _2float(x=x)
86
+ op = Fhorner.__name__
87
+ if len(cs) > 1 and x:
88
+ for c in reversed(cs):
89
+ self._fset_ps(_mul(x, op))
90
+ self._fadd(c, op, up=False)
91
+ self._update()
92
+ else: # x == 0
93
+ self._fadd(cs[0], op)
94
+ else:
95
+ self._fset(_0_0)
86
96
 
87
97
 
88
98
  class Fhypot(Fsum):
89
- '''Precision hypotenuse of summation.
99
+ '''Precision summation and hypotenuse, default C{power=2}.
90
100
  '''
91
101
  def __init__(self, *xs, **power_name_RESIDUAL):
92
- '''New L{Fhypot} hypotenuse of (the I{power} of) several
93
- C{scalar} or C{Fsum} values.
102
+ '''New L{Fhypot} hypotenuse of (the I{power} of) several components.
94
103
 
95
- @arg xs: One or more values to include (each C{scalar}
96
- or an C{Fsum} instance).
97
- @kwarg power_name_RESIDUAL: Optional exponent and root
98
- order C{B{power}=2}, C{B{name}=NN} and
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
99
108
  C{B{RESIDUAL}=None}, see L{Fsum.__init__}.
100
109
  '''
101
110
  try:
102
111
  p, kwds = _xkwds_pop2(power_name_RESIDUAL, power=2)
103
112
  Fsum.__init__(self, **kwds)
104
113
  if xs:
105
- self._facc(_Powers(p, xs), up=False) # PYCHOK yield
106
- self._fset(self._fpow(_1_0 / p, _pow_op_), asis=True)
107
- except Exception as X:
108
- raise self._ErrorX(X, xs, power=p)
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)
109
121
 
110
122
 
111
123
  class Fpolynomial(Fsum):
112
124
  '''Precision polynomial evaluation.
113
125
  '''
114
- def __init__(self, x, *cs, **name):
126
+ def __init__(self, x, *cs, **name_RESIDUAL):
115
127
  '''New L{Fpolynomial} evaluation of the polynomial
116
- M{sum(cs[i] * x**i for i=0..len(cs))}.
128
+ M{sum(cs[i] * x**i for i=0..len(cs)-1)}.
117
129
 
118
- @arg x: Polynomial argument (C{scalar}).
119
- @arg cs: Polynomial coeffients (C{scalar}s), all
120
- positional.
121
- @kwarg name: Optional name (C{str}).
130
+ @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__}.
122
135
 
123
136
  @raise OverflowError: Partial C{2sum} overflow.
124
137
 
@@ -126,79 +139,81 @@ class Fpolynomial(Fsum):
126
139
 
127
140
  @raise ValueError: Non-finite B{C{x}}.
128
141
 
129
- @see: Function L{fpolynomial} and method L{Fsum.fadd}.
142
+ @see: Class L{Fhorner}, function L{fpolynomial} and
143
+ method L{Fsum.fadd}.
130
144
  '''
131
- Fsum.__init__(self, *cs[:1], **name)
145
+ Fsum.__init__(self, *cs[:1], **name_RESIDUAL)
132
146
  n = len(cs) - 1
133
147
  if n > 0:
134
- self.fadd(_map_mul(cs[1:], fpowers(x, n), Fpolynomial))
148
+ self.fadd(_1map_mul(cs[1:], _powers(x, n)))
149
+ elif n < 0:
150
+ self._fset(_0_0)
135
151
 
136
152
 
137
153
  class Fpowers(Fsum):
138
- '''Precision summation or powers, optimized for C{power=2}.
154
+ '''Precision summation of powers, optimized for C{power=2, 3 and 4}.
139
155
  '''
140
156
  def __init__(self, power, *xs, **name_RESIDUAL):
141
- '''New L{Fpowers} sum of (the I{power} of) several C{scalar}
142
- or C{Fsum} values.
143
-
144
- @arg power: The exponent (C{scalar} or C{Fsum}).
145
- @arg xs: One or more values to include (each C{scalar}
146
- or an C{Fsum} instance).
147
- @kwarg power_name_RESIDUAL: Optional exponent and root
148
- order C{B{power}=2}, C{B{name}=NN} and
149
- C{B{RESIDUAL}=None}, see L{Fsum.__init__}.
157
+ '''New L{Fpowers} sum of (the I{power} of) several values.
158
+
159
+ @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__}.
150
164
  '''
151
165
  try:
152
166
  Fsum.__init__(self, **name_RESIDUAL)
153
167
  if xs:
154
- self._facc(_Powers(power, xs), up=False) # PYCHOK yield
155
- except Exception as X:
156
- raise self._ErrorX(X, xs, power=power)
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)
157
173
 
158
174
 
159
175
  class Fn_rt(Fsum):
160
- '''Precision n-th root of summation.
176
+ '''N-th root of a precision summation.
161
177
  '''
162
178
  def __init__(self, root, *xs, **name_RESIDUAL):
163
- '''New L{Fn_rt} root of the precision sum of several
164
- C{scalar} or C{Fsum} values.
179
+ '''New L{Fn_rt} root of a precision sum.
165
180
 
166
- @arg root: The order (C{scalar} or C{Fsum}).
167
- @arg xs: Values to include (each C{scalar} or an
168
- C{Fsum} instance).
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).
169
185
  @kwarg name_RESIDUAL: See L{Fsum.__init__}.
170
186
  '''
171
187
  try:
172
- Fsum.__init__(self, *xs, **name_RESIDUAL)
173
- self._fset(self._fpow(_1_0 / root, _pow_op_), asis=True)
174
- except Exception as X:
175
- raise self._ErrorX(X, xs, root=root)
188
+ Fsum.__init__(self, **name_RESIDUAL)
189
+ 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)
176
197
 
177
198
 
178
199
  class Fcbrt(Fn_rt):
179
- '''Precision cubic root of summation.
200
+ '''Cubic root of a precision summation.
180
201
  '''
181
202
  def __init__(self, *xs, **name_RESIDUAL):
182
- '''New L{Fcbrt} cubic root of the precision sum of
183
- several C{scalar} or C{Fsum} values.
203
+ '''New L{Fcbrt} cubic root of a precision sum.
184
204
 
185
- @arg xs: Values to include (each C{scalar} or an
186
- C{Fsum} instance).
187
- @kwarg name_RESIDUAL: See L{Fsum.__init__}.
205
+ @see: Class L{Fn_rt} for further details.
188
206
  '''
189
207
  Fn_rt.__init__(self, _3_0, *xs, **name_RESIDUAL)
190
208
 
191
209
 
192
210
  class Fsqrt(Fn_rt):
193
- '''Precision square root of summation.
211
+ '''Square root of a precision summation.
194
212
  '''
195
213
  def __init__(self, *xs, **name_RESIDUAL):
196
- '''New L{Fsqrt} square root of the precision sum of
197
- several C{scalar} or C{Fsum} values.
214
+ '''New L{Fsqrt} square root of a precision sum.
198
215
 
199
- @arg xs: Values to include (each C{scalar} or an
200
- C{Fsum} instance).
201
- @kwarg name_RESIDUAL: See L{Fsum.__init__}.
216
+ @see: Class L{Fn_rt} for further details.
202
217
  '''
203
218
  Fn_rt.__init__(self, _2_0, *xs, **name_RESIDUAL)
204
219
 
@@ -344,7 +359,7 @@ def fatan1(x):
344
359
  # Eq (9): PI_4 * x - x * (abs(x) - 1) * (0.2447 + 0.0663 * abs(x)), for -1 < x < 1
345
360
  # PI_4 * x - (x**2 - x) * (0.2447 + 0.0663 * x), for 0 < x - 1
346
361
  # x * (1.0300981633974482 + x * (-0.1784 - x * 0.0663))
347
- H = Fhorner(x, _0_0, 1.0300982, -0.1784, -0.0663)
362
+ H = Fhorner(x, _0_0, 1.0300981634, -0.1784, -0.0663)
348
363
  return float(H)
349
364
 
350
365
 
@@ -355,12 +370,12 @@ def fatan2(y, x):
355
370
  master/Source/Shaders/Builtin/Functions/fastApproximateAtan.glsl>}
356
371
  and L{fatan1}.
357
372
  '''
358
- b, a = fabs(y), fabs(x)
359
- if a < b:
373
+ a, b = fabs(x), fabs(y)
374
+ if b > a:
360
375
  r = (PI_2 - fatan1(a / b)) if a else PI_2
361
- elif b < a:
376
+ elif a > b:
362
377
  r = fatan1(b / a) if b else _0_0
363
- elif a: # == b != 0
378
+ elif a: # a == b != 0
364
379
  r = PI_4
365
380
  else: # a == b == 0
366
381
  return _0_0
@@ -407,7 +422,7 @@ def fdot(a, *b):
407
422
 
408
423
  def fdot3(a, b, c, start=0):
409
424
  '''Return the precision dot product M{start +
410
- sum(a[i] * b[i] * c[i] for i=0..len(a))}.
425
+ sum(a[i] * b[i] * c[i] for i=0..len(a)-1)}.
411
426
 
412
427
  @arg a: Iterable, list, tuple, etc. (C{scalar}s).
413
428
  @arg b: Iterable, list, tuple, etc. (C{scalar}s).
@@ -424,7 +439,7 @@ def fdot3(a, b, c, start=0):
424
439
  def _mul3(a, b, c): # map function
425
440
  return a * b * c
426
441
 
427
- def _muly(a, b, c, start):
442
+ def _mul3_(a, b, c, start):
428
443
  yield start
429
444
  for abc in map(_mul3, a, b, c):
430
445
  yield abc
@@ -432,12 +447,12 @@ def fdot3(a, b, c, start=0):
432
447
  if not len(a) == len(b) == len(c):
433
448
  raise LenError(fdot3, a=len(a), b=len(b), c=len(c))
434
449
 
435
- return fsum(_muly(a, b, c, start) if start else map(_mul3, a, b, c))
450
+ return fsum(_mul3_(a, b, c, start) if start else map(_mul3, a, b, c))
436
451
 
437
452
 
438
453
  def fhorner(x, *cs):
439
454
  '''Evaluate the polynomial M{sum(cs[i] * x**i for
440
- i=0..len(cs))} using the Horner form.
455
+ i=0..len(cs)-1)} using the Horner form.
441
456
 
442
457
  @arg x: Polynomial argument (C{scalar}).
443
458
  @arg cs: Polynomial coeffients (C{scalar}s).
@@ -483,45 +498,37 @@ def fidw(xs, ds, beta=2):
483
498
  b = -Int_(beta=beta, low=0, high=3)
484
499
  if b < 0:
485
500
  ws = tuple(float(d)**b for d in ds)
486
- t = fsum(_map_mul1(xs, ws)) # fdot(xs, *ws)
501
+ t = fsum(_1map_mul(xs, ws)) # Fdot(xs, *ws)
487
502
  x = _over(t, fsum(ws, floats=True))
488
503
  else: # b == 0
489
504
  x = fsum(xs) / n # fmean(xs)
490
505
  elif d < 0: # PYCHOK no cover
491
- n = Fmt.INDEX(distance=ds.index(d))
506
+ n = Fmt.SQUARE(distance=ds.index(d))
492
507
  raise _ValueError(n, d, txt=_negative_)
493
508
  return x
494
509
 
495
510
 
496
511
  def fmean(xs):
497
- '''Compute the accurate mean M{sum(xs[i] for
498
- i=0..len(xs)) / len(xs)}.
512
+ '''Compute the accurate mean M{sum(xs) / len(xs)}.
499
513
 
500
514
  @arg xs: Values (C{scalar} or L{Fsum} instances).
501
515
 
502
516
  @return: Mean value (C{float}).
503
517
 
504
- @raise OverflowError: Partial C{2sum} overflow.
518
+ @raise LenError: No B{C{xs}} values.
505
519
 
506
- @raise ValueError: No B{C{xs}} values.
520
+ @raise OverflowError: Partial C{2sum} overflow.
507
521
  '''
508
522
  n, xs = len2(xs)
509
- if n > 0:
510
- return fsum(xs) / n # if n > 1 else _2float(index=0, xs=xs[0])
511
- raise _ValueError(xs=xs)
523
+ if n < 1:
524
+ raise LenError(fmean, xs=xs)
525
+ return Fsum(*xs).fover(n) if n > 1 else _2float(index=0, xs=xs[0])
512
526
 
513
527
 
514
528
  def fmean_(*xs):
515
- '''Compute the accurate mean M{sum(xs[i] for
516
- i=0..len(xs)) / len(xs)}.
517
-
518
- @arg xs: Values (C{scalar} or L{Fsum} instances).
529
+ '''Compute the accurate mean M{sum(xs) / len(xs)}.
519
530
 
520
- @return: Mean value (C{float}).
521
-
522
- @raise OverflowError: Partial C{2sum} overflow.
523
-
524
- @raise ValueError: No B{C{xs}} values.
531
+ @see: Function L{fmean} for further details.
525
532
  '''
526
533
  return fmean(xs)
527
534
 
@@ -533,7 +540,8 @@ def fpolynomial(x, *cs, **over):
533
540
  @arg x: Polynomial argument (C{scalar}).
534
541
  @arg cs: Polynomial coeffients (C{scalar}s), all
535
542
  positional.
536
- @kwarg over: Optional, final divisor (C{scalar}
543
+ @kwarg over: Optional final, I{non-zero} divisor
544
+ (C{scalar}).
537
545
 
538
546
  @return: Polynomial value (C{float}).
539
547
 
@@ -553,28 +561,24 @@ def fpolynomial(x, *cs, **over):
553
561
  def fpowers(x, n, alts=0):
554
562
  '''Return a series of powers M{[x**i for i=1..n]}.
555
563
 
556
- @arg x: Value (C{scalar}).
564
+ @arg x: Value (C{scalar} or L{Fsum}).
557
565
  @arg n: Highest exponent (C{int}).
558
- @kwarg alts: Only alternating powers, starting with
559
- this exponent (C{int}).
566
+ @kwarg alts: Only alternating powers, starting with this
567
+ exponent (C{int}).
560
568
 
561
- @return: Powers of B{C{x}} (C{float}s or C{int}s).
569
+ @return: Tuple of powers of B{C{x}} (C{type(B{x})}).
562
570
 
563
- @raise TypeError: Non-scalar B{C{x}} or B{C{n}} not C{int}.
571
+ @raise TypeError: Invalid B{C{x}} or B{C{n}} not C{int}.
564
572
 
565
- @raise ValueError: Non-finite B{C{x}} or non-positive B{C{n}}.
573
+ @raise ValueError: Non-finite B{C{x}} or invalid B{C{n}}.
566
574
  '''
567
575
  if not isint(n):
568
576
  raise _IsnotError(int.__name__, n=n)
569
577
  elif n < 1:
570
578
  raise _ValueError(n=n)
571
579
 
572
- p = t = x if isint(x) else _2float(x=x)
573
- ps = [p]
574
- _a = ps.append
575
- for _ in range(1, n):
576
- p *= t
577
- _a(p)
580
+ p = x if isint(x) or isinstance(x, Fsum) else _2float(x=x)
581
+ ps = tuple(_powers(p, n))
578
582
 
579
583
  if alts > 0: # x**2, x**4, ...
580
584
  # ps[alts-1::2] chokes PyChecker
@@ -618,7 +622,7 @@ def frange(start, number, step=1):
618
622
  if not isint(number):
619
623
  raise _IsnotError(int.__name__, number=number)
620
624
  for i in range(number):
621
- yield start + i * step
625
+ yield start + (step * i)
622
626
 
623
627
 
624
628
  try:
@@ -712,7 +716,7 @@ if _sys_version_info2 < (3, 8): # PYCHOK no cover
712
716
  computed as M{hypot_(*((c1 - c2) for c1, c2 in zip(p1, p2)))},
713
717
  provided I{p1} and I{p2} have the same, non-zero length I{n}.
714
718
  '''
715
- h, x2 = _h_x2(xs)
719
+ h, x2 = _h_x2(xs, hypot_)
716
720
  return (h * sqrt(x2)) if x2 else _0_0
717
721
 
718
722
  elif _sys_version_info2 < (3, 10):
@@ -743,20 +747,23 @@ else:
743
747
  hypot_ = hypot
744
748
 
745
749
 
746
- def _h_x2(xs):
750
+ def _h_x2(xs, which):
747
751
  '''(INTERNAL) Helper for L{hypot_} and L{hypot2_}.
748
752
  '''
749
- if xs:
750
- n, xs = len2(xs)
751
- if n > 0:
752
- h = float(max(map(fabs, xs)))
753
- if h < EPS0:
754
- x2 = _0_0
755
- else: # math.fsum, see C{_hypot21_} below
756
- x2 = _fsum(_x2_h2(_1_0, xs, h, _N_1_0))
757
- return h, x2
753
+ n, xs = len2(xs)
754
+ if n > 0:
755
+ h = float(max(map(fabs, xs)))
756
+ if h < EPS0:
757
+ x2 = _0_0
758
+ 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))
761
+ else:
762
+ x2 = _1_0
763
+ return h, x2
758
764
 
759
- raise _ValueError(xs=xs, txt=_too_(_few_))
765
+ t = Fmt.PAREN(which.__name__, xs)
766
+ raise _ValueError(t, txt=_too_(_few_))
760
767
 
761
768
 
762
769
  def hypot1(x):
@@ -777,15 +784,12 @@ def hypot2(x, y):
777
784
 
778
785
  @return: C{B{x}**2 + B{y}**2} (C{float}).
779
786
  '''
787
+ if fabs(x) < fabs(y):
788
+ x, y = y, x
780
789
  if x:
790
+ h2 = x**2
781
791
  if y:
782
- if fabs(x) < fabs(y):
783
- x, y = y, x
784
- h2 = x**2 * ((y / x)**2 + _1_0)
785
- else:
786
- h2 = x**2
787
- elif y:
788
- h2 = y**2
792
+ h2 *= (y / x)**2 + _1_0
789
793
  else:
790
794
  h2 = _0_0
791
795
  return h2
@@ -804,7 +808,7 @@ def hypot2_(*xs):
804
808
 
805
809
  @see: Function L{hypot_}.
806
810
  '''
807
- h, x2 = _h_x2(xs)
811
+ h, x2 = _h_x2(xs, hypot2_)
808
812
  return (h**2 * x2) if x2 else _0_0
809
813
 
810
814
 
@@ -814,17 +818,13 @@ def _map_mul(a, b, where):
814
818
  n = len(b)
815
819
  if len(a) != n: # PYCHOK no cover
816
820
  raise LenError(where, a=len(a), b=n)
817
- return map(_operator.mul, a, b) if n > 3 else _map_mul1(a, b)
821
+ return map(_operator.mul, a, b) if n > 3 else _1map_mul(a, b)
818
822
 
819
823
 
820
- def _map_mul1(a, b):
824
+ def _1map_mul(a, b):
821
825
  '''(INTERNAL) Yield each B{C{a * b}}, 1-primed.
822
826
  '''
823
- yield _1_0
824
- for ab in map(_operator.mul, a, b):
825
- if ab:
826
- yield ab
827
- yield _N_1_0
827
+ return _1primed(map(_operator.mul, a, b))
828
828
 
829
829
 
830
830
  def norm2(x, y):
@@ -838,14 +838,15 @@ def norm2(x, y):
838
838
  @raise ValueError: Invalid B{C{x}} or B{C{y}}
839
839
  or zero norm.
840
840
  '''
841
- h = hypot(x, y)
842
- if not h:
843
- x = y = _0_0 # pass?
844
- elif not isnear1(h):
845
- try:
846
- x, y = x / h, y / h
847
- except Exception as e:
848
- raise _xError(e, x=x, y=y, h=h)
841
+ try:
842
+ h = hypot(x, y)
843
+ if h:
844
+ x, y = (x / h), (y / h)
845
+ else:
846
+ x = _copysign_0_0(x) # pass?
847
+ y = _copysign_0_0(y)
848
+ except Exception as e:
849
+ raise _xError(e, x=x, y=y, h=h)
849
850
  return x, y
850
851
 
851
852
 
@@ -859,16 +860,22 @@ def norm_(*xs):
859
860
  @raise ValueError: Invalid or insufficent B{C{xs}}
860
861
  or zero norm.
861
862
  '''
862
- h = hypot_(*xs)
863
- if h:
864
- try:
865
- for i, x in enumerate(xs):
866
- yield x / h
867
- except Exception as e:
868
- raise _xError(e, Fmt.SQUARE(xs=i), x, _h_, h)
869
- else:
870
- for _ in xs:
871
- yield _0_0
863
+ try:
864
+ h = hypot_(*xs)
865
+ _h = (_1_0 / h) if h else _0_0
866
+ for i, x in enumerate(xs):
867
+ yield x * _h
868
+ except Exception as e:
869
+ raise _xError(e, Fmt.SQUARE(xs=i), x, _h_, h)
870
+
871
+
872
+ def _powers(x, n):
873
+ '''(INTERNAL) Yield C{x**i for i=1..n}.
874
+ '''
875
+ p = 1 # type(p) == type(x)
876
+ for _ in range(n):
877
+ p *= x
878
+ yield p
872
879
 
873
880
 
874
881
  def _root(x, p, where):
@@ -931,36 +938,22 @@ def sqrt_a(h, b):
931
938
  try:
932
939
  if not (_isHeight(h) and _isRadius(b)):
933
940
  raise TypeError(_not_scalar_)
934
- elif isnear0(h): # PYCHOK no cover
935
- c, b = fabs(h), fabs(b)
936
- d = c - b
937
- if d < 0:
938
- raise ValueError('abs(h) < abs(b)')
939
- a = copysign0(sqrt((c + b) * d), h) if d > 0 else _0_0
940
- else:
941
- c = float(h)
941
+ c = fabs(h)
942
+ if c > EPS0:
942
943
  s = _1_0 - (b / c)**2
943
944
  if s < 0:
944
- raise ValueError('abs(h) < abs(b)')
945
+ raise ValueError(_h_lt_b_)
945
946
  a = (sqrt(s) * c) if 0 < s < 1 else (c if s else _0_0)
947
+ else: # PYCHOK no cover
948
+ b = fabs(b)
949
+ d = c - b
950
+ if d < 0:
951
+ raise ValueError(_h_lt_b_)
952
+ d *= c + b
953
+ a = sqrt(d) if d else _0_0
946
954
  except Exception as x:
947
955
  raise _xError(x, h=h, b=b)
948
- return a
949
-
950
-
951
- def _x2_h2(s, xs, h, e):
952
- '''(INTERNAL) Yield M{(x / h)**2 for x in xs}.
953
- '''
954
- yield s
955
- if h in (_0_0, _1_0):
956
- for x in xs:
957
- if x:
958
- yield x**2
959
- else:
960
- for x in xs:
961
- if x:
962
- yield (x / h)**2
963
- yield e
956
+ return copysign0(a, h)
964
957
 
965
958
 
966
959
  def zcrt(x):