Skip to content

Commit 9416cf7

Browse files
committed
Fixes issue #3, test = GeodSolve99
Problem was that output of sincosd(+/-45) was inconsistent because of directed rounding by Math.round. Fix by porting special treatment of angles +/-45 and +/-30 from C++ library.
1 parent f9a6b00 commit 9416cf7

File tree

2 files changed

+30
-17
lines changed

2 files changed

+30
-17
lines changed

geodesic/Math.js.in

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -296,14 +296,21 @@ geodesic.Accumulator = {};
296296
m.sincosd = function(x) {
297297
// In order to minimize round-off errors, this function exactly reduces
298298
// the argument to the range [-45, 45] before converting it to radians.
299-
var r, q, s, c, sinx, cosx;
300-
r = x % 360;
301-
q = Math.round(r / 90); // If r is NaN this returns NaN
302-
r -= 90 * q;
303-
// now abs(r) <= 45
304-
r *= this.degree;
299+
var d, r, q, s, c, sinx, cosx;
300+
d = x % 360;
301+
q = Math.round(d / 90); // If d is NaN this returns NaN
302+
d -= 90 * q;
303+
// now abs(d) <= 45
304+
r = d * this.degree;
305305
// Possibly could call the gnu extension sincos
306306
s = Math.sin(r); c = Math.cos(r);
307+
if (Math.abs(d) === 45) {
308+
c = Math.sqrt(0.5);
309+
s = m.copysign(c, r);
310+
} else if (Math.abs(d) === 30) {
311+
c = Math.sqrt(0.75);
312+
s = m.copysign(0.5, r)
313+
}
307314
switch (q & 3) {
308315
case 0: sinx = s; cosx = c; break;
309316
case 1: sinx = c; cosx = -s; break;
@@ -325,22 +332,29 @@ geodesic.Accumulator = {};
325332
m.sincosde = function(x, t) {
326333
// In order to minimize round-off errors, this function exactly reduces
327334
// the argument to the range [-45, 45] before converting it to radians.
328-
var r, q, s, c, sinx, cosx;
329-
r = x % 360;
330-
q = Math.round(r / 90); // If r is NaN this returns NaN
331-
r = m.AngRound((r - 90 * q) + t);
332-
// now abs(r) <= 45
333-
r *= this.degree;
335+
var d, r, q, s, c, sinx, cosx;
336+
d = x % 360;
337+
q = Math.round(d / 90); // If d is NaN this returns NaN
338+
d = m.AngRound((d - 90 * q) + t);
339+
// now abs(d) <= 45
340+
r = d * this.degree;
334341
// Possibly could call the gnu extension sincos
335342
s = Math.sin(r); c = Math.cos(r);
343+
if (Math.abs(d) === 45) {
344+
c = Math.sqrt(0.5);
345+
s = m.copysign(c, r);
346+
} else if (Math.abs(d) === 30) {
347+
c = Math.sqrt(0.75);
348+
s = m.copysign(0.5, r)
349+
}
336350
switch (q & 3) {
337351
case 0: sinx = s; cosx = c; break;
338352
case 1: sinx = c; cosx = -s; break;
339353
case 2: sinx = -s; cosx = -c; break;
340354
default: sinx = -c; cosx = s; break; // case 3
341355
}
342356
cosx += 0;
343-
if (sinx === 0) sinx = m.copysign(sinx, x);
357+
if (sinx === 0) sinx = m.copysign(sinx, x+t);
344358
return {s: sinx, c: cosx};
345359
};
346360

geodesic/test/geodesictest.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -651,15 +651,14 @@ describe("geodesic", function() {
651651

652652
it("GeodSolve99", function() {
653653
// Test case https://github.com/geographiclib/geographiclib-js/issues/3
654+
// Problem was that output of sincosd(+/-45) was inconsistent because of
655+
// directed rounding by Math.round. Fix by porting special treatment of
656+
// angles +/-45 and +/-30 from C++ library.
654657
var geod = g.WGS84,
655658
inv = geod.Inverse(45, 0, -45, 179.572719);
656-
// inv = geod.Inverse(45, 0, -45, 179);
657659
assert.approx(inv.azi1, 90.00000028, 1e-8 );
658660
assert.approx(inv.azi2, 90.00000028, 1e-8 );
659661
assert.approx(inv.s12, 19987083.007, 0.5e-3);
660-
// assert.approx(inv.azi1, 90.20248882, 1e-8 );
661-
// assert.approx(inv.azi2, 90.20248882, 1e-8 );
662-
// assert.approx(inv.s12, 19941926.020, 0.5e-3);
663662
});
664663

665664
});

0 commit comments

Comments
 (0)