pygeodesy 25.12.12__py2.py3-none-any.whl → 25.12.31__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
@@ -5,16 +5,16 @@ u'''Class L{Fsum} for precision floating point summation similar to
5
5
  Python's C{math.fsum}, but enhanced with I{precision running} summation
6
6
  plus optionally, accurate I{TwoProduct} multiplication.
7
7
 
8
- Accurate multiplication is based on the C{math.fma} function from
9
- Python 3.13 and newer or an equivalent C{fma} implementation for
10
- Python 3.12 and older. To enable accurate multiplication, set env
11
- variable C{PYGEODESY_FSUM_F2PRODUCT} to C{"std"} or any non-empty
12
- string or invoke function C{pygeodesy.f2product(True)} or set. With
13
- C{"std"} the C{fma} implemention follows the C{math.fma} function,
14
- otherwise the C{PyGeodesy 24.09.09} release.
8
+ Accurate multiplication is based on the C{math.fma} function from Python
9
+ 3.13 and newer or an equivalent C{fma} implementation for Python 3.12 and
10
+ older. Set env variable C{PYGEODESY_FSUM_F2PRODUCT} to C{"std"} or any
11
+ non-empty string or invoke function C{pygeodesy.f2product(True)} to enable
12
+ accurate multiplication. With C{"std"} the C{fma} implemention follows
13
+ the C{math.fma} function, otherwise the implementation of the C{PyGeodesy
14
+ 24.09.09} release.
15
15
 
16
16
  Generally, an L{Fsum} instance is considered a C{float} plus a small or
17
- zero C{residue} aka C{residual} value, see property L{Fsum.residual}.
17
+ zero C{residue} aka C{residual}, see property L{Fsum.residual}.
18
18
 
19
19
  Set env variable C{PYGEODESY_FSUM_RESIDUAL} to a C{float} string greater
20
20
  than C{"0.0"} as the threshold to throw a L{ResidualError} for a division,
@@ -28,7 +28,7 @@ L{Fsum.fint2} and L{Fsum.is_integer}. Also, L{Fsum} methods L{Fsum.pow},
28
28
  L{Fsum.__ipow__}, L{Fsum.__pow__} and L{Fsum.__rpow__} return a (very long)
29
29
  C{int} if invoked with optional argument C{mod} set to C{None}. The
30
30
  C{residual} of an C{integer} L{Fsum} is between C{-1.0} and C{+1.0} and
31
- will be C{INT0} if that is considered to be I{exact}.
31
+ will be C{INT0} if that L{Fsum} is an I{exact float} or I{exact integer}.
32
32
 
33
33
  Set env variable C{PYGEODESY_FSUM_NONFINITES} to C{"std"} or use function
34
34
  C{pygeodesy.nonfiniterrors(False)} to allow I{non-finite} C{float}s like
@@ -62,7 +62,7 @@ from math import fabs, isinf, isnan, \
62
62
  ceil as _ceil, floor as _floor # PYCHOK used! .ltp
63
63
 
64
64
  __all__ = _ALL_LAZY.fsums
65
- __version__ = '25.06.03'
65
+ __version__ = '25.12.24'
66
66
 
67
67
  from pygeodesy.interns import (
68
68
  _PLUS_ as _add_op_, # in .auxilats.auxAngle
@@ -321,8 +321,8 @@ def nonfiniterrors(raiser=None):
321
321
  '''
322
322
  d = Fsum._isfine
323
323
  if raiser is not None:
