pygeodesy 24.8.24__py2.py3-none-any.whl → 24.9.9__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/etm.py CHANGED
@@ -73,10 +73,9 @@ from pygeodesy.elliptic import _ALL_LAZY, Elliptic
73
73
  # from pygeodesy.errors import _incompatible # from .named
74
74
  # from pygeodesy.fsums import Fsum # from .fmath
75
75
  from pygeodesy.fmath import cbrt, hypot, hypot1, hypot2, Fsum
76
- from pygeodesy.interns import _COMMASPACE_, _DASH_, _near_, _SPACE_, \
77
- _spherical_
78
- from pygeodesy.karney import _copyBit, _diff182, _fix90, _norm2, _norm180, \
79
- _tand, _unsigned2
76
+ from pygeodesy.interns import _COMMASPACE_, _near_, _SPACE_, _spherical_
77
+ from pygeodesy.karney import _K_2_4, _copyBit, _diff182, _fix90, \
78
+ _norm2, _norm180, _tand, _unsigned2
80
79
  # from pygeodesy.lazily import _ALL_LAZY # from .elliptic
81
80
  from pygeodesy.named import callername, _incompatible, _NamedBase
82
81
  from pygeodesy.namedTuples import Forward4Tuple, Reverse4Tuple
@@ -92,7 +91,7 @@ from pygeodesy.utm import _cmlon, _LLEB, _parseUTM5, _toBand, _toXtm8, \
92
91
  from math import asinh, atan2, degrees, radians, sinh, sqrt
93
92
 
94
93
  __all__ = _ALL_LAZY.etm
95
- __version__ = '24.06.11'
94
+ __version__ = '24.09.06'
96
95
 
97
96
  _OVERFLOW = _1_EPS**2 # about 2e+31
98
97
  _TAYTOL = pow(EPS, 0.6)
@@ -431,13 +430,15 @@ class ExactTransverseMercator(_NamedBase):
431
430
 
432
431
  f = flattening
433
432
 
434
- def forward(self, lat, lon, lon0=None, **name): # MCCABE 13
433
+ def forward(self, lat, lon, lon0=None, jam=_K_2_4, **name): # MCCABE 13
435
434
  '''Forward projection, from geographic to transverse Mercator.
436
435
 
437
436
  @arg lat: Latitude of point (C{degrees}).
438
437
  @arg lon: Longitude of point (C{degrees}).
439
438
  @kwarg lon0: Central meridian (C{degrees180}), overriding
440
439
  the default if not C{None}.
440
+ @kwarg jam: If C{True}, use the C{Jacobi amplitude}
441
+ otherwise C{Bulirsch}' function (C{bool}).
441
442
  @kwarg name: Optional C{B{name}=NN} (C{str}).
442
443
 
443
444
  @return: L{Forward4Tuple}C{(easting, northing, gamma, scale)}.
@@ -473,7 +474,7 @@ class ExactTransverseMercator(_NamedBase):
473
474
  tau, lam = _tand(lat), radians(lon)
474
475
  u, v = self._zetaInv2(self._E.es_taupf(tau), lam)
475
476
 
476
- sncndn6 = self._sncndn6(u, v)
477
+ sncndn6 = self._sncndn6(u, v, jam=jam)
477
478
  y, x, _ = self._sigma3(v, *sncndn6)
478
479
  g, k = (lon, self.k0) if isnear90(lat) else \
479
480
  self._zetaScaled(sncndn6, ll=False)
@@ -668,13 +669,15 @@ class ExactTransverseMercator(_NamedBase):
668
669
  self._mu = mu
669
670
  self._mv = mv
670
671
 
671
- def reverse(self, x, y, lon0=None, **name):
672
+ def reverse(self, x, y, lon0=None, jam=_K_2_4, **name):
672
673
  '''Reverse projection, from Transverse Mercator to geographic.
673
674
 
674
675
  @arg x: Easting of point (C{meters}).
675
676
  @arg y: Northing of point (C{meters}).
676
677
  @kwarg lon0: Optional central meridian (C{degrees180}),
677
678
  overriding the default (C{iff not None}).
679
+ @kwarg jam: If C{True}, use the C{Jacobi amplitude}
680
+ otherwise C{Bulirsch}' function (C{bool}).
678
681
  @kwarg name: Optional C{B{name}=NN} (C{str}).
679
682
 
680
683
  @return: L{Reverse4Tuple}C{(lat, lon, gamma, scale)}.
@@ -706,7 +709,7 @@ class ExactTransverseMercator(_NamedBase):
706
709
  v = self._Ev_cK
707
710
 
708
711
  if v or u != self._Eu_cK:
