pygeodesy 24.4.18__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-24.4.18.dist-info → PyGeodesy-24.4.24.dist-info}/METADATA +2 -2
- {PyGeodesy-24.4.18.dist-info → PyGeodesy-24.4.24.dist-info}/RECORD +9 -9
- pygeodesy/__init__.py +1 -1
- pygeodesy/constants.py +1 -2
- pygeodesy/fmath.py +150 -104
- pygeodesy/fsums.py +104 -87
- pygeodesy/lazily.py +2 -2
- {PyGeodesy-24.4.18.dist-info → PyGeodesy-24.4.24.dist-info}/WHEEL +0 -0
- {PyGeodesy-24.4.18.dist-info → PyGeodesy-24.4.24.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: PyGeodesy
|
|
3
|
-
Version: 24.4.
|
|
3
|
+
Version: 24.4.24
|
|
4
4
|
Summary: Pure Python geodesy tools
|
|
5
5
|
Home-page: https://GitHub.com/mrJean1/PyGeodesy
|
|
6
6
|
Author: Jean M. Brouwers
|
|
@@ -158,7 +158,7 @@ and McCabe_ using Python 2.7.18 and with Flake8_ using Python 3.11.5, both in 64
|
|
|
158
158
|
|
|
159
159
|
For a summary of all *Karney*-based functionality in ``pygeodesy``, see module karney_.
|
|
160
160
|
|
|
161
|
-
*Last updated: April
|
|
161
|
+
*Last updated: April 24, 2024.*
|
|
162
162
|
|
|
163
163
|
License
|
|
164
164
|
=======
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
pygeodesy/LICENSE,sha256=YfgAiyxOwY6P9Kkb1_5XN81nueTLrpb3Ffkv3EuPgFU,1144
|
|
2
|
-
pygeodesy/__init__.py,sha256=
|
|
2
|
+
pygeodesy/__init__.py,sha256=td1SZErPJBK8oIAHrj4sVvK-n3PjnJbckJQjWhyNHf0,40824
|
|
3
3
|
pygeodesy/__main__.py,sha256=qMFG3caY8ZXWu6uGiemzyT4OqTFZnsFtlxcGCAgkVJw,4637
|
|
4
4
|
pygeodesy/albers.py,sha256=g2AVlpV8JO2AYFCthoIbRC2h1OJqjb9P3hpwF0C3TI8,30994
|
|
5
5
|
pygeodesy/azimuthal.py,sha256=tc4JxgLi-0jzU08m4Bvi-t-kzHXYPeGuzL3j_tyVFUA,50125
|
|
@@ -7,7 +7,7 @@ pygeodesy/basics.py,sha256=_BMYLzGKA6OIS3qv25HfHy7MIh0kAbmkzyScb59clUs,28160
|
|
|
7
7
|
pygeodesy/booleans.py,sha256=HZbwoL-S7Ww9d4C2D1BVqXfmcuqqVpEVSU9_S0uyUyo,74204
|
|
8
8
|
pygeodesy/cartesianBase.py,sha256=I3q29mRdBB3NCDmPoJsJ0QOFfLzkdMWc8X9zG4IwJyA,47264
|
|
9
9
|
pygeodesy/clipy.py,sha256=VU3ynQ1IZ0v5hJlicqD48oW0imRgiL5_ZzRPrIjpfPw,27683
|
|
10
|
-
pygeodesy/constants.py,sha256=
|
|
10
|
+
pygeodesy/constants.py,sha256=RxO8dMe_3AEfmZyKaRIy_44QnOTdEpzgYwimN0_w9Qs,19113
|
|
11
11
|
pygeodesy/css.py,sha256=sKXsahUiyruDcUk-tGjA6mxq-xzwBoBKxKo9_b2uBmY,25394
|
|
12
12
|
pygeodesy/datums.py,sha256=gJZPgV4bELZvZ8Sj2zE3MBysVtsLxqsN8zm0xjOKvpo,33851
|
|
13
13
|
pygeodesy/dms.py,sha256=op3MU-59CoJQRdybnu21aVM9wtocd_-XFNAZFqmozSo,44439
|
|
@@ -25,11 +25,11 @@ pygeodesy/elliptic.py,sha256=XRVpmpdm3hbztM4P-qhWKQizbgsXDUxWujgmOrIpgiQ,42428
|
|
|
25
25
|
pygeodesy/epsg.py,sha256=ldHoLWqJWR4FUiBVnDTtrI_e7TNjjtr9OkxDlri1g5E,8165
|
|
26
26
|
pygeodesy/errors.py,sha256=mUaacHJKcSCowlcbzamaBMDqjI2dqsTM5O4ozIITtAk,27233
|
|
27
27
|
pygeodesy/etm.py,sha256=joEhU2lw9ehRv101nRpZvXq8hOYAEzdcYFpif9_obfk,44585
|
|
28
|
-
pygeodesy/fmath.py,sha256=
|
|
28
|
+
pygeodesy/fmath.py,sha256=cRisVRkuarEwu4pKOCWmBa-98lV2PP9oJVkkODQLc2E,32480
|
|
29
29
|
pygeodesy/formy.py,sha256=Rces4Q5ecED0WVfuI9mQzeyHE54LDowYfI6faBHpyeA,74536
|
|
30
30
|
pygeodesy/frechet.py,sha256=qgee-ISBtT7Ov3rJkcd_t-WeXTbeNoMSQuMa0j3MyQc,33512
|
|
31
31
|
pygeodesy/fstats.py,sha256=r8O2aIknHuoHsW8gZUIY42zpHZy7syHvCB7uCVtPpkc,25559
|
|
32
|
-
pygeodesy/fsums.py,sha256=
|
|
32
|
+
pygeodesy/fsums.py,sha256=Am8CRdltomItdCpdBUDyc1xP53KmrCXXs9rBTa19hs4,73370
|
|
33
33
|
pygeodesy/gars.py,sha256=fCiWBJ4kOJxPfNOxadX-OzBGDXj7C9g02NuGHiZa_88,11342
|
|
34
34
|
pygeodesy/geodesicw.py,sha256=5yjJ2rLekSsjT7e-Km6v592ZcFlA41flQP_E42jU9Sw,26901
|
|
35
35
|
pygeodesy/geodsolve.py,sha256=3GLI2_4gglzTpZwKchNzAv-XhWFBzWRKjcWsjCC3dvI,21900
|
|
@@ -42,7 +42,7 @@ pygeodesy/iters.py,sha256=CfU365eE9F4oWZbBx0qTEvfodMhpa8rGOepLIv67xF8,20181
|
|
|
42
42
|
pygeodesy/karney.py,sha256=lYdsSHis8xQJVS1V0F3cphx6Dhgd77xTlMOdVR8MN8I,34994
|
|
43
43
|
pygeodesy/ktm.py,sha256=sCvbLvJItavlruilAyjeZ0sOZx2yJumzGe_UiIVbGi4,27315
|
|
44
44
|
pygeodesy/latlonBase.py,sha256=LimCMj91J3Q4D_rTu7VN7c63cLL_KzxXagFQfedobmc,77730
|
|
45
|
-
pygeodesy/lazily.py,sha256=
|
|
45
|
+
pygeodesy/lazily.py,sha256=YeOQQ2Tu0LTD-AMDABc0bemeLRKTteTEJXJDl3_7vZU,48645
|
|
46
46
|
pygeodesy/lcc.py,sha256=yNpmAdOwv3HNh2ZLopF5QtvDokeQYCmnxSc8UFUPHO4,25737
|
|
47
47
|
pygeodesy/ltp.py,sha256=8se8dYG7LG__Ru0FoK939DJBF9GCQGeJik_Un1Im8Xw,48609
|
|
48
48
|
pygeodesy/ltpTuples.py,sha256=iKzvDfv33HfmEevjNISUS4c9KXIkiISEkVlQopyKgfY,55769
|
|
@@ -109,7 +109,7 @@ pygeodesy/rhumb/aux_.py,sha256=W4HkgoHAQz_aWaysfsmOA5010nCGvBfUs2Q-bymnHYU,16660
|
|
|
109
109
|
pygeodesy/rhumb/bases.py,sha256=kzU_Dgt4FNPMgTg5rqbw-HiNpflDPKpmq9jhPbQmR4U,53851
|
|
110
110
|
pygeodesy/rhumb/ekx.py,sha256=lF3tZ-ZY9fPJV8y1kgHW-7EOZCyb3gJr-kR-jj5Fbf8,23871
|
|
111
111
|
pygeodesy/rhumb/solve.py,sha256=NZfwx7xv5UriQs7A0c7ZhoxxVUeAT15UwXK_jtwEXQw,27802
|
|
112
|
-
PyGeodesy-24.4.
|
|
113
|
-
PyGeodesy-24.4.
|
|
114
|
-
PyGeodesy-24.4.
|
|
115
|
-
PyGeodesy-24.4.
|
|
112
|
+
PyGeodesy-24.4.24.dist-info/METADATA,sha256=IGu3-2Wu7HfzR8MYGeOU_oWysKdkDfMkndw45lFqWvY,19366
|
|
113
|
+
PyGeodesy-24.4.24.dist-info/WHEEL,sha256=DZajD4pwLWue70CAfc7YaxT1wLUciNBvN_TTcvXpltE,110
|
|
114
|
+
PyGeodesy-24.4.24.dist-info/top_level.txt,sha256=cEQPatCXzKZqrivpULC5V5fuy9_V_bAwaP_gUGid7pQ,10
|
|
115
|
+
PyGeodesy-24.4.24.dist-info/RECORD,,
|
pygeodesy/__init__.py
CHANGED
pygeodesy/constants.py
CHANGED
|
@@ -23,7 +23,7 @@ except ImportError: # Python 2-
|
|
|
23
23
|
_inf, _nan = float(_INF_), float(_NAN_)
|
|
24
24
|
|
|
25
25
|
__all__ = _ALL_LAZY.constants
|
|
26
|
-
__version__ = '24.04.
|
|
26
|
+
__version__ = '24.04.23'
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
def _copysign_0_0(y):
|
|
@@ -247,7 +247,6 @@ _1_16th = _Float(_1_16th =_1_0 / _16_0) # PYCHOK in .ellipsoids, .karney
|
|
|
247
247
|
_1_64th = _Float(_1_64th =_1_0 / 64) # PYCHOK in .elliptic, pow(2.0, -6)
|
|
248
248
|
_1_3rd = _Float(_1_3rd =_1_0 / _3_0) # PYCHOK in .fmath
|
|
249
249
|
_1_6th = _Float(_1_6th =_1_0 / _6_0) # PYCHOK in .fmath
|
|
250
|
-
_2_3rd = _Float(_2_3rd =_2_0 / _3_0) # PYCHOK in .fmath
|
|
251
250
|
|
|
252
251
|
_K0_UTM = _Float(_K0_UTM = 0.9996) # PYCHOK in .etm, .ktm, .utm, UTM scale at central meridian
|
|
253
252
|
# sqrt(2) <https://WikiPedia.org/wiki/Square_root_of_2>
|
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,
|
|
12
|
-
_1_5,
|
|
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,
|
|
17
|
-
|
|
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,21 +22,14 @@ 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.
|
|
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
|
|
|
35
|
-
def _Fsum__init__(inst, raiser=MISSING, **name_RESIDUAL):
|
|
36
|
-
'''(INTERNAL) Init an C{Fsum} instance.
|
|
37
|
-
'''
|
|
38
|
-
Fsum.__init__(inst, **name_RESIDUAL) # PYCHOK self
|
|
39
|
-
inst._fset_ps(_0_0)
|
|
40
|
-
return {} if raiser is MISSING else dict(raiser=raiser)
|
|
41
|
-
|
|
42
|
-
|
|
43
33
|
class Fdot(Fsum):
|
|
44
34
|
'''Precision dot product.
|
|
45
35
|
'''
|
|
@@ -104,7 +94,7 @@ class Fhorner(Fsum):
|
|
|
104
94
|
|
|
105
95
|
|
|
106
96
|
class Fhypot(Fsum):
|
|
107
|
-
'''Precision summation and hypotenuse, default C{
|
|
97
|
+
'''Precision summation and hypotenuse, default C{root=2}.
|
|
108
98
|
'''
|
|
109
99
|
def __init__(self, *xs, **root_name_RESIDUAL_raiser):
|
|
110
100
|
'''New L{Fhypot} hypotenuse of (the I{root} of) several components.
|
|
@@ -189,7 +179,7 @@ class Froot(Fsum):
|
|
|
189
179
|
try:
|
|
190
180
|
raiser = _Fsum__init__(self, **name_RESIDUAL_raiser)
|
|
191
181
|
if xs:
|
|
192
|
-
self.
|
|
182
|
+
self.fadd(xs)
|
|
193
183
|
self._fset(self.root(root, **raiser))
|
|
194
184
|
except Exception as X:
|
|
195
185
|
raise self._ErrorXs(X, xs, root=root)
|
|
@@ -203,7 +193,7 @@ class Fcbrt(Froot):
|
|
|
203
193
|
|
|
204
194
|
@see: Class L{Froot} for further details.
|
|
205
195
|
'''
|
|
206
|
-
Froot.__init__(self,
|
|
196
|
+
Froot.__init__(self, 3, *xs, **name_RESIDUAL_raiser)
|
|
207
197
|
|
|
208
198
|
|
|
209
199
|
class Fsqrt(Froot):
|
|
@@ -214,15 +204,24 @@ class Fsqrt(Froot):
|
|
|
214
204
|
|
|
215
205
|
@see: Class L{Froot} for further details.
|
|
216
206
|
'''
|
|
217
|
-
Froot.__init__(self,
|
|
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)
|
|
218
216
|
|
|
219
217
|
|
|
220
218
|
def bqrt(x):
|
|
221
|
-
'''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})}.
|
|
222
221
|
|
|
223
|
-
@arg x: Value (C{scalar}).
|
|
222
|
+
@arg x: Value (C{scalar} or L{Fsum} instance).
|
|
224
223
|
|
|
225
|
-
@return: I{Quartic} root (C{float}).
|
|
224
|
+
@return: I{Quartic} root (C{float} or L{Fsum}).
|
|
226
225
|
|
|
227
226
|
@raise ValueError: Negative B{C{x}}.
|
|
228
227
|
|
|
@@ -232,70 +231,76 @@ def bqrt(x):
|
|
|
232
231
|
|
|
233
232
|
|
|
234
233
|
try:
|
|
235
|
-
from math import cbrt # Python 3.11+
|
|
236
|
-
|
|
237
|
-
def cbrt2(x):
|
|
238
|
-
'''Compute the cube root I{squared} M{x**(2/3)}.
|
|
239
|
-
'''
|
|
240
|
-
return cbrt(x)**2 # cbrt(-0.0*2) == -0.0
|
|
234
|
+
from math import cbrt as _cbrt # Python 3.11+
|
|
241
235
|
|
|
242
236
|
except ImportError: # Python 3.10-
|
|
243
237
|
|
|
244
|
-
def
|
|
245
|
-
'''Compute the cube root M{x**(1/3)}.
|
|
246
|
-
|
|
247
|
-
@arg x: Value (C{scalar}).
|
|
248
|
-
|
|
249
|
-
@return: Cubic root (C{float}).
|
|
250
|
-
|
|
251
|
-
@see: Functions L{cbrt2} and L{sqrt3}.
|
|
238
|
+
def _cbrt(x):
|
|
239
|
+
'''(INTERNAL) Compute the I{signed}, cube root M{x**(1/3)}.
|
|
252
240
|
'''
|
|
253
241
|
# <https://archive.lib.MSU.edu/crcmath/math/math/r/r021.htm>
|
|
254
242
|
# simpler and more accurate than Ken Turkowski's CubeRoot, see
|
|
255
243
|
# <https://People.FreeBSD.org/~lstewart/references/apple_tr_kt32_cuberoot.pdf>
|
|
256
|
-
return _copysign(pow(fabs(x), _1_3rd), x) #
|
|
244
|
+
return _copysign(pow(fabs(x), _1_3rd), x) # to avoid complex
|
|
257
245
|
|
|
258
|
-
def cbrt2(x): # PYCHOK attr
|
|
259
|
-
'''Compute the cube root I{squared} M{x**(2/3)}.
|
|
260
246
|
|
|
261
|
-
|
|
247
|
+
def cbrt(x):
|
|
248
|
+
'''Compute the cube root M{x**(1/3)}, preserving C{type(B{x})}.
|
|
262
249
|
|
|
263
|
-
|
|
250
|
+
@arg x: Value (C{scalar} or L{Fsum} instance).
|
|
264
251
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
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)
|
|
268
273
|
|
|
269
274
|
|
|
270
275
|
def euclid(x, y):
|
|
271
276
|
'''I{Appoximate} the norm M{sqrt(x**2 + y**2)} by
|
|
272
277
|
M{max(abs(x), abs(y)) + min(abs(x), abs(y)) * 0.4142...}.
|
|
273
278
|
|
|
274
|
-
@arg x: X component (C{scalar}).
|
|
275
|
-
@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).
|
|
276
281
|
|
|
277
|
-
@return: Appoximate norm (C{float}).
|
|
282
|
+
@return: Appoximate norm (C{float} or L{Fsum}).
|
|
278
283
|
|
|
279
284
|
@see: Function L{euclid_}.
|
|
280
285
|
'''
|
|
281
|
-
x, y =
|
|
286
|
+
x, y = abs(x), abs(y) # NOT fabs!
|
|
282
287
|
if x < y:
|
|
283
288
|
x, y = y, x
|
|
284
289
|
return x + y * _0_4142 # XXX * _0_5 before 20.10.02
|
|
285
290
|
|
|
286
291
|
|
|
287
292
|
def euclid_(*xs):
|
|
288
|
-
'''I{Appoximate} the norm M{sqrt(sum(x**2 for x in xs))}
|
|
289
|
-
|
|
293
|
+
'''I{Appoximate} the norm M{sqrt(sum(x**2 for x in xs))} by
|
|
294
|
+
cascaded L{euclid}.
|
|
290
295
|
|
|
291
|
-
@arg xs: X arguments, positional (C{scalar}s).
|
|
296
|
+
@arg xs: X arguments, positional (C{scalar}s or L{Fsum} instances).
|
|
292
297
|
|
|
293
|
-
@return: Appoximate norm (C{float}).
|
|
298
|
+
@return: Appoximate norm (C{float} or L{Fsum}).
|
|
294
299
|
|
|
295
300
|
@see: Function L{euclid}.
|
|
296
301
|
'''
|
|
297
302
|
e = _0_0
|
|
298
|
-
for x in sorted(map(
|
|
303
|
+
for x in sorted(map(abs, xs)): # NOT fabs, reverse=True!
|
|
299
304
|
# e = euclid(x, e)
|
|
300
305
|
if e < x:
|
|
301
306
|
e, x = x, e
|
|
@@ -388,8 +393,8 @@ def fatan2(y, x):
|
|
|
388
393
|
def favg(v1, v2, f=_0_5):
|
|
389
394
|
'''Return the average of two values.
|
|
390
395
|
|
|
391
|
-
@arg v1: One value (C{scalar}).
|
|
392
|
-
@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).
|
|
393
398
|
@kwarg f: Optional fraction (C{float}).
|
|
394
399
|
|
|
395
400
|
@return: M{v1 + f * (v2 - v1)} (C{float}).
|
|
@@ -606,6 +611,39 @@ except ImportError:
|
|
|
606
611
|
return freduce(_operator.mul, xs, start)
|
|
607
612
|
|
|
608
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
|
+
|
|
609
647
|
def frange(start, number, step=1):
|
|
610
648
|
'''Generate a range of C{float}s.
|
|
611
649
|
|
|
@@ -715,8 +753,8 @@ if _sys_version_info2 < (3, 8): # PYCHOK no cover
|
|
|
715
753
|
computed as M{hypot_(*((c1 - c2) for c1, c2 in zip(p1, p2)))},
|
|
716
754
|
provided I{p1} and I{p2} have the same, non-zero length I{n}.
|
|
717
755
|
'''
|
|
718
|
-
|
|
719
|
-
return (
|
|
756
|
+
_, R = _h_xs2(xs, True, hypot_)
|
|
757
|
+
return float(R)
|
|
720
758
|
|
|
721
759
|
elif _sys_version_info2 < (3, 10):
|
|
722
760
|
# In Python 3.8 and 3.9 C{math.hypot} is inaccurate, see
|
|
@@ -732,13 +770,8 @@ elif _sys_version_info2 < (3, 10):
|
|
|
732
770
|
|
|
733
771
|
@return: C{sqrt(B{x}**2 + B{y}**2)} (C{float}).
|
|
734
772
|
'''
|
|
735
|
-
if
|
|
736
|
-
|
|
737
|
-
elif y:
|
|
738
|
-
h = fabs(y)
|
|
739
|
-
else:
|
|
740
|
-
h = _0_0
|
|
741
|
-
return h
|
|
773
|
+
return (float(Fhypot(x, y, raiser=False)) if y else
|
|
774
|
+
fabs(x)) if x else fabs(y)
|
|
742
775
|
|
|
743
776
|
from math import hypot as hypot_ # PYCHOK in Python 3.8 and 3.9
|
|
744
777
|
else:
|
|
@@ -746,29 +779,32 @@ else:
|
|
|
746
779
|
hypot_ = hypot
|
|
747
780
|
|
|
748
781
|
|
|
749
|
-
def
|
|
782
|
+
def _h_xs2(xs, pot_, which):
|
|
750
783
|
'''(INTERNAL) Helper for L{hypot_} and L{hypot2_}.
|
|
751
784
|
'''
|
|
752
785
|
n, xs = len2(xs)
|
|
753
786
|
if n > 0:
|
|
754
|
-
h = float(max(map(
|
|
787
|
+
h = float(max(map(abs, xs))) # NOT fabs!
|
|
755
788
|
if h < EPS0:
|
|
756
|
-
|
|
789
|
+
R = _0_0
|
|
757
790
|
elif n > 1:
|
|
758
|
-
|
|
759
|
-
|
|
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)
|
|
760
797
|
else:
|
|
761
|
-
|
|
762
|
-
return h,
|
|
798
|
+
R = h if pot_ else (h**2)
|
|
799
|
+
return h, R
|
|
763
800
|
|
|
764
|
-
|
|
765
|
-
raise _ValueError(t, txt=_too_(_few_))
|
|
801
|
+
raise _ValueError(unstr(which, xs), txt=_too_(_few_))
|
|
766
802
|
|
|
767
803
|
|
|
768
804
|
def hypot1(x):
|
|
769
805
|
'''Compute the norm M{sqrt(1 + x**2)}.
|
|
770
806
|
|
|
771
|
-
@arg x: Argument (C{scalar}).
|
|
807
|
+
@arg x: Argument (C{scalar} or L{Fsum} instance).
|
|
772
808
|
|
|
773
809
|
@return: Norm (C{float}).
|
|
774
810
|
'''
|
|
@@ -778,12 +814,12 @@ def hypot1(x):
|
|
|
778
814
|
def hypot2(x, y):
|
|
779
815
|
'''Compute the I{squared} norm M{x**2 + y**2}.
|
|
780
816
|
|
|
781
|
-
@arg x: X argument (C{scalar}).
|
|
782
|
-
@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).
|
|
783
819
|
|
|
784
|
-
@return: C{B{x}**2 + B{y}**2} (C{float}).
|
|
820
|
+
@return: C{B{x}**2 + B{y}**2} (C{float} or L{Fsum}).
|
|
785
821
|
'''
|
|
786
|
-
if
|
|
822
|
+
if abs(x) < abs(y): # NOT fabs!
|
|
787
823
|
x, y = y, x
|
|
788
824
|
if x:
|
|
789
825
|
h2 = x**2
|
|
@@ -795,9 +831,10 @@ def hypot2(x, y):
|
|
|
795
831
|
|
|
796
832
|
|
|
797
833
|
def hypot2_(*xs):
|
|
798
|
-
'''Compute the I{squared} norm C{
|
|
834
|
+
'''Compute the I{squared} norm C{fsum(x**2 for x in B{xs})}.
|
|
799
835
|
|
|
800
|
-
@arg xs: X arguments (C{scalar}s),
|
|
836
|
+
@arg xs: X arguments (C{scalar}s or L{Fsum} instances),
|
|
837
|
+
all positional.
|
|
801
838
|
|
|
802
839
|
@return: Squared norm (C{float}).
|
|
803
840
|
|
|
@@ -807,8 +844,8 @@ def hypot2_(*xs):
|
|
|
807
844
|
|
|
808
845
|
@see: Function L{hypot_}.
|
|
809
846
|
'''
|
|
810
|
-
|
|
811
|
-
return (
|
|
847
|
+
_, R = _h_xs2(xs, False, hypot2_)
|
|
848
|
+
return float(R)
|
|
812
849
|
|
|
813
850
|
|
|
814
851
|
def _map_mul(a, b, where):
|
|
@@ -860,12 +897,13 @@ def norm_(*xs):
|
|
|
860
897
|
or zero norm.
|
|
861
898
|
'''
|
|
862
899
|
try:
|
|
900
|
+
i = x = h = None
|
|
863
901
|
h = hypot_(*xs)
|
|
864
902
|
_h = (_1_0 / h) if h else _0_0
|
|
865
903
|
for i, x in enumerate(xs):
|
|
866
904
|
yield x * _h
|
|
867
|
-
except Exception as
|
|
868
|
-
raise _xError(
|
|
905
|
+
except Exception as X:
|
|
906
|
+
raise _xError(X, Fmt.SQUARE(xs=i), x, h=h)
|
|
869
907
|
|
|
870
908
|
|
|
871
909
|
def _powers(x, n):
|
|
@@ -880,34 +918,40 @@ def _powers(x, n):
|
|
|
880
918
|
def _root(x, p, where):
|
|
881
919
|
'''(INTERNAL) Raise C{x} to power C{0 < p < 1}.
|
|
882
920
|
'''
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
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
|
|
887
929
|
|
|
888
930
|
|
|
889
931
|
def sqrt0(x, Error=None):
|
|
890
|
-
'''Return the square root iff C{B{x} >}
|
|
932
|
+
'''Return the square root C{sqrt(B{x})} iff C{B{x} > }L{EPS02},
|
|
933
|
+
preserving C{type(B{x})}.
|
|
891
934
|
|
|
892
|
-
@arg x: Value (C{scalar}).
|
|
935
|
+
@arg x: Value (C{scalar} or L{Fsum} instance).
|
|
893
936
|
@kwarg Error: Error to raise for negative B{C{x}}.
|
|
894
937
|
|
|
895
|
-
@return: Square root (C{float}) or C{0.0}.
|
|
938
|
+
@return: Square root (C{float} or L{Fsum}) or C{0.0}.
|
|
896
939
|
|
|
897
940
|
@note: Any C{B{x} < }L{EPS02} I{including} C{B{x} < 0}
|
|
898
941
|
returns C{0.0}.
|
|
899
942
|
'''
|
|
900
943
|
if Error and x < 0:
|
|
901
|
-
raise Error(
|
|
902
|
-
return
|
|
944
|
+
raise Error(unstr(sqrt0, x))
|
|
945
|
+
return _root(x, _0_5, sqrt0) if x > EPS02 else (_0_0 if x < EPS02 else EPS0)
|
|
903
946
|
|
|
904
947
|
|
|
905
948
|
def sqrt3(x):
|
|
906
|
-
'''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})}.
|
|
907
951
|
|
|
908
|
-
@arg x: Value (C{scalar}).
|
|
952
|
+
@arg x: Value (C{scalar} or L{Fsum} instance).
|
|
909
953
|
|
|
910
|
-
@return: Square root I{cubed} (C{float}).
|
|
954
|
+
@return: Square root I{cubed} (C{float} or L{Fsum}).
|
|
911
955
|
|
|
912
956
|
@raise ValueError: Negative B{C{x}}.
|
|
913
957
|
|
|
@@ -956,11 +1000,12 @@ def sqrt_a(h, b):
|
|
|
956
1000
|
|
|
957
1001
|
|
|
958
1002
|
def zcrt(x):
|
|
959
|
-
'''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})}.
|
|
960
1005
|
|
|
961
|
-
@arg x: Value (C{scalar}).
|
|
1006
|
+
@arg x: Value (C{scalar} or L{Fsum} instance).
|
|
962
1007
|
|
|
963
|
-
@return: I{Zenzi-cubic} root (C{float}).
|
|
1008
|
+
@return: I{Zenzi-cubic} root (C{float} or L{Fsum}).
|
|
964
1009
|
|
|
965
1010
|
@see: Functions L{bqrt} and L{zqrt}.
|
|
966
1011
|
|
|
@@ -970,11 +1015,12 @@ def zcrt(x):
|
|
|
970
1015
|
|
|
971
1016
|
|
|
972
1017
|
def zqrt(x):
|
|
973
|
-
'''Return the 8-th, I{zenzi-quartic} or I{squared-quartic} root,
|
|
1018
|
+
'''Return the 8-th, I{zenzi-quartic} or I{squared-quartic} root,
|
|
1019
|
+
M{x**(1 / 8)}, preserving C{type(B{x})}.
|
|
974
1020
|
|
|
975
|
-
@arg x: Value (C{scalar}).
|
|
1021
|
+
@arg x: Value (C{scalar} or L{Fsum} instance).
|
|
976
1022
|
|
|
977
|
-
@return: I{Zenzi-quartic} root (C{float}).
|
|
1023
|
+
@return: I{Zenzi-quartic} root (C{float} or L{Fsum}).
|
|
978
1024
|
|
|
979
1025
|
@see: Functions L{bqrt} and L{zcrt}.
|
|
980
1026
|
|
pygeodesy/fsums.py
CHANGED
|
@@ -29,8 +29,9 @@ from pygeodesy.basics import iscomplex, isint, isscalar, itemsorted, \
|
|
|
29
29
|
signOf, _signOf
|
|
30
30
|
from pygeodesy.constants import INT0, _isfinite, NEG0, _pos_self, \
|
|
31
31
|
_0_0, _1_0, _N_1_0, Float, Int
|
|
32
|
-
from pygeodesy.errors import _OverflowError, _TypeError,
|
|
33
|
-
_xError2, _xkwds_get,
|
|
32
|
+
from pygeodesy.errors import _AssertionError, _OverflowError, _TypeError, \
|
|
33
|
+
_ValueError, _xError, _xError2, _xkwds_get, \
|
|
34
|
+
_ZeroDivisionError
|
|
34
35
|
from pygeodesy.interns import NN, _arg_, _COMMASPACE_, _DASH_, _DOT_, _EQUAL_, \
|
|
35
36
|
_exceeds_, _from_, _iadd_op_, _LANGLE_, _negative_, \
|
|
36
37
|
_NOTEQUAL_, _not_finite_, _PERCENT_, _PLUS_, _R_, \
|
|
@@ -45,7 +46,7 @@ from pygeodesy.props import _allPropertiesOf_n, deprecated_property_RO, \
|
|
|
45
46
|
from math import ceil as _ceil, fabs, floor as _floor # PYCHOK used! .ltp
|
|
46
47
|
|
|
47
48
|
__all__ = _ALL_LAZY.fsums
|
|
48
|
-
__version__ = '24.04.
|
|
49
|
+
__version__ = '24.04.24'
|
|
49
50
|
|
|
50
51
|
_add_op_ = _PLUS_ # in .auxilats.auxAngle
|
|
51
52
|
_eq_op_ = _EQUAL_ * 2 # _DEQUAL_
|
|
@@ -145,6 +146,12 @@ def _2halfeven(s, r, p):
|
|
|
145
146
|
return s
|
|
146
147
|
|
|
147
148
|
|
|
149
|
+
def _1_over(x, op=_truediv_op_, **raiser):
|
|
150
|
+
'''(INTERNAL) Return C{Fsum(1) /= B{x}}.
|
|
151
|
+
'''
|
|
152
|
+
return _Psum_(_1_0)._ftruediv(x, op, **raiser)
|
|
153
|
+
|
|
154
|
+
|
|
148
155
|
def _1primed(xs): # in .fmath
|
|
149
156
|
'''(INTERNAL) 1-Primed summation of iterable C{xs}
|
|
150
157
|
items, all I{known} to be C{finite float}.
|
|
@@ -156,9 +163,11 @@ def _1primed(xs): # in .fmath
|
|
|
156
163
|
|
|
157
164
|
|
|
158
165
|
def _2ps(s, r):
|
|
159
|
-
'''(INTERNAL) Return
|
|
166
|
+
'''(INTERNAL) Return an C{s} and C{r} pair, I{ps-ordered}.
|
|
160
167
|
'''
|
|
161
|
-
|
|
168
|
+
if fabs(s) < fabs(r):
|
|
169
|
+
s, r = r, s
|
|
170
|
+
return (r, s) if r else (s,) # PYCHOK types
|
|
162
171
|
|
|
163
172
|
|
|
164
173
|
def _psum(ps): # PYCHOK used!
|
|
@@ -192,13 +201,10 @@ def _Psum(ps, **name):
|
|
|
192
201
|
return F
|
|
193
202
|
|
|
194
203
|
|
|
195
|
-
def
|
|
196
|
-
'''(INTERNAL) Return an C{Fsum} from
|
|
204
|
+
def _Psum_(*ps, **name):
|
|
205
|
+
'''(INTERNAL) Return an C{Fsum} from 1 or 2 known scalar(s) C{ps}.
|
|
197
206
|
'''
|
|
198
|
-
|
|
199
|
-
F._ps[:] = p,
|
|
200
|
-
F._n = 1 # len(F._ps)
|
|
201
|
-
return F
|
|
207
|
+
return _Psum(ps, **name)
|
|
202
208
|
|
|
203
209
|
|
|
204
210
|
def _2scalar(other, _raiser=None, **mod):
|
|
@@ -267,9 +273,9 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
267
273
|
@note: Handling of exceptions and C{inf}, C{INF}, C{nan} and C{NAN} differs from
|
|
268
274
|
Python's C{math.fsum}.
|
|
269
275
|
|
|
270
|
-
@see: U{Hettinger<https://GitHub.com/ActiveState/code/
|
|
271
|
-
393090_Binary_floating_point_summatiaccurate_full/recipe-393090.py>},
|
|
272
|
-
<https://WikiPedia.org/wiki/Kahan_summation_algorithm>}, U{Klein
|
|
276
|
+
@see: U{Hettinger<https://GitHub.com/ActiveState/code/tree/master/recipes/Python/
|
|
277
|
+
393090_Binary_floating_point_summatiaccurate_full/recipe-393090.py>},
|
|
278
|
+
U{Kahan<https://WikiPedia.org/wiki/Kahan_summation_algorithm>}, U{Klein
|
|
273
279
|
<https://Link.Springer.com/article/10.1007/s00607-005-0139-x>}, Python 2.6+
|
|
274
280
|
file I{Modules/mathmodule.c} and the issue log U{Full precision summation
|
|
275
281
|
<https://Bugs.Python.org/issue2819>}.
|
|
@@ -336,8 +342,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
336
342
|
'''
|
|
337
343
|
return self.ceil
|
|
338
344
|
|
|
339
|
-
def __cmp__(self, other): #
|
|
340
|
-
'''Compare this with an other instance or C{scalar}
|
|
345
|
+
def __cmp__(self, other): # PYCHOK no cover
|
|
346
|
+
'''Compare this with an other instance or C{scalar}, Python 2-.
|
|
341
347
|
|
|
342
348
|
@return: -1, 0 or +1 (C{int}).
|
|
343
349
|
|
|
@@ -686,8 +692,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
686
692
|
@arg ndigits: Optional number of digits (C{int}).
|
|
687
693
|
'''
|
|
688
694
|
# <https://docs.Python.org/3.12/reference/datamodel.html?#object.__round__>
|
|
689
|
-
return
|
|
690
|
-
|
|
695
|
+
return _Psum_(round(float(self), *ndigits), # can be C{int}
|
|
696
|
+
name=self.__round__.__name__)
|
|
691
697
|
|
|
692
698
|
def __rpow__(self, other, *mod):
|
|
693
699
|
'''Return C{B{other}**B{self}} as an L{Fsum}.
|
|
@@ -771,6 +777,13 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
771
777
|
d = 1
|
|
772
778
|
return n, d
|
|
773
779
|
|
|
780
|
+
@property_RO
|
|
781
|
+
def as_iscalar(self):
|
|
782
|
+
'''Get this instance I{as-is} (L{Fsum}) or C{scalar} iff scalar.
|
|
783
|
+
'''
|
|
784
|
+
s, r = self._fprs2
|
|
785
|
+
return self if r else s
|
|
786
|
+
|
|
774
787
|
@property_RO
|
|
775
788
|
def ceil(self):
|
|
776
789
|
'''Get this instance' C{ceil} value (C{int} in Python 3+,
|
|
@@ -854,7 +867,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
854
867
|
def _Error(self, op, other, Error, **txt_cause):
|
|
855
868
|
'''(INTERNAL) Format an B{C{Error}} for C{{self} B{op} B{other}}.
|
|
856
869
|
'''
|
|
857
|
-
return Error(_SPACE_(self.
|
|
870
|
+
return Error(_SPACE_(self.as_iscalar, op, other), **txt_cause)
|
|
858
871
|
|
|
859
872
|
def _ErrorX(self, X, op, other, *mod):
|
|
860
873
|
'''(INTERNAL) Format the caught exception C{X}.
|
|
@@ -875,9 +888,9 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
875
888
|
'''(INTERNAL) Accumulate more C{scalars} or L{Fsum}s.
|
|
876
889
|
'''
|
|
877
890
|
if xs:
|
|
878
|
-
|
|
879
|
-
ps
|
|
880
|
-
ps[:] =
|
|
891
|
+
_xs = _2floats(xs, **origin_X_x) # PYCHOK yield
|
|
892
|
+
ps = self._ps
|
|
893
|
+
ps[:] = self._ps_acc(list(ps), _xs, up=up)
|
|
881
894
|
return self
|
|
882
895
|
|
|
883
896
|
def _facc_1(self, xs, **up):
|
|
@@ -907,7 +920,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
907
920
|
r = 0
|
|
908
921
|
if isinstance(p, Fsum):
|
|
909
922
|
s, r = p._fprs2
|
|
910
|
-
if r:
|
|
923
|
+
if r == 0:
|
|
911
924
|
return _Pow4(s)
|
|
912
925
|
m = Fsum._pow
|
|
913
926
|
elif isint(p, both=True) and int(p) >= 0:
|
|
@@ -922,7 +935,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
922
935
|
if p: # and xs:
|
|
923
936
|
_pow = Fsum._pow_2_3
|
|
924
937
|
_Fs = Fsum
|
|
925
|
-
_Ps =
|
|
938
|
+
_Ps = _Psum_ # ()._fset_ps_
|
|
926
939
|
op = which.__name__
|
|
927
940
|
|
|
928
941
|
def _X(X):
|
|
@@ -1052,24 +1065,28 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1052
1065
|
raise ValueError(_not_finite_) if op is None else \
|
|
1053
1066
|
self._ValueError(op, other, txt=_not_finite_)
|
|
1054
1067
|
|
|
1055
|
-
def fint(self, raiser=True, **
|
|
1068
|
+
def fint(self, raiser=True, name=NN, **RESIDUAL):
|
|
1056
1069
|
'''Return this instance' current running sum as C{integer}.
|
|
1057
1070
|
|
|
1058
1071
|
@kwarg raiser: Use C{B{raiser}=False} to ignore L{ResidualError}s
|
|
1059
1072
|
(C{bool}), see also method L{RESIDUAL}.
|
|
1060
1073
|
@kwarg name: Optional name (C{str}), overriding C{"fint"}.
|
|
1074
|
+
@kwarg RESIDUAL: Optional threshold, overriding the current
|
|
1075
|
+
L{RESIDUAL<Fsum.RESIDUAL>} (C{scalar}).
|
|
1061
1076
|
|
|
1062
|
-
@return: The C{integer} (L{Fsum})
|
|
1077
|
+
@return: The C{integer} sum (L{Fsum}) if this instance
|
|
1078
|
+
C{is_integer} and the residual is zero or
|
|
1079
|
+
insignificant or if C{B{raiser}=False}.
|
|
1063
1080
|
|
|
1064
1081
|
@raise ResidualError: Non-zero I{integer} residual.
|
|
1065
1082
|
|
|
1066
1083
|
@see: Methods L{Fsum.int_float} and L{Fsum.is_integer}.
|
|
1067
1084
|
'''
|
|
1068
1085
|
i, r = self._fint2
|
|
1069
|
-
if r and raiser:
|
|
1086
|
+
if r and raiser and self._raiser2sum(r, i, **RESIDUAL):
|
|
1070
1087
|
t = _stresidual(_integer_, r)
|
|
1071
1088
|
raise ResidualError(_integer_, i, txt=t)
|
|
1072
|
-
f = self._copy_2(self.fint,
|
|
1089
|
+
f = self._copy_2(self.fint, name=name)
|
|
1073
1090
|
return f._fset(i)
|
|
1074
1091
|
|
|
1075
1092
|
def fint2(self, **name):
|
|
@@ -1165,7 +1182,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1165
1182
|
i, _ = self._fint2 # assert _ == 0
|
|
1166
1183
|
x = _2scalar(other) # C{int}, C{float} or other
|
|
1167
1184
|
f = self._pow_2_3(i, x, other, op, **raiser) if isscalar(x) else \
|
|
1168
|
-
|
|
1185
|
+
_Psum_(i)._pow( x, other, op, **raiser) # x is Fsum
|
|
1169
1186
|
else: # mod[0] is None, power(self, other)
|
|
1170
1187
|
f = self._pow(other, other, op, **raiser)
|
|
1171
1188
|
else: # pow(self, other)
|
|
@@ -1250,7 +1267,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1250
1267
|
# Property's _fset zaps the value just set by the @setter
|
|
1251
1268
|
self.__dict__.update(_fint2=t, _fprs=s, _fprs2=Fsum2Tuple(s, INT0))
|
|
1252
1269
|
else: # PYCHOK no cover
|
|
1253
|
-
raise self.
|
|
1270
|
+
raise self._Error(_fset_op_, other, _AssertionError)
|
|
1254
1271
|
return self
|
|
1255
1272
|
|
|
1256
1273
|
def _fset_ps(self, other, n=0): # in .fmath
|
|
@@ -1264,12 +1281,12 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1264
1281
|
self._n = n or 1
|
|
1265
1282
|
return self
|
|
1266
1283
|
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1284
|
+
# def _fset_ps_(self, *xs):
|
|
1285
|
+
# '''(INTERNAL) Set partials to all known scalar C{xs}.
|
|
1286
|
+
# '''
|
|
1287
|
+
# self._ps[:] = xs
|
|
1288
|
+
# self.n = len(xs)
|
|
1289
|
+
# return self
|
|
1273
1290
|
|
|
1274
1291
|
def fsub(self, xs=()):
|
|
1275
1292
|
'''Subtract an iterable of C{scalar} or L{Fsum} instances from
|
|
@@ -1436,24 +1453,26 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1436
1453
|
'''
|
|
1437
1454
|
return _0_0
|
|
1438
1455
|
|
|
1439
|
-
def int_float(self, raiser=False):
|
|
1456
|
+
def int_float(self, raiser=False, **RESIDUAL):
|
|
1440
1457
|
'''Return this instance' current running sum as C{int} or C{float}.
|
|
1441
1458
|
|
|
1442
1459
|
@kwarg raiser: If C{True} throw a L{ResidualError} if the
|
|
1443
|
-
residual
|
|
1460
|
+
residual exceeds the C{RESIDUAL} (C{bool}).
|
|
1461
|
+
@kwarg RESIDUAL: Optional threshold, overriding the current
|
|
1462
|
+
L{RESIDUAL<Fsum.RESIDUAL>} (C{scalar}).
|
|
1444
1463
|
|
|
1445
1464
|
@return: This C{integer} sum if this instance C{is_integer},
|
|
1446
|
-
otherwise return the C{float} sum if the residual
|
|
1447
|
-
|
|
1465
|
+
otherwise return the C{float} sum if the residual is
|
|
1466
|
+
zero or insignificant or if C{B{raiser}=False}.
|
|
1448
1467
|
|
|
1449
1468
|
@raise ResidualError: Non-zero residual and C{B{raiser}=True}.
|
|
1450
1469
|
|
|
1451
|
-
@see: Methods L{Fsum.fint} and L{Fsum.fint2}.
|
|
1470
|
+
@see: Methods L{Fsum.fint} and L{Fsum.fint2} and property L{Fsum.as_iscalar}.
|
|
1452
1471
|
'''
|
|
1453
1472
|
s, r = self._fint2
|
|
1454
1473
|
if r:
|
|
1455
1474
|
s, r = self._fprs2
|
|
1456
|
-
if r and raiser: # PYCHOK no cover
|
|
1475
|
+
if r and raiser and self._raiser2sum(r, s, **RESIDUAL): # PYCHOK no cover
|
|
1457
1476
|
t = _stresidual(_non_zero_, r)
|
|
1458
1477
|
raise ResidualError(int_float=s, txt=t)
|
|
1459
1478
|
s = float(s) # redundant
|
|
@@ -1467,7 +1486,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1467
1486
|
def is_integer(self):
|
|
1468
1487
|
'''Is this instance' running sum C{integer}? (C{bool}).
|
|
1469
1488
|
|
|
1470
|
-
@see: Methods L{Fsum.fint} and L{Fsum.
|
|
1489
|
+
@see: Methods L{Fsum.fint}, L{Fsum.fint2} and L{Fsum.is_scalar}.
|
|
1471
1490
|
'''
|
|
1472
1491
|
_, r = self._fint2
|
|
1473
1492
|
return False if r else True
|
|
@@ -1486,12 +1505,20 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1486
1505
|
f = Fsum._math_fsum
|
|
1487
1506
|
return 2 if _psum is f else bool(f)
|
|
1488
1507
|
|
|
1508
|
+
def is_scalar(self):
|
|
1509
|
+
'''Is this instance' running sum C{scalar}? (C{bool}).
|
|
1510
|
+
|
|
1511
|
+
@see: Method L{Fsum.is_integer} and property L{Fsum.as_iscalar}.
|
|
1512
|
+
'''
|
|
1513
|
+
s, r = t = self._fprs2
|
|
1514
|
+
return False if r and _2sum(s, r) != t else True
|
|
1515
|
+
|
|
1489
1516
|
def _mul_Fsum(self, other, op=_mul_op_): # in .fmath.Fhorner
|
|
1490
1517
|
'''(INTERNAL) Return C{B{self} * Fsum B{other}} as L{Fsum} or C{0}.
|
|
1491
1518
|
'''
|
|
1492
1519
|
# assert isinstance(other, Fsum)
|
|
1493
1520
|
if self._ps and other._ps:
|
|
1494
|
-
f = self._ps_mul(op, *other._ps) # NO .
|
|
1521
|
+
f = self._ps_mul(op, *other._ps) # NO .as_iscalar
|
|
1495
1522
|
else:
|
|
1496
1523
|
f = _0_0
|
|
1497
1524
|
return f
|
|
@@ -1503,7 +1530,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1503
1530
|
if self._ps and self._finite(factor, op):
|
|
1504
1531
|
f = self if factor == _1_0 else (
|
|
1505
1532
|
self._neg if factor == _N_1_0 else
|
|
1506
|
-
self._ps_mul(op, factor).
|
|
1533
|
+
self._ps_mul(op, factor).as_iscalar)
|
|
1507
1534
|
else:
|
|
1508
1535
|
f = _0_0
|
|
1509
1536
|
return f
|
|
@@ -1594,7 +1621,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1594
1621
|
_mul_Fsum = Fsum._mul_Fsum
|
|
1595
1622
|
if x > 4:
|
|
1596
1623
|
p = self
|
|
1597
|
-
f = self if (x & 1) else
|
|
1624
|
+
f = self if (x & 1) else _Psum_(_1_0)
|
|
1598
1625
|
m = x >> 1 # // 2
|
|
1599
1626
|
while m:
|
|
1600
1627
|
p = _mul_Fsum(p, p, op) # p **= 2
|
|
@@ -1605,7 +1632,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1605
1632
|
f = _mul_Fsum(self, self, op)
|
|
1606
1633
|
if x > 2: # self**3 or 4
|
|
1607
1634
|
p = self if x < 4 else f
|
|
1608
|
-
f = _mul_Fsum(f, p, op).
|
|
1635
|
+
f = _mul_Fsum(f, p, op).as_iscalar
|
|
1609
1636
|
else: # self**1 or self**0 == 1 or _1_0
|
|
1610
1637
|
f = self._pow_0_1(x, other)
|
|
1611
1638
|
elif ps: # self._ps[0]**x
|
|
@@ -1630,19 +1657,23 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1630
1657
|
# assert x < 0 # < -1
|
|
1631
1658
|
s, r = f._fprs2 if isinstance(f, Fsum) else (f, 0)
|
|
1632
1659
|
if r:
|
|
1633
|
-
return
|
|
1660
|
+
return _1_over(f, op, **raiser) # PYCHOK 2 args
|
|
1634
1661
|
# use **= -1 for the CPython float_pow
|
|
1635
1662
|
# error if s is zero, and not s = 1 / s
|
|
1636
1663
|
x = -1
|
|
1637
1664
|
elif x < 0: # == -1: self**(-1) == 1 / self
|
|
1638
1665
|
if r:
|
|
1639
|
-
return
|
|
1666
|
+
return _1_over(self, op, **raiser) # PYCHOK 2 args
|
|
1640
1667
|
else: # self**1 or self**0
|
|
1641
1668
|
return self._pow_0_1(x, other) # self, 1 or 1.0
|
|
1642
|
-
elif r
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1669
|
+
elif r: # non-zero residual**fractional
|
|
1670
|
+
if s:
|
|
1671
|
+
n, d = self.as_integer_ratio()
|
|
1672
|
+
if abs(n) > abs(d):
|
|
1673
|
+
n, d, x = d, n, (-x)
|
|
1674
|
+
s = n / d
|
|
1675
|
+
else:
|
|
1676
|
+
s = r
|
|
1646
1677
|
# assert isscalar(s) and isscalar(x)
|
|
1647
1678
|
return self._pow_2_3(s, x, other, op, **raiser)
|
|
1648
1679
|
|
|
@@ -1701,11 +1732,22 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1701
1732
|
yield -p
|
|
1702
1733
|
yield _N_1_0
|
|
1703
1734
|
|
|
1704
|
-
def _raiser(self, r, s, raiser=True):
|
|
1735
|
+
def _raiser(self, r, s, raiser=True, **RESIDUAL):
|
|
1705
1736
|
'''(INTERNAL) Does ratio C{r / s} exceed the RESIDUAL threshold?
|
|
1706
1737
|
'''
|
|
1707
|
-
self._ratio =
|
|
1708
|
-
|
|
1738
|
+
self._ratio = r = (r / s) if s else s # == 0.
|
|
1739
|
+
if r and raiser:
|
|
1740
|
+
R = self._RESIDUAL
|
|
1741
|
+
if RESIDUAL:
|
|
1742
|
+
R = _xkwds_get(RESIDUAL, RESIDUAL=R)
|
|
1743
|
+
return fabs(r) > R
|
|
1744
|
+
return False
|
|
1745
|
+
|
|
1746
|
+
def _raiser2sum(self, r, s, **raiser_RESIDUAL):
|
|
1747
|
+
'''(INTERNAL) Does ratio C{r / s} exceed the RESIDUAL threshold
|
|
1748
|
+
I{and} is the residual B{C{r}} significant vs sum B{C{s}}?
|
|
1749
|
+
'''
|
|
1750
|
+
return self._raiser(r, s, **raiser_RESIDUAL) and _2sum(s, r) != (s, r)
|
|
1709
1751
|
|
|
1710
1752
|
@property_RO
|
|
1711
1753
|
def real(self):
|
|
@@ -1739,7 +1781,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1739
1781
|
C{PYGEODESY_FSUM_RESIDUAL} or if omitted, keep the
|
|
1740
1782
|
current setting.
|
|
1741
1783
|
|
|
1742
|
-
@return: The previous C{RESIDUAL} setting (C{float}), default C{0.}.
|
|
1784
|
+
@return: The previous C{RESIDUAL} setting (C{float}), default C{0.0}.
|
|
1743
1785
|
|
|
1744
1786
|
@raise ValueError: Negative B{C{threshold}}.
|
|
1745
1787
|
|
|
@@ -1777,18 +1819,9 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1777
1819
|
|
|
1778
1820
|
@see: Method L{Fsum.pow}.
|
|
1779
1821
|
'''
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
else:
|
|
1784
|
-
try:
|
|
1785
|
-
x = _1_0 / _2float(root=root)
|
|
1786
|
-
except Exception as X:
|
|
1787
|
-
E, t = _xError2(X)
|
|
1788
|
-
n = _SPACE_(_1_0, _truediv_op_, _root_)
|
|
1789
|
-
raise E(n, root, txt=t, cause=X)
|
|
1790
|
-
f = self._copy_2(self.root)
|
|
1791
|
-
return f._fpow(x, _root_, **raiser) # == pow(f, x)
|
|
1822
|
+
x = _1_over(root, **raiser)
|
|
1823
|
+
f = self._copy_2(self.root)
|
|
1824
|
+
return f._fpow(x, f.name, **raiser) # == pow(f, x)
|
|
1792
1825
|
|
|
1793
1826
|
def _scalar(self, other, op, **txt):
|
|
1794
1827
|
'''(INTERNAL) Return scalar C{other}.
|
|
@@ -1797,13 +1830,6 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase
|
|
|
1797
1830
|
return other
|
|
1798
1831
|
raise self._TypeError(op, other, **txt) # _invalid_
|
|
1799
1832
|
|
|
1800
|
-
@property_RO
|
|
1801
|
-
def _2scalar(self):
|
|
1802
|
-
'''(INTERNAL) Get this instance as C{scalar} or C{as-is}.
|
|
1803
|
-
'''
|
|
1804
|
-
s, r = self._fprs2
|
|
1805
|
-
return self if r else s
|
|
1806
|
-
|
|
1807
1833
|
def signOf(self, res=True):
|
|
1808
1834
|
'''Determine the sign of this instance.
|
|
1809
1835
|
|
|
@@ -2049,23 +2075,14 @@ if __name__ == '__main__':
|
|
|
2049
2075
|
|
|
2050
2076
|
def _test(n):
|
|
2051
2077
|
# copied from Hettinger, see L{Fsum} reference
|
|
2052
|
-
from pygeodesy import printf
|
|
2053
|
-
from random import gauss, random, shuffle
|
|
2078
|
+
from pygeodesy import frandoms, printf
|
|
2054
2079
|
|
|
2055
2080
|
printf(_fsum.__name__, end=_COMMASPACE_)
|
|
2056
2081
|
printf(_psum.__name__, end=_COMMASPACE_)
|
|
2057
2082
|
|
|
2058
2083
|
F = Fsum()
|
|
2059
2084
|
if F.is_math_fsum():
|
|
2060
|
-
|
|
2061
|
-
for _ in range(n):
|
|
2062
|
-
t = list(c)
|
|
2063
|
-
s = 0
|
|
2064
|
-
for _ in range(n * 8):
|
|
2065
|
-
v = gauss(0, random())**7 - s
|
|
2066
|
-
t.append(v)
|
|
2067
|
-
s += v
|
|
2068
|
-
shuffle(t)
|
|
2085
|
+
for t in frandoms(n, seeded=True):
|
|
2069
2086
|
assert float(F.fset_(*t)) == _fsum(t)
|
|
2070
2087
|
printf(_DOT_, end=NN)
|
|
2071
2088
|
printf(NN)
|
pygeodesy/lazily.py
CHANGED
|
@@ -260,7 +260,7 @@ _ALL_LAZY = _NamedEnum_RO(_name='_ALL_LAZY',
|
|
|
260
260
|
'bqrt', 'cbrt', 'cbrt2', 'euclid', 'euclid_',
|
|
261
261
|
'facos1', 'fasin1', 'fatan', 'fatan1', 'fatan2', 'favg',
|
|
262
262
|
'fdot', 'fdot3', 'fmean', 'fmean_', 'fhorner', 'fidw', 'fpolynomial',
|
|
263
|
-
'fpowers', 'fprod', 'frange', 'freduce', 'fremainder',
|
|
263
|
+
'fpowers', 'fprod', 'frandoms', 'frange', 'freduce', 'fremainder',
|
|
264
264
|
'hypot', 'hypot_', 'hypot1', 'hypot2', 'hypot2_',
|
|
265
265
|
'norm2', 'norm_', 'sqrt0', 'sqrt3', 'sqrt_a', 'zcrt', 'zqrt'),
|
|
266
266
|
formy=_i('Radical2Tuple',
|
|
@@ -504,7 +504,7 @@ class _ALL_MODS(object):
|
|
|
504
504
|
_ALL_MODS = _ALL_MODS() # PYCHOK singleton
|
|
505
505
|
|
|
506
506
|
__all__ = _ALL_LAZY.lazily
|
|
507
|
-
__version__ = '24.04.
|
|
507
|
+
__version__ = '24.04.22'
|
|
508
508
|
|
|
509
509
|
|
|
510
510
|
def _ALL_OTHER(*objs):
|
|
File without changes
|
|
File without changes
|