324
- Fsum._isfine = {} if bool(raiser) else Fsum._nonfinites_isfine_kwds[True]
325
- return (False if d is Fsum._nonfinites_isfine_kwds[True] else
324
+ Fsum._isfine = {} if bool(raiser) else _nonfinites_isfine_kwds[True]
325
+ return (False if d is _nonfinites_isfine_kwds[True] else
326
326
  _xkwds_get1(d, _isfine=_isfinite) is _isfinite) if d else True
327
327
 
328
328
 
@@ -370,7 +370,7 @@ def _Psum(ps, **name_f2product_nonfinites_RESIDUAL):
370
370
  return F
371
371
 
372
372
 
373
- def _Psum_(*ps, **name_f2product_nonfinites_RESIDUAL): # in .fmath
373
+ def _Psum_(*ps, **name_f2product_nonfinites_RESIDUAL):
374
374
  '''(INTERNAL) Return an C{Fsum} from I{known scalar} C{ps}.
375
375
  '''
376
376
  return _Psum(ps, **name_f2product_nonfinites_RESIDUAL)
@@ -486,7 +486,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
486
486
 
487
487
  @note: Handling of I{non-finites} as C{inf}, C{INF}, C{NINF}, C{nan} and C{NAN} is
488
488
  determined by function L{nonfiniterrors<fsums.nonfiniterrors>} for the default
489
- and by method L{nonfinites<Fsum.nonfinites>} for individual C{Fsum} instances,
489
+ or by method L{nonfinites<Fsum.nonfinites>} for individual C{Fsum} instances,
490
490
  overruling the default. For backward compatibility, I{non-finites} raise
491
491
  exceptions by default.
492
492
 
@@ -829,7 +829,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
829
829
  return self._cmp_0(other, _lt_op_ + _fset_op_) <= 0
830
830
 
831
831
  def __len__(self):
832
- '''Return the number of values accumulated (C{int}).
832
+ '''Return the number of (non-zero) values accumulated (C{int}).
833
833
  '''
834
834
  return self._n
835
835
 
@@ -1447,7 +1447,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1447
1447
  @arg other2: Addend (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
1448
1448
  @kwarg nonfinites: Use C{B{nonfinites}=True} or C{False}, to
1449
1449
  override L{nonfinites<Fsum.nonfinites>} and
1450
- L{nonfiniterrors} default (C{bool}).
1450
+ the L{nonfiniterrors} default (C{bool}).
1451
1451
  '''
1452
1452
  op = typename(self.fma)
1453
1453
  _fs = self._ps_other
@@ -1479,7 +1479,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1479
1479
  an L{Fsum} or L{Fsum2Tuple}), all positional.
1480
1480
  @kwarg nonfinites: Use C{B{nonfinites}=True} or C{False}, to
1481
1481
  override L{nonfinites<Fsum.nonfinites>} and
1482
- L{nonfiniterrors} default (C{bool}).
1482
+ the L{nonfiniterrors} default (C{bool}).
1483
1483
 
1484
1484
  @note: Equivalent to L{fdot_<pygeodesy.fmath.fdot_>}C{(*xys,
1485
1485
  start=self)}.
@@ -1615,8 +1615,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1615
1615
  '''
1616
1616
  if two: # delattrof(self, _f2product=None)
1617
1617
  t = _xkwds_pop(self.__dict__, _f2product=None)
1618
- if two[0] is not None:
1619
- self._f2product = bool(two[0])
1618
+ self._optionals(f2product=two[0])
1620
1619
  else: # getattrof(self, _f2product=None)
1621
1620
  t = _xkwds_get(self.__dict__, _f2product=None)
1622
1621
  return t
@@ -2070,25 +2069,21 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2070
2069
  @see: Function L{nonfiniterrors<fsums.nonfiniterrors>}.
2071
2070
 
2072
2071
  @note: Use property L{nonfinitesOK<Fsum.nonfinitesOK>} to determine
2073
- whether I{non-finites} are C{OK} for this L{Fsum} and by the
2072
+ whether I{non-finites} are C{OK} for this L{Fsum} or by the
2074
2073
  L{nonfiniterrors} default.
2075
2074
  '''
2076
- _ks = Fsum._nonfinites_isfine_kwds
2077
2075
  if OK: # delattrof(self, _isfine=None)
2078
2076
  k = _xkwds_pop(self.__dict__, _isfine=None)
2079
- if OK[0] is not None:
2080
- self._isfine = _ks[bool(OK[0])]
2077
+ self._optionals(nonfinites=OK[0])
2081
2078
  self._update()
2082
2079
  else: # getattrof(self, _isfine=None)
2083
2080
  k = _xkwds_get(self.__dict__, _isfine=None)
2081
+ _ks = _nonfinites_isfine_kwds
2084
2082
  # dict(map(reversed, _ks.items())).get(k, None)
2085
2083
  # raises a TypeError: unhashable type: 'dict'
2086
2084
  return True if k is _ks[True] else (
2087
2085
  False if k is _ks[False] else None)
2088
2086
 
2089
- _nonfinites_isfine_kwds = {True: dict(_isfine=_isOK),
2090
- False: dict(_isfine=_isfinite)}
2091
-
2092
2087
  @property_RO
2093
2088
  def nonfinitesOK(self):