709
- g, k, lat, lon = self._zetaScaled(self._sncndn6(u, v))
712
+ g, k, lat, lon = self._zetaScaled(self._sncndn6(u, v, jam=jam))
710
713
  else: # PYCHOK no cover
711
714
  g, k, lat, lon = _0_0, self.k0, _90_0, _0_0
712
715
 
@@ -866,12 +869,12 @@ class ExactTransverseMercator(_NamedBase):
866
869
 
867
870
  return u, v, t, C
868
871
 
869
- def _sncndn6(self, u, v):
872
+ def _sncndn6(self, u, v, **jam):
870
873
  '''(INTERNAL) Get 6-tuple C{(snu, cnu, dnu, snv, cnv, dnv)}.
871
874
  '''
872
875
  # snu, cnu, dnu = self._Eu.sncndn(u)
873
876
  # snv, cnv, dnv = self._Ev.sncndn(v)
874
- return self._Eu.sncndn(u) + self._Ev.sncndn(v)
877
+ return self._Eu.sncndn(u, **jam) + self._Ev.sncndn(v, **jam)
875
878
 
876
879
  def toStr(self, joined=_COMMASPACE_, **kwds): # PYCHOK signature
877
880
  '''Return a C{str} representation.
@@ -1094,67 +1097,76 @@ def toEtm8(latlon, lon=None, datum=None, Etm=Etm, falsed=True,
1094
1097
  n, latlon, d.exactTM, Error=ETMError)
1095
1098
 
1096
1099
 
1097
- if __name__ == '__main__': # MCCABE 13
1098
-
1099
- from pygeodesy import fstr, KTransverseMercator, printf
1100
- from pygeodesy.internals import _usage
1101
- from sys import argv, exit as _exit
1102
-
1103
- # mimick some of I{Karney}'s utility C{TransverseMercatorProj}
1104
- _f = _r = _s = _t = False
1105
- _p = -6
1106
- _as = argv[1:]
1107
- while _as and _as[0].startswith(_DASH_):
1108
- _a = _as.pop(0)
1109
- if len(_a) < 2:
1110
- _exit('%s: option %r invalid' % (_usage(*argv), _a))
1111
- elif '-forward'.startswith(_a):
1112
- _f, _r = True, False
1113
- elif '-reverse'.startswith(_a):
1114
- _f, _r = False, True
1115
- elif '-precision'.startswith(_a):
1116
- _p = int(_as.pop(0))
1117
- elif '-series'.startswith(_a):
1118
- _s, _t = True, False
1119
- elif _a == '-t':
1120
- _s, _t = False, True
1121
- elif '-help'.startswith(_a):
1100
+ if __name__ == '__main__': # MCCABE 16
1101
+
1102
+ def _main():
1103
+
1104
+ from pygeodesy import fstr, KTransverseMercator
1105
+ # from pygeodesy.interns import _DASH_ # from internals
1106
+ from pygeodesy.internals import printf, _usage, _DASH_
1107
+ from sys import argv, exit as _exit
1108
+
1109
+ def _help():
1122
1110
  _exit(_usage(argv[0], '[-s | -t ]',
1123
1111
  '[-p[recision] <ndigits>',
1124
1112
  '[-f[orward] <lat> <lon>',
1125
1113
  '|-r[everse] <easting> <northing>',
1126
1114
  '|<lat> <lon>]',
1127
1115
  '|-h[elp]'))
1116
+
1117
+ # mimick some of I{Karney}'s utility C{TransverseMercatorProj}
1118
+ _f = _r = _s = _t = False
1119
+ _p = -6
1120
+ _as = argv[1:]
1121
+ while _as and _as[0].startswith(_DASH_):
1122
+ _a = _as.pop(0)
1123
+ if len(_a) < 2:
1124
+ _exit('%s: option %r invalid' % (_usage(*argv), _a))
1125
+ elif '-forward'.startswith(_a):
1126
+ _f, _r = True, False
1127
+ elif '-reverse'.startswith(_a):
1128
+ _f, _r = False, True
1129
+ elif '-precision'.startswith(_a):
1130
+ _p = int(_as.pop(0))
1131
+ elif '-series'.startswith(_a):
1132
+ _s, _t = True, False
1133
+ elif _a == '-t':
1134
+ _s, _t = False, True
1135
+ elif '-help'.startswith(_a):
1136
+ _help()
1137
+ else:
1138
+ _exit('%s: option %r not supported' % (_usage(*argv), _a))
1139
+
1140
+ if len(_as) > 1:
1141
+ f2 = map1(float, *_as[:2])
1142
+ else:
1143
+ printf('%s ...: incomplete', _usage(*argv))
1144
+ _help()
1145
+
1146
+ if _s: # -series
1147
+ tm = KTransverseMercator()
1148
+ else:
1149
+ tm = ExactTransverseMercator(extendp=_t)
1150
+
1151
+ if _f:
1152
+ t = tm.forward(*f2)
1153
+ elif _r:
1154
+ t = tm.reverse(*f2)
1128
1155
  else:
1129
- _exit('%s: option %r not supported' % (_usage(*argv), _a))
1130
- if len(_as) > 1:
1131
- f2 = map1(float, *_as[:2])
1132
- else:
1133
- _exit('%s ...: incomplete' % (_usage(*argv),))
1134
-
1135
- if _s: # -series
1136
- tm = KTransverseMercator()
1137
- else:
1138
- tm = ExactTransverseMercator(extendp=_t)
1139
-
1140
- if _f:
1141
- t = tm.forward(*f2)
1142
- elif _r:
1143
- t = tm.reverse(*f2)
1144
- else:
1145
- t = tm.forward(*f2)
1156
+ t = tm.forward(*f2)
1157
+ printf('%s: %s', tm.classname, fstr(t, prec=_p, sep=_SPACE_))
1158
+ t = tm.reverse(t.easting, t.northing)
1146
1159
  printf('%s: %s', tm.classname, fstr(t, prec=_p, sep=_SPACE_))
1147
- t = tm.reverse(t.easting, t.northing)
1148
- printf('%s: %s', tm.classname, fstr(t, prec=_p, sep=_SPACE_))
1149
1160
 
1161
+ _main()
1150
1162
 
1151
- # % python3 -m pygeodesy.etm -p 12 33.33 44.44
1163
+ # % python3.12 -m pygeodesy.etm -p 12 33.33 44.44
1152
1164
  # ExactTransverseMercator: 4276926.11480390653 4727193.767015309073 28.375536563148 1.233325101778
1153
1165
  # ExactTransverseMercator: 33.33 44.44 28.375536563148 1.233325101778
1154
1166
 
1155
- # % python3 -m pygeodesy.etm -s -p 12 33.33 44.44
1156
- # KTransverseMercator: 4276926.114803904667 4727193.767015310004 28.375536563148 1.233325101778
1157
- # KTransverseMercator: 33.33 44.44 28.375536563148 1.233325101778
1167
+ # % python3.12 -s -m pygeodesy.etm -p 12 33.33 44.44
1168
+ # ExactTransverseMercator: 4276926.11480390653 4727193.767015309073 28.375536563148 1.233325101778
1169
+ # ExactTransverseMercator: 33.33 44.44 28.375536563148 1.233325101778
1158
1170
 
1159
1171
  # % echo 33.33 44.44 | .../bin/TransverseMercatorProj
1160
1172
  # 4276926.114804 4727193.767015 28.375536563148 1.233325101778
pygeodesy/fmath.py CHANGED
@@ -14,7 +14,7 @@ from pygeodesy.constants import EPS0, EPS02, EPS1, NAN, PI, PI_2, PI_4, \
14
14
  from pygeodesy.errors import _IsnotError, LenError, _TypeError, _ValueError, \
15
15
  _xError, _xkwds_get1, _xkwds_pop2
16
16
  from pygeodesy.fsums import _2float, Fsum, fsum, fsum1_, _isFsumTuple, _1primed, \
17
- Fmt, unstr
17
+ Fmt, unstr
18
18
  from pygeodesy.interns import MISSING, _negative_, _not_scalar_
19
19
  from pygeodesy.lazily import _ALL_LAZY, _sys_version_info2
20
20
  # from pygeodesy.streprs import Fmt, unstr # from .fsums
@@ -24,10 +24,10 @@ from math import fabs, sqrt # pow
24
24
  import operator as _operator # in .datums, .trf, .utm
25
25
 
26
26
  __all__ = _ALL_LAZY.fmath
27
- __version__ = '24.08.15'
27
+ __version__ = '24.09.09'
28
28
 
29
- # sqrt(2) <https://WikiPedia.org/wiki/Square_root_of_2>
30
- _0_4142 = 0.41421356237309504880 # ... sqrt(2) - 1
29
+ # sqrt(2) - 1 <https://WikiPedia.org/wiki/Square_root_of_2>
30
+ _0_4142 = 0.41421356237309504880 # ... ~ 3730904090310553 / 9007199254740992
31
31
  _2_3rd = _1_3rd * 2
32
32
  _h_lt_b_ = 'abs(h) < abs(b)'
33
33
 
@@ -36,13 +36,10 @@ class Fdot(Fsum):
36
36
  '''Precision dot product.
