Closed oysstu closed 3 years ago
No, the following example shows that np.arcsin delivers double precision both for small and large angles, but np.arcos solution gives less than double precision for most of the angles (even though the precision is ok for most applications) :
>>> import numpy as np
>>> theta = np.logspace(-50, 0)*np.pi/2
>>> sin_theta = np.sin(theta)
>>> t1 = np.arcsin(sin_theta)
>>> t2 = np.arcos(-sin_theta)-np.pi/2
>>> np.abs(t1-theta)/theta
array([0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00,
0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00,
0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00,
0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00,
0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00,
0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00,
0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00,
0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00,
0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00,
0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00,
0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00,
0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 1.8090627e-16,
0.0000000e+00, 0.0000000e+00])
>>> np.abs(t2-theta)/theta
array([3.17768732e-07, 8.41285987e-08, 2.99824097e-08, 2.51113553e-07,
3.65447084e-08, 6.71601921e-08, 1.13440618e-08, 6.73537798e-09,
2.06761534e-08, 3.76403350e-09, 2.41976409e-09, 9.60252863e-10,
1.34828226e-09, 3.70225909e-10, 4.83429429e-10, 1.75196678e-10,
8.52621110e-11, 6.57949754e-11, 1.75711340e-10, 4.99285763e-12,
8.42401296e-11, 4.23587289e-11, 3.14708133e-11, 1.77221187e-11,
4.08716375e-12, 8.06297736e-12, 3.40705458e-12, 4.44254594e-13,
1.95394667e-13, 1.00059067e-12, 7.88776657e-14, 4.48770241e-13,
1.34252409e-13, 1.45198665e-13, 1.68480928e-14, 1.21205710e-14,
4.80642950e-14, 2.70152645e-14, 1.37805543e-14, 1.01907463e-14,
5.30814909e-15, 2.65430892e-15, 8.29544787e-16, 1.62960687e-15,
1.85198952e-16, 3.47278700e-16, 4.34136709e-16, 1.80906270e-16,
2.26152806e-16, 0.00000000e+00])
Aha, I see. I assumed that the comment was related to footnote 2 in Gade (2010) regarding the numerical precision of the inverse trigonometric functions near the endpoints of their domains due to the steep slope.
I can confirm your findings on Linux, where presumably numpy uses the trigonometric functions of gcc/glibc. It looks like the asin and acos functions in glibc are implemented in terms of the atan machine instruction. The division by x in acos may be the cause for the numerical issues, but then again using long double does not help so perhaps not. asin = atan (x / sqrt(1 - x^2)) acos = atan (sqrt(1 - x^2) / x)
import numpy as np
theta = np.logspace(-50, 0, dtype=np.float64)*np.pi/2
cos_theta = np.cos(theta)
sin_theta = np.sin(theta)
t1 = np.arcsin(sin_theta)
t2 = np.arccos(-sin_theta) - np.pi/2
t3 = np.arctan2(sin_theta, cos_theta)
print('theta\n', theta)
print('t1\n', t1)
print('t2\n', t2)
print('t3\n', t3)
Output:
theta
[1.57079633e-50 1.64637226e-49 1.72558439e-48 1.80860766e-47
1.89562545e-46 1.98682993e-45 2.08242254e-44 2.18261442e-43
2.28762684e-42 2.39769174e-41 2.51305220e-40 2.63396302e-39
2.76069123e-38 2.89351674e-37 3.03273290e-36 3.17864719e-35
3.33158186e-34 3.49187471e-33 3.65987975e-32 3.83596803e-31
4.02052848e-30 4.21396870e-29 4.41671594e-28 4.62921799e-27
4.85194418e-26 5.08538642e-25 5.33006030e-24 5.58650620e-23
5.85529052e-22 6.13700690e-21 6.43227754e-20 6.74175457e-19
7.06612151e-18 7.40609477e-17 7.76242520e-16 8.13589980e-15
8.52734344e-14 8.93762066e-13 9.36763760e-12 9.81834400e-11
1.02907353e-09 1.07858548e-08 1.13047961e-07 1.18487053e-06
1.24187836e-05 1.30162902e-04 1.36425448e-03 1.42989303e-02
1.49868967e-01 1.57079633e+00]
t1
[1.57079633e-50 1.64637226e-49 1.72558439e-48 1.80860766e-47
1.89562545e-46 1.98682993e-45 2.08242254e-44 2.18261442e-43
2.28762684e-42 2.39769174e-41 2.51305220e-40 2.63396302e-39
2.76069123e-38 2.89351674e-37 3.03273290e-36 3.17864719e-35
3.33158186e-34 3.49187471e-33 3.65987975e-32 3.83596803e-31
4.02052848e-30 4.21396870e-29 4.41671594e-28 4.62921799e-27
4.85194418e-26 5.08538642e-25 5.33006030e-24 5.58650620e-23
5.85529052e-22 6.13700690e-21 6.43227754e-20 6.74175457e-19
7.06612151e-18 7.40609477e-17 7.76242520e-16 8.13589980e-15
8.52734344e-14 8.93762066e-13 9.36763760e-12 9.81834400e-11
1.02907353e-09 1.07858548e-08 1.13047961e-07 1.18487053e-06
1.24187836e-05 1.30162902e-04 1.36425448e-03 1.42989303e-02
1.49868967e-01 1.57079633e+00]
t2
[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 2.22044605e-16 8.88178420e-16 8.21565038e-15
8.52651283e-14 8.93729535e-13 9.36761779e-12 9.81834614e-11
1.02907349e-09 1.07858549e-08 1.13047961e-07 1.18487053e-06
1.24187836e-05 1.30162902e-04 1.36425448e-03 1.42989303e-02
1.49868967e-01 1.57079633e+00]
t3
[1.57079633e-50 1.64637226e-49 1.72558439e-48 1.80860766e-47
1.89562545e-46 1.98682993e-45 2.08242254e-44 2.18261442e-43
2.28762684e-42 2.39769174e-41 2.51305220e-40 2.63396302e-39
2.76069123e-38 2.89351674e-37 3.03273290e-36 3.17864719e-35
3.33158186e-34 3.49187471e-33 3.65987975e-32 3.83596803e-31
4.02052848e-30 4.21396870e-29 4.41671594e-28 4.62921799e-27
4.85194418e-26 5.08538642e-25 5.33006030e-24 5.58650620e-23
5.85529052e-22 6.13700690e-21 6.43227754e-20 6.74175457e-19
7.06612151e-18 7.40609477e-17 7.76242520e-16 8.13589980e-15
8.52734344e-14 8.93762066e-13 9.36763760e-12 9.81834400e-11
1.02907353e-09 1.07858548e-08 1.13047961e-07 1.18487053e-06
1.24187836e-05 1.30162902e-04 1.36425448e-03 1.42989303e-02
1.49868967e-01 1.57079633e+00]
Hi,
I was doing some quick experimentation with nvector, and found this calculation of the cross-track distance on the great circle. https://github.com/pbrod/nvector/blob/bf1cf5e1e210b74a57ea4bb2c277b388308bdba9/src/nvector/_core.py#L1140-L1143
The arccos function is inaccurate for small angles, as mentioned in the comment. When this function is called from cross_track_distance however, it is taken between the cross product of the n-vectors describing the path (c^E) and the position B. For small cross-track errors, shouldn't the expression with arccos be the most accurate (since arcsin is inaccurate at -pi/2 and pi/2)?