2094
2089
  '''Are I{non-finites} C{OK} for this L{Fsum} or by default? (C{bool}).
@@ -2111,9 +2106,9 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2111
2106
  '''(INTERNAL) Re/set options from keyword arguments.
2112
2107
  '''
2113
2108
  if f2product is not None:
2114
- self.f2product(f2product)
2109
+ self._f2product = bool(f2product)
2115
2110
  if nonfinites is not None:
2116
- self.nonfinites(nonfinites)
2111
+ self._isfine = _nonfinites_isfine_kwds[bool(nonfinites)]
2117
2112
  if name_RESIDUAL: # MUST be last
2118
2113
  n, kwds = _name2__(**name_RESIDUAL)
2119
2114
  if kwds:
@@ -2535,6 +2530,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2535
2530
 
2536
2531
  _ROs = _allPropertiesOf_n(3, Fsum, Property_RO) # PYCHOK see Fsum._update
2537
2532
 
2533
+ _nonfinites_isfine_kwds = {True: dict(_isfine=_isOK),
2534
+ False: dict(_isfine=_isfinite)}
2538
2535
  if _NONFINITES == _std_: # PYCHOK no cover
2539
2536
  _ = nonfiniterrors(False)
2540
2537
 
@@ -2685,6 +2682,21 @@ class Fsum2Tuple(_NamedTuple): # in .fstats
2685
2682
  _Fsum_2Tuple_types = Fsum, Fsum2Tuple # PYCHOK lines
2686
2683
 
2687
2684
 
2685
+ class _Ksum(Fsum):
2686
+ '''(INTERNAL) For C{.karney._sum3}, specifically and only.
2687
+ '''
2688
+ _isfine = _nonfinites_isfine_kwds[True]
2689
+
2690
+ def __init__(self, s, t, *xs):
2691
+ ps = [t, s] if t else [s]
2692
+ self._ps = self._ps_acc(ps, xs, up=False)
2693
+
2694
+ @property_RO
2695
+ def _s_t_n3(self):
2696
+ s, t = self._fprs2
2697
+ return s, t, self._n
2698
+
2699
+
2688
2700
  class ResidualError(_ValueError):
2689
2701
  '''Error raised for a division, power or root operation of
2690
2702
  an L{Fsum} instance with a C{residual} I{ratio} exceeding
pygeodesy/geod3solve.py CHANGED
@@ -5,13 +5,14 @@ u'''Wrapper to invoke I{Karney}'s U{Geod3Solve
5
5
  <https://GeographicLib.SourceForge.io/C++/doc/Geod3Solve.1.html>} utility
6
6
  as a C{triaxial} geodesic, but intended I{mainly for testing purposes}.
7
7
 
8
- Set env variable C{PYGEODESY_GEOD3SOLVE} to the (fully qualified) path
9
- of the C{Geod3Solve} executable.
8
+ Set env variable C{PYGEODESY_GEOD3SOLVE} to the (fully qualified) path of
9
+ the C{Geod3Solve} executable or use property L{Geodesic3Solve.Geod3Solve
10
+ <geod3solve._Geodesic3SolveBase.Geod3Solve>}.
10
11
  '''
11
12
 
12
13
  from pygeodesy.angles import Ang, Deg, isAng, hypot
13
14
  from pygeodesy.basics import _xinstanceof # typename
14
- from pygeodesy.constants import _0_0, _0_5, _360_0
15
+ from pygeodesy.constants import _0_0, _0_5, _360_0, _over
15
16
  from pygeodesy.errors import GeodesicError, _xkwds_get
16
17
  # from pygeodesy.fmath import hypot # from .angles
17
18
  # from pygeodesy.geodesicx import GeodesicAreaExact # _MODS
@@ -25,7 +26,7 @@ from pygeodesy.units import Degrees, Meter
25
26
  # from pygeodesy.utily import sincos2d # from .karney
26
27
 
27
28
  __all__ = _ALL_LAZY.geod3solve
28
- __version__ = '25.12.12'
29
+ __version__ = '25.12.31'
29
30
 
30
31
  _Triaxial3_WGS84 = Triaxial3s.WGS84_3r # a=6378172, b=6378102, c=6356752
31
32
 
@@ -39,8 +40,8 @@ class Geodesic3Error(GeodesicError):
39
40
  class Geod3Solve8Tuple(_GTuple):