37
37
  '''
38
38
  def __init__(self, a, *b, **name_RESIDUAL):
39
- '''New L{Fdot} precision dot product M{sum(a[i] * b[i] for
40
- i=0..len(a)-1)}.
39
+ '''New L{Fdot} precision dot product M{sum(a[i] * b[i] for i=0..len(a)-1)}.
41
40
 
42
- @arg a: Iterable of values (each C{scalar} or an L{Fsum} or L{Fsum2Tuple}
43
- instance).
44
- @arg b: Other values (each C{scalar} or an L{Fsum} or L{Fsum2Tuple} instance),
45
- all positional.
41
+ @arg a: Iterable of values (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
42
+ @arg b: Other values (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}), all positional.
46
43
  @kwarg name_RESIDUAL: Optional C{B{name}=NN} (C{str}) and the C{B{RESIDUAL}=0.0}
47
44
  threshold (C{scalar}) for raising L{ResidualError}s, see class
48
45
  L{Fsum<Fsum.__init__>}.
@@ -64,14 +61,16 @@ class Fdot(Fsum):
64
61
  class Fhorner(Fsum):
65
62
  '''Precision polynomial evaluation using the Horner form.
66
63
  '''
67
- def __init__(self, x, *cs, **name_RESIDUAL):
68
- '''New L{Fhorner} evaluation of polynomial M{sum(cs[i] * x**i for
69
- i=0..len(cs)-1)}.
64
+ def __init__(self, x, *cs, **incx_name_RESIDUAL):
65
+ '''New L{Fhorner} evaluation of polynomial M{sum(cs[i] * x**i for i=0..n)} if
66
+ C{B{incx}=False} for decreasing exponent M{sum(... i=n..0)} where C{n =
67
+ len(cs) - 1}.
70
68
 
71
- @arg x: Polynomial argument (C{scalar} or an L{Fsum} or L{Fsum2Tuple}).
72
- @arg cs: Polynomial coeffients (each C{scalar} or an L{Fsum} or L{Fsum2Tuple}
73
- instance), all positional.
74
- @kwarg name_RESIDUAL: Optional C{B{name}=NN} (C{str}) and the C{B{RESIDUAL}=0.0}
69
+ @arg x: Polynomial argument (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
70
+ @arg cs: Polynomial coeffients (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}),
71
+ all positional.
72
+ @kwarg incx_name_RESIDUAL: Optional C{B{name}=NN} (C{str}), C{B{incx}=True}
73
+ for in-/decreasing exponents (C{bool}) and the C{B{RESIDUAL}=0.0}
75
74
  threshold (C{scalar}) for raising L{ResidualError}s, see class
76
75
  L{Fsum<Fsum.__init__>}.
77
76
 
@@ -83,9 +82,10 @@ class Fhorner(Fsum):
83
82
 
84
83
  @see: Function L{fhorner} and methods L{Fsum.fadd} and L{Fsum.fmul}.
85
84
  '''
