@@ -26,14 +26,84 @@ import (
2626// to be calculated and compared. Otherwise it is simpler to use Angle.
2727//
2828// 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.
37107type ChordAngle float64
38108
39109const (
@@ -225,7 +295,7 @@ func (c ChordAngle) Sin() float64 {
225295// It is more efficient than Sin.
226296func (c ChordAngle ) Sin2 () float64 {
227297 // 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:
229299 // sin(2*A) = 2 * sin(A) * cos(A)
230300 // cos^2(A) = 1 - sin^2(A)
231301 // This is much faster than converting to an angle and computing its sine.
0 commit comments