40
41
  '''8-Tuple C{(bet1, omg1, alp1, bet2, omg2, alp2, s12, a12)} with C{ellipsoidal}
41
42
  latitudes C{bet1} and C{bet2}, C{ellipsoidal} longitudes C{omg1} and C{omg2},
42
- forward azimuths C{alp1} and C{alp2} in bearings from North, distanc C{s12} in
43
- C{meter}, conventionally and I{approximate} arc length {a12} in degrees, see
43
+ forward azimuths C{alp1} and C{alp2} in bearings from North, distance C{s12} in
44
+ C{meter}, conventionally and I{approximate} arc length C{a12} in degrees, see
44
45
  U{Geod3Solve<https://GeographicLib.SourceForge.io/C++/doc/Geod3Solve.1.html>}.
45
46
  '''
46
47
  # from Geod3Solve --help option -f ... bet1 omg1 alp1 bet2 omg2 alp2 s12
@@ -161,11 +162,11 @@ class Geodesic3Solve(_Geodesic3SolveBase):
161
162
  '''
162
163
  a = r.s12 or _0_0
163
164
  if a:
165
+ t = self.triaxial3
164
166
  z = _toAzi(r.alp1) + _toAzi(r.alp2)
165
167
  s, c = sincos2d(z * _0_5)
166
- t = self.triaxial3
167
- a *= hypot(s / t._ab_elliperim, # azimuth!
168
- c / t._bc_elliperim) * _360_0
168
+ a *= hypot(_over(s, t.perimeter4ab), # azimuth!
169
+ _over(c, t.perimeter4bc)) * _360_0
169
170
  r[_a12_] = a
170
171
  return r
171
172
 
pygeodesy/geodesici.py CHANGED
@@ -7,10 +7,11 @@ Class L{Intersector} is a pure Python version of I{Karney}'s C++ class U{Interse
7
7
  <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1Intersect.html>}.
8
8
 
9
9
  Class L{Intersectool} is a wrapper to invoke I{Karney}'s U{IntersectTool
10
- <https://GeographicLib.SourceForge.io/C++/doc/IntersectTool.1.html>} utility, but intended I{for testing purposes only}.
10
+ <https://GeographicLib.SourceForge.io/C++/doc/IntersectTool.1.html>} utility, mainly intended I{for testing purposes}.
11
11
 
12
- Set env variable C{PYGEODESY_INTERSECTTOOL} to the (fully qualified) path of the C{IntersectTool} executable. For usage
13
- and some examples run C{"env PYGEODESY_INTERSECTTOOL=<IntersectTool-path> python3 -m pygeodesy.geodesici --help"}.
12
+ Set env variable C{PYGEODESY_INTERSECTTOOL} to the (fully qualified) path of the C{IntersectTool} executable or use
13
+ property L{Intersectool.IntersectTool}. For usage and some examples run C{"env PYGEODESY_INTERSECTTOOL=<IntersectTool-path>
14
+ python3 -m pygeodesy.geodesici --help"}.
14
15
 
15
16
  Both L{Intersectool} and L{Intersector} provide methods C{All}, C{Closest}, C{Next} and C{Segment} and produce
16
17
  L{XDict} instances with 4 or more items. Adjacent methods C{All5}, C{Closest5}, C{Next5} and C{Segment} return
@@ -57,7 +58,7 @@ from pygeodesy.utily import atan2, sincos2, fabs, radians
57
58
  # from math import ceil as _ceil, fabs, radians # .fsums, .utily
58
59
 
59
60
  __all__ = _ALL_LAZY.geodesici
60
- __version__ = '25.06.02'
61
+ __version__ = '25.12.31'
61
62
 
62
63
  _0t = 0, # int
63
64
  _1_1t = -1, +1
@@ -23,7 +23,7 @@ from pygeodesy.karney import Caps, GeodesicError
23
23
  from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY
24
24
 
25
25
  __all__ = _ALL_LAZY.geodesicx + _ALL_DOCS(Caps, GeodesicError)
26
- __version__ = '25.09.02'
26
+ __version__ = '25.12.23'
27
27
 
28
28
  # **) MIT License
29
29
  #
@@ -19,19 +19,20 @@ from __future__ import division as _; del _ # noqa: E702 ;
19
19
 
20
20
  from pygeodesy.basics import _copysign, isodd, unsigned0
21
21
  from pygeodesy.constants import NAN, _0_0, _0_5, _720_0
22
+ from pygeodesy.fmath import _fma
22
23
  from pygeodesy.internals import printf, typename
23
24
  # from pygeodesy.interns import _COMMASPACE_ # from .lazily
24
25
  from pygeodesy.karney import Area3Tuple, _diff182, GeodesicError, \
25
- _norm180, _remainder, _sum3
26
+ _norm180, _remainder, _sum2
26
27
  from pygeodesy.lazily import _ALL_DOCS, _COMMASPACE_
27
28
  from pygeodesy.named import ADict, callername, _NamedBase, pairs
28
29
  from pygeodesy.props import Property, Property_RO, property_RO
29
30
  # from pygeodesy.streprs import pairs # from .named
30
31
 
31
- from math import fmod as _fmod
32
+ from math import fabs, fmod as _fmod
32
33
 
33
34
  __all__ = ()
34
- __version__ = '25.09.16'
35
+ __version__ = '25.12.23'
35
36
 
36
37
 
37
38
  class GeodesicAreaExact(_NamedBase):
@@ -427,30 +428,39 @@ class _Accumulator(_NamedBase):
427
428
  @kwarg y: Initial value (C{scalar}).
428
429
  @kwarg name: Optional C{B{name}=NN} (C{str}).
429
430
  '''