85
+ incx, name_RESIDUAL = _xkwds_pop2(incx_name_RESIDUAL, incx=True)
86
86
  Fsum.__init__(self, **name_RESIDUAL)
87
87
  if cs:
88
- self._fhorner(x, cs, Fhorner.__name__)
88
+ self._fhorner(x, cs, Fhorner.__name__, incx=incx)
89
89
  else:
90
90
  self._fset_ps(_0_0)
91
91
 
@@ -94,11 +94,11 @@ class Fhypot(Fsum):
94
94
  '''Precision summation and hypotenuse, default C{root=2}.
95
95
  '''
96
96
  def __init__(self, *xs, **root_name_RESIDUAL_raiser):
97
- '''New L{Fhypot} hypotenuse of (the I{root} of) several components
98
- (raised to the power I{root}).
97
+ '''New L{Fhypot} hypotenuse of (the I{root} of) several components (raised
98
+ to the power I{root}).
99
99
 
100
- @arg xs: Components (each C{scalar} or an L{Fsum} or L{Fsum2Tuple} instance),
101
- all positional.
100
+ @arg xs: Components (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}), all
101
+ positional.
102
102
  @kwarg root_name_RESIDUAL_raiser: Optional, exponent and C{B{root}=2} order
103
103
  (C{scalar}), C{B{name}=NN} (C{str}), the C{B{RESIDUAL}=0.0}
104
104
  threshold (C{scalar}) and C{B{raiser}=True} (C{bool}) for
@@ -121,12 +121,12 @@ class Fpolynomial(Fsum):
121
121
  '''Precision polynomial evaluation.
122
122
  '''
