summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGary E. Miller <gem@rellim.com>2019-02-22 14:59:37 -0800
committerGary E. Miller <gem@rellim.com>2019-02-22 14:59:37 -0800
commit1db29a3fa49eca5929ba03346eac7cd49f58e86d (patch)
tree290d2a67cac87a289d390cb01a938fb74ecc0413
parent99835709b0f9bc8a39bf2736e78a2690dd636d4b (diff)
downloadgpsd-1db29a3fa49eca5929ba03346eac7cd49f58e86d.tar.gz
deg_to_s(): Add rounding for dd, ddmm, and ddmmss. Update tests.
-rw-r--r--gpsdclient.c37
-rw-r--r--tests/test_gpsdclient.c70
2 files changed, 77 insertions, 30 deletions
diff --git a/gpsdclient.c b/gpsdclient.c
index c34ea06c..3705f6f2 100644
--- a/gpsdclient.c
+++ b/gpsdclient.c
@@ -29,6 +29,7 @@ static struct exportmethod_t exportmethods[] = {
};
/* convert double degrees to a static string and return a pointer to it
+ * WARNING: not thread safe!
*
* deg_str_type:
* deg_dd : return DD.ddddddd
@@ -38,8 +39,10 @@ static struct exportmethod_t exportmethods[] = {
* returns 'nan' for 0 > f or 360 < f
*
* NOTE: degrees must be positive.
+ * 360.0 is rolled over to 0.0
*
- * for cm level accuracy we need degrees to 7+ decimal places
+ * for cm level accuracy, at sea level, we need degrees
+ * to 7+ decimal places
* Ref: https://en.wikipedia.org/wiki/Decimal_degrees
*
*/
@@ -54,17 +57,43 @@ char *deg_to_str(enum deg_str_type type, double f)
return str;
}
- /* FIXME: s/b rounding */
+ /* add rounding quanta */
+ /* IEEE 754 wants round to nearest even.
+ * We cheat and just round to nearest.
+ * Intel trying to kill off round to nearest even. */
+ switch (type) {
+ default:
+ /* huh? */
+ type = deg_dd;
+ /* FALLTHROUGH */
+ case deg_dd:
+ /* DD.dddddddd */
+ f += 0.5 * 1e-8; /* round up */
+ break;
+ case deg_ddmm:
+ /* DD MM.mmmmmm */
+ f += (0.5 * 1e-6) / 60; /* round up */
+ break;
+ case deg_ddmmss:
+ f += (0.5 * 1e-5) / 3600; /* round up */
+ break;
+ }
fmin = modf(f, &fdeg);
deg = (int)fdeg;
+ if (360 == deg) {
+ /* fix round-up roll-over */
+ deg = 0;
+ fmin = 0.0;
+ }
if (deg_dd == type) {
/* DD.dddddddd */
+ long frac_deg = (long)(fmin * 100000000.0);
/* cm level accuracy requires the %08ld */
- long frac_deg = (long)(fmin * 100000000);
(void)snprintf(str, sizeof(str), "%3d.%08ld", deg, frac_deg);
return str;
}
+
fsec = modf(fmin * 60, &fmin);
min = (int)fmin;
@@ -75,7 +104,7 @@ char *deg_to_str(enum deg_str_type type, double f)
return str;
}
/* else DD MM SS.sss */
- fdsec = modf(fsec * 60, &fsec);
+ fdsec = modf(fsec * 60.0, &fsec);
sec = (int)fsec;
dsec = (int)(fdsec * 100000.0);
(void)snprintf(str, sizeof(str), "%3d %02d' %02d.%05d\"", deg, min, sec,
diff --git a/tests/test_gpsdclient.c b/tests/test_gpsdclient.c
index 6f81633f..c65b35f6 100644
--- a/tests/test_gpsdclient.c
+++ b/tests/test_gpsdclient.c
@@ -24,39 +24,57 @@ struct test {
};
struct test tests[] = {
- /* 1 degree, 1 arcminute, 1.999 arcsec */
- {(1.0 + 1.0/60.0 + 1.999/3600.0),
- " 1.01722194",
- " 1 01.033316'",
- " 1 01' 01.99899\""},
- /* 1 deg, 2 min, 2.0999 sec */
- {(1.0 + 2.0/60.0 + 2.999/3600.0),
- " 1.03416638",
- " 1 02.049983'",
- " 1 02' 02.99900\""},
- /* 44.99999994, should not be rounded up */
- {44.99999994,
- " 44.99999994",
- " 44 59.999996'",
- " 44 59' 59.99978\""},
- /* 44.99999999999 */
- /* FIXME: s/b rounded */
- {44.99999999999,
- " 44.99999999",
- " 44 59.999999'",
- " 44 59' 59.99999\""},
+ /* 1.999999995 sec */
+ {(1.999999995),
+ " 2.00000000", /* rounded up */
+ " 2 00.000000'", /* rounded up */
+ " 1 59' 59.99998\""},
+ /* 3.999999999 sec */
+ {(3.999999994),
+ " 3.99999999", /* not rounded up */
+ " 4 00.000000'", /* rounded up */
+ " 3 59' 59.99998\""},
+ /* 5 degree, 1.99999960 arcmin */
+ {(5.0 + 1.999999600/60.0),
+ " 5.03333333",
+ " 5 02.000000'", /* rounded up */
+ " 5 01' 59.99998\""},
+ /* 6 degree, 1.99999940 arcmin */
+ {(6.0 + 1.999999400/60.0),
+ " 6.03333332",
+ " 6 01.999999'", /* not rounded up */
+ " 6 01' 59.99996\""},
+ /* 7 degree, 59.99999960 arcmin */
+ {(7.0 + 59.999999600/60.0),
+ " 7.99999999",
+ " 8 00.000000'", /* rounded up */
+ " 7 59' 59.99998\""},
+ /* 9 degree, 59.99999940 arcmin */
+ {(9.0 + 59.999999400/60.0),
+ " 9.99999999",
+ " 9 59.999999'", /* not rounded up */
+ " 9 59' 59.99996\""},
+ /* 11 degree, 1 arcminute, 1.99999600 arcsec */
+ {(11.0 + 1.0/60.0 + 1.99999600/3600.0),
+ " 11.01722222",
+ " 11 01.033333'",
+ " 11 01' 02.00000\""}, /* rounded up */
+ /* 12 deg, 2 min, 2.99999400 sec */
+ {(12.0 + 2.0/60.0 + 2.99999400/3600.0),
+ " 12.03416667",
+ " 12 02.050000'",
+ " 12 02' 02.99999\""}, /* not rounded up */
/* -44.99999999999 */
- /* FIXME: should not be nan? */
+ /* nan because not positive degrees */
{-44.99999999999,
"nan",
"nan",
"nan"},
/* 359.99999999999 */
- /* FIXME: s/b rounded */
{359.99999999999,
- "359.99999999",
- "359 59.999999'",
- "359 59' 59.99999\""},
+ " 0.00000000", /* rounded up, and rolled over */
+ " 0 00.000000'",
+ " 0 00' 00.00000\""},
};