430
- if isinstance(y, _Accumulator):
431
- self._s, self._t, self._n = y._s, y._t, 1
432
- elif y:
433
- self._s, self._n = float(y), 1
431
+ self._s_t(*_s_t2(y))
432
+ self._n = 1
434
433
  if name:
435
434
  self.name = name
436
435
 
437
- def Add(self, y):
438
- '''Add a value.
436
+ def Add(self, *ys):
437
+ '''Add one or more scalars or L{_Accumulator}s.
439
438
 
440
439
  @return: Current C{sum}.
441
- '''
442
- self._n += 1
443
- self._s, self._t, _ = _sum3(self._s, self._t, y)
444
- return self._s # current .Sum()
440
+
441
+ @see: C++ U{Accumulator.Add<https://GeographicLib.sourceforge.io/C++/doc/Accumulator_8hpp_source.html>}
442
+ for more details about Karney's and Shewchuk's addition.
443
+ '''
444
+ # _Accumulator().Add(1, 1e20, 2, 100, 5000, -1e20) ... 5103.0
445
+ s, t = self._s, self._t
446
+ for y in ys:
447
+ for y in _s_t2(y):
448
+ if y:
449
+ t, u = _sum2(t, y)
450
+ s, t = _sum2(s, t)
451
+ if s: # accumlate u in t
452
+ t += u
453
+ else: # s == 0 implies t == 0
454
+ s = u
455
+ self._n += 1
456
+ return self._s_t(s, t)
445
457
 
446
458
  def Negate(self):
447
459
  '''Negate sum.
448
460
 
449
461
  @return: Current C{sum}.
450
462
  '''
451
- self._s = s = -self._s
452
- self._t = -self._t
453
- return s # current .Sum()
463
+ return self._s_t(-self._s, -self._t)
454
464
 
455
465
  @property_RO
456
466
  def num(self):
@@ -459,22 +469,27 @@ class _Accumulator(_NamedBase):
459
469
  return self._n
460
470
 
461
471
  def Remainder(self, y):
462
- '''Remainder on division by B{C{y}}.
472
+ '''Remainder of division by B{C{y}}.
463
473
 
464
474
  @return: Remainder of C{sum} / B{C{y}}.
465
475
  '''
466
- self._s = _remainder(self._s, y)
467
- # self._t = _remainder(self._t, y)
468
- self._n = -1
469
- return self.Add(_0_0)
476
+ return self._s_t(_remainder(self._s, y),
477
+ _remainder(self._t, y))
470
478
 
471
479
  def Reset(self, y=0):
472
- '''Set value from argument.
480
+ '''Reset from scalar or L{_Accumulator}.
473
481
  '''
474
- self._n, self._s, self._t = 0, float(y), _0_0
482
+ self._s_t(*_s_t2(y))
483
+ self._n = 0
475
484
 
476
485
  Set = Reset
477
486
 
487
+ def _s_t(self, s, t=0):
488
+ if t and fabs(s) < fabs(t):
489
+ s, t = t, s
490
+ self._s, self._t = s, t
491
+ return s
492
+
478
493
  def Sum(self, y=0):