123
123
  def __init__(self, x, *cs, **name_RESIDUAL):
124
- '''New L{Fpolynomial} evaluation of the polynomial
125
- M{sum(cs[i] * x**i for i=0..len(cs)-1)}.
124
+ '''New L{Fpolynomial} evaluation of the polynomial M{sum(cs[i] * x**i for
125
+ i=0..len(cs)-1)}.
126
126
 
127
- @arg x: Polynomial argument (C{scalar} or an L{Fsum} or L{Fsum2Tuple}).
128
- @arg cs: Polynomial coeffients (each C{scalar} or an L{Fsum} or L{Fsum2Tuple}
129
- instance), all positional.
127
+ @arg x: Polynomial argument (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
128
+ @arg cs: Polynomial coeffients (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}),
129
+ all positional.
130
130
  @kwarg name_RESIDUAL: Optional C{B{name}=NN} (C{str}) and the C{B{RESIDUAL}=0.0}
131
131
  threshold (C{scalar}) for raising L{ResidualError}s, see class
132
132
  L{Fsum<Fsum.__init__>}.
@@ -153,9 +153,9 @@ class Fpowers(Fsum):
153
153
  def __init__(self, power, *xs, **name_RESIDUAL_raiser):
154
154
  '''New L{Fpowers} sum of (the I{power} of) several bases.
155
155
 
156
- @arg power: The exponent (C{scalar} or an L{Fsum} or L{Fsum2Tuple}).
157
- @arg xs: One or more bases (each C{scalar} or an L{Fsum} or L{Fsum2Tuple} instance),
158
- all positional.
156
+ @arg power: The exponent (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
157
+ @arg xs: One or more bases (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}), all
158
+ positional.
159
159
  @kwarg name_RESIDUAL_raiser: Optional C{B{name}=NN} (C{str}), the C{B{RESIDUAL}=0.0}
160
160
  threshold (C{scalar}) and C{B{raiser}=True} (C{bool}) for raising
161
161
  L{ResidualError}s, see class L{Fsum<Fsum.__init__>} and method
@@ -175,9 +175,9 @@ class Froot(Fsum):
175
175
  def __init__(self, root, *xs, **name_RESIDUAL_raiser):
176
176
  '''New L{Froot} root of a precision sum.
177
177
 
178
- @arg root: The order (C{scalar} or an L{Fsum} or L{Fsum2Tuple}), non-zero.
179
- @arg xs: Items to summate (each a C{scalar} or an L{Fsum} or L{Fsum2Tuple} instance),
180
- all positional.
178
+ @arg root: The order (C{scalar}, an L{Fsum} or L{Fsum2Tuple}), non-zero.
179
+ @arg xs: Items to summate (each a C{scalar}, an L{Fsum} or L{Fsum2Tuple}), all
180
+ positional.
181
181
  @kwarg name_RESIDUAL_raiser: Optional C{B{name}=NN} (C{str}), the C{B{RESIDUAL}=0.0}
182
182
  threshold (C{scalar}) and C{B{raiser}=True} (C{bool}) for raising
183
183
  L{ResidualError}s, see class L{Fsum<Fsum.__init__>} and method
@@ -226,7 +226,7 @@ def bqrt(x):
226
226
  '''Return the 4-th, I{bi-quadratic} or I{quartic} root, M{x**(1 / 4)},
227
227
  preserving C{type(B{x})}.
228
228
 
229
- @arg x: Value (C{scalar} or an L{Fsum} or L{Fsum2Tuple}).
229
+ @arg x: Value (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
230
230
 
231
231
  @return: I{Quartic} root (C{float} or an L{Fsum}).
232
232
 
@@ -256,7 +256,7 @@ except ImportError: # Python 3.10-
256
256
  def cbrt(x):
257
257
  '''Compute the cube root M{x**(1/3)}, preserving C{type(B{x})}.
258
258
 
