@@ -26,14 +26,84 @@ import (
26
26
// to be calculated and compared. Otherwise it is simpler to use Angle.
27
27
//
28
28
// ChordAngle loses some accuracy as the angle approaches π radians.
29
- // Specifically, the representation of (π - x) radians has an error of about
30
- // (1e-15 / x), with a maximum error of about 2e-8 radians (about 13cm on the
31
- // Earth's surface). For comparison, for angles up to π/2 radians (10000km)
32
- // the worst-case representation error is about 2e-16 radians (1 nanonmeter),
33
- // which is about the same as Angle.
34
- //
35
- // ChordAngles are represented by the squared chord length, which can
36
- // range from 0 to 4. Positive infinity represents an infinite squared length.
29
+ // There are several different ways to measure this error, including the
30
+ // representational error (i.e., how accurately ChordAngle can represent
31
+ // angles near π radians), the conversion error (i.e., how much precision is
32
+ // lost when an Angle is converted to an ChordAngle), and the measurement
33
+ // error (i.e., how accurate the ChordAngle(a, b) constructor is when the
34
+ // points A and B are separated by angles close to π radians). All of these
35
+ // errors differ by a small constant factor.
36
+ //
37
+ // For the measurement error (which is the largest of these errors and also
38
+ // the most important in practice), let the angle between A and B be (π - x)
39
+ // radians, i.e. A and B are within "x" radians of being antipodal. The
40
+ // corresponding chord length is
41
+ //
42
+ // r = 2 * sin((π - x) / 2) = 2 * cos(x / 2)
43
+ //
44
+ // For values of x not close to π the relative error in the squared chord
45
+ // length is at most 4.5 * dblEpsilon (see MaxPointError below).
46
+ // The relative error in "r" is thus at most 2.25 * dblEpsilon ~= 5e-16. To
47
+ // convert this error into an equivalent angle, we have
48
+ //
49
+ // |dr / dx| = sin(x / 2)
50
+ //
51
+ // and therefore
52
+ //
53
+ // |dx| = dr / sin(x / 2)
54
+ // = 5e-16 * (2 * cos(x / 2)) / sin(x / 2)
55
+ // = 1e-15 / tan(x / 2)
56
+ //
57
+ // The maximum error is attained when
58
+ //
59
+ // x = |dx|
60
+ // = 1e-15 / tan(x / 2)
61
+ // ~= 1e-15 / (x / 2)
62
+ // ~= sqrt(2e-15)
63
+ //
64
+ // In summary, the measurement error for an angle (π - x) is at most
65
+ //
66
+ // dx = min(1e-15 / tan(x / 2), sqrt(2e-15))
67
+ // (~= min(2e-15 / x, sqrt(2e-15)) when x is small)
68
+ //
69
+ // On the Earth's surface (assuming a radius of 6371km), this corresponds to
70
+ // the following worst-case measurement errors:
71
+ //
72
+ // Accuracy: Unless antipodal to within:
73
+ // --------- ---------------------------
74
+ // 6.4 nanometers 10,000 km (90 degrees)
75
+ // 1 micrometer 81.2 kilometers
76
+ // 1 millimeter 81.2 meters
77
+ // 1 centimeter 8.12 meters
78
+ // 28.5 centimeters 28.5 centimeters
79
+ //
80
+ // The representational and conversion errors referred to earlier are somewhat
81
+ // smaller than this. For example, maximum distance between adjacent
82
+ // representable ChordAngle values is only 13.5 cm rather than 28.5 cm. To
83
+ // see this, observe that the closest representable value to r^2 = 4 is
84
+ // r^2 = 4 * (1 - dblEpsilon / 2). Thus r = 2 * (1 - dblEpsilon / 4) and
85
+ // the angle between these two representable values is
86
+ //
87
+ // x = 2 * acos(r / 2)
88
+ // = 2 * acos(1 - dblEpsilon / 4)
89
+ // ~= 2 * asin(sqrt(dblEpsilon / 2)
90
+ // ~= sqrt(2 * dblEpsilon)
91
+ // ~= 2.1e-8
92
+ //
93
+ // which is 13.5 cm on the Earth's surface.
94
+ //
95
+ // The worst case rounding error occurs when the value halfway between these
96
+ // two representable values is rounded up to 4. This halfway value is
97
+ // r^2 = (4 * (1 - dblEpsilon / 4)), thus r = 2 * (1 - dblEpsilon / 8) and
98
+ // the worst case rounding error is
99
+ //
100
+ // x = 2 * acos(r / 2)
101
+ // = 2 * acos(1 - dblEpsilon / 8)
102
+ // ~= 2 * asin(sqrt(dblEpsilon / 4)
103
+ // ~= sqrt(dblEpsilon)
104
+ // ~= 1.5e-8
105
+ //
106
+ // which is 9.5 cm on the Earth's surface.
37
107
type ChordAngle float64
38
108
39
109
const (
@@ -225,7 +295,7 @@ func (c ChordAngle) Sin() float64 {
225
295
// It is more efficient than Sin.
226
296
func (c ChordAngle ) Sin2 () float64 {
227
297
// Let a be the (non-squared) chord length, and let A be the corresponding
228
- // half-angle (a = 2*sin(A)). The formula below can be derived from:
298
+ // half-angle (a = 2*sin(A)). The formula below can be derived from:
229
299
// sin(2*A) = 2 * sin(A) * cos(A)
230
300
// cos^2(A) = 1 - sin^2(A)
231
301
// This is much faster than converting to an angle and computing its sine.
0 commit comments