479
494
  '''Return C{sum + B{y}}.
480
495
 
@@ -488,6 +503,17 @@ class _Accumulator(_NamedBase):
488
503
  s = self
489
504
  return s._s
490
505
 
506
+ def Times(self, y):
507
+ '''Multiply by a scalar.
508
+
509
+ @return: Current C{sum}.
510
+ '''
511
+ s = d = self._s
512
+ s *= y
513
+ d = _fma(y, d, -s)
514
+ t = _fma(y, self._t, d)
515
+ return self._s_t(s, t) # current .Sum()
516
+
491
517
  def toStr(self, prec=6, sep=_COMMASPACE_, **unused): # PYCHOK signature
492
518
  '''Return this C{_Accumulator} as string.
493
519
 
@@ -502,6 +528,10 @@ class _Accumulator(_NamedBase):
502
528
  return sep.join(pairs(d, prec=prec))
503
529
 
504
530
 
531
+ def _s_t2(y):
532
+ return (y._s, y._t) if isinstance(y, _Accumulator) else (float(y),) # PYCHOK OK
533
+
534
+
505
535
  __all__ += _ALL_DOCS(GeodesicAreaExact, PolygonArea)
506
536
 
507
537
  # **) MIT License
pygeodesy/geodsolve.py CHANGED
@@ -5,8 +5,9 @@ u'''Wrapper to invoke I{Karney}'s U{GeodSolve
5
5
  <https://GeographicLib.SourceForge.io/C++/doc/GeodSolve.1.html>} utility
6
6
  as an (exact) geodesic, but intended I{mainly for testing purposes}.
7
7
 
8
- Set env variable C{PYGEODESY_GEODSOLVE} to the (fully qualified) path
9
- of the C{GeodSolve} executable.
8
+ Set env variable C{PYGEODESY_GEODSOLVE} to the (fully qualified) path of
9
+ the C{GeodSolve} executable or use property L{GeodesicSolve.GeodSolve
10
+ <geodsolve._GeodesicSolveBase.GeodSolve>}.
10
11
  '''
11
12
 
12
13
  from pygeodesy.basics import _xinstanceof # typename
@@ -28,7 +29,7 @@ from pygeodesy.solveBase import _SolveGDictBase, _SolveGDictLineBase
28
29
  from pygeodesy.utily import _unrollon, _Wrap, wrap360
29
30
 
30
31
  __all__ = _ALL_LAZY.geodsolve
31
- __version__ = '25.12.06'
32
+ __version__ = '25.12.31'
32
33
 
33
34
 
34
35
  class GeodSolve12Tuple(_GTuple):
pygeodesy/karney.py CHANGED
@@ -153,14 +153,14 @@ in C{pygeodesy} are based on I{Karney}'s post U{Area of a spherical polygon
153
153
  # make sure int/int division yields float quotient, see .basics
154
154
  from __future__ import division as _; del _ # noqa: E702 ;
155
155
 
156
- from pygeodesy.basics import _copysign, _isin, isint, neg, unsigned0, \
157
- _xgeographiclib, _zip
156
+ from pygeodesy.basics import _copysign, _isin, isint, neg, _xgeographiclib, _zip
158
157
  from pygeodesy.constants import NAN, _isfinite as _math_isfinite, \
159
158
  _0_0, _1_0, _2_0, _180_0, _N_180_0, _360_0
160
159
  # from pygeodesy.deprecated.classes import Rhumb7Tuple # _MODS
161
160
  from pygeodesy.errors import GeodesicError, _ValueError, _xkwds
162
161
  # from pygeodesy.geod3Solve import Geod3Solve8Tuple # _MODS
163
- from pygeodesy.fmath import cbrt, fremainder, norm2 # Fhorner, Fsum
162
+ from pygeodesy.fmath import cbrt, fhorner, fremainder, norm2
163
+ from pygeodesy.fsums import _Ksum
164
164
  from pygeodesy.internals import _getenv, _popen2, _PYGEODESY_ENV, typename, \
165
165
  _version_info
166
166
  from pygeodesy.interns import NN, _a12_, _area_, _azi2_, _azi12_, _composite_, \
@@ -177,7 +177,7 @@ from pygeodesy.utily import atan2d, sincos2d, tand, _unrollon, fabs
177
177
  # from math import fabs # from .utily
178
178
 