259
- @arg x: Value (C{scalar} or an L{Fsum} or L{Fsum2Tuple}).
259
+ @arg x: Value (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
260
260
 
261
261
  @return: Cubic root (C{float} or L{Fsum}).
262
262
 
@@ -274,7 +274,7 @@ def cbrt(x):
274
274
  def cbrt2(x): # PYCHOK attr
275
275
  '''Compute the cube root I{squared} M{x**(2/3)}, preserving C{type(B{x})}.
276
276
 
277
- @arg x: Value (C{scalar} or an L{Fsum} or L{Fsum2Tuple}).
277
+ @arg x: Value (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
278
278
 
279
279
  @return: Cube root I{squared} (C{float} or L{Fsum}).
280
280
 
@@ -284,11 +284,11 @@ def cbrt2(x): # PYCHOK attr
284
284
 
285
285
 
286
286
  def euclid(x, y):
287
- '''I{Appoximate} the norm M{sqrt(x**2 + y**2)} by
288
- M{max(abs(x), abs(y)) + min(abs(x), abs(y)) * 0.4142...}.
287
+ '''I{Appoximate} the norm M{sqrt(x**2 + y**2)} by M{max(abs(x),
288
+ abs(y)) + min(abs(x), abs(y)) * 0.4142...}.
289
289
 
290
- @arg x: X component (C{scalar} or L{Fsum} instance).
291
- @arg y: Y component (C{scalar} or L{Fsum} instance).
290
+ @arg x: X component (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
291
+ @arg y: Y component (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
292
292
 
293
293
  @return: Appoximate norm (C{float} or L{Fsum}).
294
294
 
@@ -301,11 +301,11 @@ def euclid(x, y):
301
301
 
302
302
 
303
303
  def euclid_(*xs):
304
- '''I{Appoximate} the norm M{sqrt(sum(x**2 for x in xs))} by
305
- cascaded L{euclid}.
304
+ '''I{Appoximate} the norm M{sqrt(sum(x**2 for x in xs))} by cascaded
305
+ L{euclid}.
306
306
 
307
- @arg xs: X arguments (each C{scalar} or an L{Fsum}
308
- instance), all positional.
307
+ @arg xs: X arguments (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}),
308
+ all positional.
309
309
 
310
310
  @return: Appoximate norm (C{float} or L{Fsum}).
311
311
 
@@ -404,10 +404,10 @@ def fatan2(y, x):
404
404
 
405
405
 
406
406
  def favg(a, b, f=_0_5):
407
- '''Return the precision average of two values.
407
+ '''Return the precise average of two values.
408
408
 
409
- @arg a: One (C{scalar} or an L{Fsum} or L{Fsum2Tuple}).
410
- @arg b: Other (C{scalar} or an L{Fsum} or L{Fsum2Tuple}).
409
+ @arg a: One (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
410
+ @arg b: Other (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
411
411
  @kwarg f: Optional fraction (C{float}).
412
412
 
413
413
  @return: M{a + f * (b - a)} (C{float}).
@@ -421,11 +421,11 @@ def favg(a, b, f=_0_5):
421
421
 
422
422
 
423
423
  def fdot(a, *b):
424
- '''Return the precision dot product M{sum(a[i] * b[i] for
425
- i=0..len(a))}.
424
+ '''Return the precision dot product M{sum(a[i] * b[i] for ni=0..len(a))}.
426
425
 
427
- @arg a: Iterable of values (each C{scalar}).
428
- @arg b: Other values (each C{scalar}), all positional.
426
+ @arg a: Iterable of values (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
427
+ @arg b: Other values (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}), all
428
+ positional.
429
429
 
430
430
  @return: Dot product (C{float}).
431
431
 
@@ -438,22 +438,17 @@ def fdot(a, *b):
438
438
 
439
439
 
440
440
  def fdot3(xs, ys, zs, start=0):
441
- '''Return the precision dot product M{start +
442
- sum(a[i] * b[i] * c[i] for i=0..len(a)-1)}.
443
-
444
- @arg xs: Iterable (each C{scalar} or an L{Fsum} or
445
- L{Fsum2Tuple} instance).
446
- @arg ys: Iterable (each C{scalar} or an L{Fsum} or
447
- L{Fsum2Tuple} instance).
448
- @arg zs: Iterable (each C{scalar} or an L{Fsum} or
449
- L{Fsum2Tuple} instance).
450
- @kwarg start: Optional bias (C{scalar} or an L{Fsum}
451
- or L{Fsum2Tuple}).
441
+ '''Return the precision dot product M{start + sum(a[i] * b[i] * c[i]
442
+ for i=0..len(a)-1)}.
443
+
444
+ @arg xs: Iterable (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
445
+ @arg ys: Iterable (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
446
+ @arg zs: Iterable (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
447
+ @kwarg start: Optional bias (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
452
448
 
453
449
  @return: Dot product (C{float}).
454
450
 
455
- @raise LenError: Unequal C{len(B{xs})}, C{len(B{ys})}
456
- and/or C{len(B{zs})}.
451
+ @raise LenError: Unequal C{len(B{xs})}, C{len(B{ys})} and/or C{len(B{zs})}.
457
452
 
458
453
  @raise OverflowError: Partial C{2sum} overflow.
459
454
  '''
@@ -462,9 +457,8 @@ def fdot3(xs, ys, zs, start=0):
462
457
  yield s
463
458
  if p:
464
459
  yield _1_0
465
- _F = Fsum
466
460
  for x, y, z in zip(xs, ys, zs):
467
- yield (_F(x) * y) * z
461
+ yield (Fsum(x) * y) * z
468
462
  if p:
469
463
  yield _N_1_0
470
464
 
@@ -475,15 +469,16 @@ def fdot3(xs, ys, zs, start=0):
475
469
  return fsum(_mul3(xs, ys, zs, start, n < 4))
476
470
 
477
471
 
478
- def fhorner(x, *cs):
479
- '''Evaluate the polynomial M{sum(cs[i] * x**i for
480
- i=0..len(cs)-1)} using the Horner form.
472
+ def fhorner(x, *cs, **incx):
473
+ '''Evaluate a polynomial using the Horner form M{sum(cs[i] * x**i
474
+ for i=0..n)} or if C{B{incx}=False} for decreasing exponent
475
+ M{sum(... i=n..0)} where C{n = len(cs) - 1}.
481
476
 
482
477
  @return: Horner sum (C{float}).
483
478
 
484
479
  @see: Class L{Fhorner} for further details.
485
480
  '''
486
- H = Fhorner(x, *cs)
481
+ H = Fhorner(x, *cs, **incx)
487
482
  return float(H)
488
483
 
489
484
 
@@ -491,10 +486,9 @@ def fidw(xs, ds, beta=2):
491
486
  '''Interpolate using U{Inverse Distance Weighting
492
487
  <https://WikiPedia.org/wiki/Inverse_distance_weighting>} (IDW).
493
488
 
494
- @arg xs: Known values (each C{scalar} or an L{Fsum} or
495
- L{Fsum2Tuple} instance).
496
- @arg ds: Non-negative distances (each C{scalar} or an L{Fsum}
497
- or L{Fsum2Tuple} instance).
489
+ @arg xs: Known values (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
490
+ @arg ds: Non-negative distances (each C{scalar}, an L{Fsum} or
491
+ L{Fsum2Tuple}).
498
492
  @kwarg beta: Inverse distance power (C{int}, 0, 1, 2, or 3).
499
493
 
500
494
  @return: Interpolated value C{x} (C{float}).
@@ -550,10 +544,22 @@ def fidw(xs, ds, beta=2):
550
544
  return x
551
545
 
552
546
 
547
+ def fma(x, y, z):
548
+ '''Fused-multiply-add, as C{math.fma(x, y, z)} from Python 3.13+.
549
+
550
+ @arg x: A C{scalar}, an L{Fsum} or L{Fsum2Tuple} instance.
551
+ @arg y: A C{scalar}, an L{Fsum} or L{Fsum2Tuple} instance.
552
+ @arg z: A C{scalar}, an L{Fsum} or L{Fsum2Tuple} instance.
553
+
554
+ @return: C{(x * y) + z} (C{float} or an L{Fsum}).
555
+ '''
556
+ return Fsum(x).fma(y, z).as_iscalar
557
+
558
+
553
559
  def fmean(xs):
554
560
  '''Compute the accurate mean M{sum(xs) / len(xs)}.
555
561
 
556
- @arg xs: Values (C{scalar} or L{Fsum} instances).
562
+ @arg xs: Values (each C{scalar}, or L{Fsum} or L{Fsum2Tuple}).
557
563
 
558
564
  @return: Mean value (C{float}).
559
565
 
@@ -576,8 +582,8 @@ def fmean_(*xs):
576
582
 
577
583
 
578
584
  def fpolynomial(x, *cs, **over):
579
- '''Evaluate the polynomial M{sum(cs[i] * x**i for
580
- i=0..len(cs)) [/ over]}.
585
+ '''Evaluate the polynomial M{sum(cs[i] * x**i for i=0..len(cs))
586
+ [/ over]}.
581
587
 
582
588
  @kwarg over: Optional final, I{non-zero} divisor (C{scalar}).
583
589
 
@@ -593,7 +599,7 @@ def fpolynomial(x, *cs, **over):
593
599
  def fpowers(x, n, alts=0):
594
600
  '''Return a series of powers M{[x**i for i=1..n]}.
595
601
 
596
- @arg x: Value (C{scalar} or an L{Fsum} or L{Fsum2Tuple}).
602
+ @arg x: Value (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
597
603
  @arg n: Highest exponent (C{int}).
598
604
  @kwarg alts: Only alternating powers, starting with this
599
605
  exponent (C{int}).
@@ -627,7 +633,7 @@ except ImportError:
627
633
  '''Iterable product, like C{math.prod} or C{numpy.prod}.
628
634
 
629
635
  @arg xs: Iterable of values to be multiplied (each
630
- C{scalar} or an L{Fsum}).
636
+ C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
631
637
  @kwarg start: Initial value, also the value returned
632
638
  for an empty B{C{xs}} (C{scalar}).
633
639
 
@@ -822,8 +828,8 @@ def hypot1(x):
822
828
  def hypot2(x, y):
823
829
  '''Compute the I{squared} norm M{x**2 + y**2}.
824
830
 
825
- @arg x: X (C{scalar} or L{Fsum} or L{Fsum2Tuple}).
826
- @arg y: Y (C{scalar} or L{Fsum} or L{Fsum2Tuple}).
831
+ @arg x: X (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
832
+ @arg y: Y (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
827
833
 
828
834
  @return: C{B{x}**2 + B{y}**2} (C{float}).
829
835
  '''
@@ -843,8 +849,8 @@ def hypot2(x, y):
843
849
  def hypot2_(*xs):
844
850
  '''Compute the I{squared} norm C{fsum(x**2 for x in B{xs})}.
845
851
 
846
- @arg xs: Components (each C{scalar} or an L{Fsum} or
847
- L{Fsum2Tuple} instance), all positional.
852
+ @arg xs: Components (each C{scalar}, an L{Fsum} or
853
+ L{Fsum2Tuple}), all positional.
848
854
 
849
855
  @return: Squared norm (C{float}).
850
856
 
@@ -899,9 +905,10 @@ def norm2(x, y):
899
905
 
900
906
 
901
907
  def norm_(*xs):
902
- '''Normalize all n-dimensional vector components.
908
+ '''Normalize the components of an n-dimensional vector.
903
909
 
904
- @arg xs: Components (C{scalar}s), all positional.
910
+ @arg xs: Components (each C{scalar}, an L{Fsum} or
911
+ L{Fsum2Tuple}), all positional.
905
912
 
906
913
  @return: Yield each component, normalized.
907
914
 
@@ -944,7 +951,7 @@ def sqrt0(x, Error=None):
944
951
  '''Return the square root C{sqrt(B{x})} iff C{B{x} > }L{EPS02},
945
952
  preserving C{type(B{x})}.
946
953
 
947
- @arg x: Value (C{scalar} or an L{Fsum} or L{Fsum2Tuple}).
954
+ @arg x: Value (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
948
955
  @kwarg Error: Error to raise for negative B{C{x}}.
949
956
 
950
957
  @return: Square root (C{float} or L{Fsum}) or C{0.0}.
@@ -956,14 +963,15 @@ def sqrt0(x, Error=None):
956
963
  '''
957
964
  if Error and x < 0:
958
965
  raise Error(unstr(sqrt0, x))
959
- return _root(x, _0_5, sqrt0) if x > EPS02 else (_0_0 if x < EPS02 else EPS0)
966
+ return _root(x, _0_5, sqrt0) if x > EPS02 else (
967
+ _0_0 if x < EPS02 else EPS0)
960
968
 
961
969
 
962
970
  def sqrt3(x):
963
971
  '''Return the square root, I{cubed} M{sqrt(x)**3} or M{sqrt(x**3)},
964
972
  preserving C{type(B{x})}.
965
973
 
966
- @arg x: Value (C{scalar} or an L{Fsum} or L{Fsum2Tuple}).
974
+ @arg x: Value (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
967
975
 
968
976
  @return: Square root I{cubed} (C{float} or L{Fsum}).
969
977
 
@@ -1019,7 +1027,7 @@ def zcrt(x):
1019
1027
  '''Return the 6-th, I{zenzi-cubic} root, M{x**(1 / 6)},
1020
1028
  preserving C{type(B{x})}.
1021
1029
 
1022
- @arg x: Value (C{scalar} or an L{Fsum} or L{Fsum2Tuple}).
1030
+ @arg x: Value (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
1023
1031
 
1024
1032
  @return: I{Zenzi-cubic} root (C{float} or L{Fsum}).
1025
1033
 
@@ -1036,7 +1044,7 @@ def zqrt(x):
1036
1044
  '''Return the 8-th, I{zenzi-quartic} or I{squared-quartic} root,
1037
1045
  M{x**(1 / 8)}, preserving C{type(B{x})}.
1038
1046
 
1039
- @arg x: Value (C{scalar} or an L{Fsum} or L{Fsum2Tuple}).
1047
+ @arg x: Value (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
1040
1048
 
1041
1049
  @return: I{Zenzi-quartic} root (C{float} or L{Fsum}).
1042
1050