179
179
  __all__ = _ALL_LAZY.karney
180
- __version__ = '25.12.12'
180
+ __version__ = '25.12.23'
181
181
 
182
182
  _1_16th = _1_0 / 16
183
183
  _2_4_ = '2.4'
@@ -913,20 +913,18 @@ try:
913
913
 
914
914
  except ImportError: # Python 3.12-
915
915
 
916
- def _poly_fma(x, s, *cs): # PYCHOK redef
917
- t = _0_0
918
- for c in cs:
919
- s, t, _ = _sum3(s * x, t * x, c)
920
- return s + t
916
+ def _poly_fma(x, *cs): # PYCHOK redef
917
+ return fhorner(x, *cs, incx=False)
921
918
 
922
919
  # def _poly_fma(x, s, *cs):
923
- # S = Fhorner(x, *cs, incx=False)
924
- # S += s
925
- # return float(S)
920
+ # t = _0_0
921
+ # for c in cs:
922
+ # s, t, _ = _sum3(s * x, t * x, c)
923
+ # return s + t
926
924
 
927
925
  def _polynomial(x, cs, i, j): # PYCHOK shared
928
- '''(INTERNAL) Like C++ C{GeographicLib.Math.hpp.polyval} but with a
929
- signature and cascaded summation different from C{karney._sum3}.
926
+ '''(INTERNAL) Like C++ C{GeographicLib.Math.hpp.polyval} but
927
+ with a different signature and cascaded summation.
930
928
 
931
929
  @return: M{sum(x**(j - k - 1) * cs[k] for k in range(i, j)}
932
930
  '''
@@ -1007,18 +1005,18 @@ def _sum2(a, b): # mimick geomath.Math.sum, actually sum2
1007
1005
  r = s - b
1008
1006
  t = s - r
1009
1007
  # elif C_CPP: # Math::sum C/C++
1010
- # r -= a; t -= b; t += r; t = -t
1011
- # else:
1012
- t = (a - r) + (b - t)
1008
+ # r -= a; t -= b; t += r; t = (-t) if s else s
1009
+ # else: # if s == 0: t = _copysign_0_0(s)
1010
+ t = ((a - r) + (b - t)) if s else s
1013
1011
  # assert fabs(s) >= fabs(t)
1014
1012
  return s, t
1015
1013
 
1016
1014
 
1017
1015
  def _sum3(s, t, *xs):
1018
- '''Accumulate any B{C{xs}} into a previous C{_sum2(s, t)}.
1016
+ '''Accumulate all B{C{xs}} scalars into a previous C{_sum2(s, t)}.
1019
1017
 
1020
1018
  @return: 3-Tuple C{(s, t, n)} where C{s} is the sum of B{s}, B{t} and all
1021
- B{xs}, C{t} the residual and C{n} the number of zero C{xs}.
1019
+ B{xs}, C{t} the residual and C{n} the number of non-zero C{xs}.
1022
1020
 
1023
1021
  @see: I{Karney's} C++ U{Accumulator<https://GeographicLib.SourceForge.io/
1024
1022
  C++/doc/Accumulator_8hpp_source.html>} comments for more details and
@@ -1026,23 +1024,10 @@ def _sum3(s, t, *xs):
1026
1024
 
1027
1025
  @note: Not "error-free", see C{pygeodesy.test/testKarney.py}.
1028
1026
  '''
1029
- z = 0
1030
- for x in xs:
1031
- if x:
1032
- t, r = _sum2(t, x) # start at the least-
1033
- if s:
1034
- s, t = _sum2(s, t) # -significant end
1035
- if s:
1036
- t += r # accumulate r into t
1037
- else:
1038
- # assert t == 0 # s == 0 implies t == 0
1039
- s = unsigned0(r) # result is r, t = 0
1040
- else:
1041
- s, t = unsigned0(t), r
1042
- else:
1043
- z += 1
1044
- # assert fabs(s) >= fabs(t)
1045
- return s, t, z
1027
+ return _Ksum(s, t, *xs)._s_t_n3 if xs else (s, t, 0)
1028
+ # previous _sum3 in .geodesicx.gxarea._Accumulator.Add
1029
+ # which fails .fmath.frandoms tests, but does pass
1030
+ # _sum3(1e20, 1, 2, 100, 5000, -1e20) ... 5103.0, 0.0, 4
1046
1031
 
1047
1032
 
1048
1033
  def _tand(x):
pygeodesy/lazily.py CHANGED
@@ -250,7 +250,7 @@ _ALL_LAZY = _NamedEnum_RO(_name='_ALL_LAZY',
250
250
  'fpolynomial', 'fpowers', 'fprod', 'frandoms', 'frange', 'freduce', 'fremainder',
251
251
  'hypot', 'hypot_', 'hypot1', 'hypot2', 'hypot2_',
252
252
  'norm2', 'norm_', 'sqrt0', 'sqrt3', 'sqrt_a', 'zcrt', 'zqrt'),
253
- formy=_a('Radical2Tuple',
253
+ formy=_a('Elliperim', 'Radical2Tuple',
254
254
  'angle2chord', 'antipode', 'antipode_', 'bearing', 'bearing_',
255
255
  'chord2angle', 'compassAngle', 'cosineLaw', 'cosineLaw_',
256
256
  'elliperim', 'equirectangular', 'equirectangular4', 'euclidean', 'euclidean_',
@@ -520,7 +520,7 @@ class _ALL_MODS(_internals._MODS_Base):
520
520
  _internals._MODS = _ALL_MODS = _ALL_MODS() # PYCHOK singleton
521
521
 
522
522
  __all__ = _ALL_LAZY.lazily
523
- __version__ = '25.12.12'
523
+ __version__ = '25.12.23'
524
524
 
525
525
 
526
526
  def _ALL_OTHER(*objs):
pygeodesy/named.py CHANGED
@@ -35,7 +35,7 @@ from pygeodesy.streprs import attrs, Fmt, lrstrip, pairs, reprs, unstr
35
35
  # from pygeodesy.units import _toUnit # _MODS
36
36
 
37
37
  __all__ = _ALL_LAZY.named
38
- __version__ = '25.11.29'
38
+ __version__ = '25.11.13'
39
39
 
40
40
  _COMMANL_ = _COMMA_ + _NL_
41
41
  _COMMASPACEDOT_ = _COMMASPACE_ + _DOT_
@@ -1188,7 +1188,7 @@ def callername(up=1, dflt=NN, source=False, underOK=False):
1188
1188
 
1189
1189
  @return: The callable name (C{str}) or B{C{dflt}} if none found.
1190
1190
  '''
1191
- try: # see .lazily._caller3
1191
+ try: # see .internals._caller3
1192
1192
  for u in range(up, up + 32):
1193
1193
  n, f, s = _caller3(u)
1194
1194
  if n and (underOK or n.startswith(_DUNDER_) or
pygeodesy/props.py CHANGED
@@ -26,7 +26,7 @@ from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, \
26
26
  from functools import wraps as _wraps
27
27
 
28
28
  __all__ = _ALL_LAZY.props
29
- __version__ = '25.05.26'
29
+ __version__ = '25.12.31'
30
30
 
31
31
  _class_ = 'class'
32
32
  _DNL_ = _NL_ * 2 # PYCHOK used!
@@ -696,8 +696,10 @@ class DeprecationWarnings(object):
696
696
  '''
697
697
  return self._Warnings if _WARNINGS_X_DEV else None
698
698
 
699
- DeprecationWarnings = DeprecationWarnings() # PYCHOK singleton
700
- _throwarning = DeprecationWarnings.throw
699
+ if not _FOR_DOCS: # PYCHOK force epydoc
700
+ DeprecationWarnings = DeprecationWarnings() # singleton
701
+ _throwarning = DeprecationWarnings.throw
702
+ # del _FOR_DOCS
701
703
 
702
704
  # **) MIT License
703
705
  #
pygeodesy/trf.py CHANGED
@@ -1,9 +1,7 @@
1
1
 
2
2
  # -*- coding: utf-8 -*-
3
3
 
4
- u'''I{Veness}' Terrestrial Reference Frames (TRF).
5
-
6
- Classes L{RefFrame}, registry L{RefFrames} and L{TRFError}.
4
+ u'''I{Veness}' Terrestrial Reference Frames (TRF), classes L{RefFrame}, registry L{RefFrames} and L{TRFError}.
7
5
 
8
6
  Transcoded from I{Chris Veness'} (C) 2006-2024 JavaScript originals U{latlon-ellipsoidal-referenceframe.js
9
7
  <https://GitHub.com/ChrisVeness/geodesy/blob/master/latlon-ellipsoidal-referenceframe.js>} and