[PATCH 1/2] Save latitude/longitude using integer math

Linus Torvalds torvalds at linux-foundation.org
Wed Dec 5 10:10:55 PST 2012


From: Linus Torvalds <torvalds at linux-foundation.org>
Date: Wed, 5 Dec 2012 08:25:33 -0800
Subject: [PATCH 1/2] Save latitude/longitude using integer math

I hate using floating point, this tries to at least make parts of it be
integer logic, and avoid the whole locale issue.  This still keeps the
latitude and longitude internally as a floating point value, and parses
it that way, but I'm slowly moving towards less and less FP use.

We're going to use micro-degrees for location information: that's
sufficient to about a tenth of a meter precision, and it fits in a
32-bit integer.

If you specify dive sites with more precision than that, you may have
OCD.

Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
---

This just cleans the code up a bit, and starts printing things out using 
integer math.

The next one will actually turn the data structures *into* integers.

 save-xml.c | 46 ++++++++++++++++++++++++++++++++++++----------
 1 file changed, 36 insertions(+), 10 deletions(-)

diff --git a/save-xml.c b/save-xml.c
index d4bc36cab1a5..948f2ed08607 100644
--- a/save-xml.c
+++ b/save-xml.c
@@ -4,6 +4,7 @@
 #include <stdlib.h>
 #include <errno.h>
 #include <time.h>
+#include <math.h>
 
 #include "dive.h"
 
@@ -177,6 +178,35 @@ static void save_salinity(FILE *f, struct dive *dive)
 	fputs(" />\n", f);
 }
 
+/*
+ * Format degrees to within 6 decimal places. That's about 0.1m
+ * on a great circle (ie longitude at equator). And micro-degrees
+ * is also enough to fit in a fixed-point 32-bit integer.
+ */
+static int format_degrees(char *buffer, double value)
+{
+	int udeg = round(value * 1000000.0);
+	const char *sign = "";
+
+	if (udeg < 0) {
+		sign = "-";
+		udeg = -udeg;
+	}
+	return sprintf(buffer, "%s%u.%06u",
+		sign, udeg / 1000000, udeg % 1000000);
+}
+
+static int format_location(char *buffer, double latitude, double longitude)
+{
+	int len = sprintf(buffer, "gps='");
+
+	len += format_degrees(buffer+len, latitude);
+	buffer[len++] = ' ';
+	len += format_degrees(buffer+len, longitude);
+	buffer[len++] = '\'';
+
+	return len;
+}
 
 static void show_location(FILE *f, struct dive *dive)
 {
@@ -192,20 +222,16 @@ static void show_location(FILE *f, struct dive *dive)
 	 * you dove a few meters away.
 	 */
 	if (latitude || longitude) {
-		int len = snprintf(buffer, sizeof(buffer)-4,
-			"  <location gps=");
-		char *buf = buffer + len;
-
-		len = strlen(g_ascii_formatd(buf, 80, "'%.12g ", latitude));
-		buf += len;
-		len = strlen(g_ascii_formatd(buf, 80, "%.12g'>", longitude));
-		buf += len;
-		len = buf - buffer;
+		int len = sprintf(buffer, "  <location ");
+
+		len += format_location(buffer+len, latitude, longitude);
 		if (!dive->location) {
-			memcpy(&buffer[len-1], "/>\n", 4);
+			memcpy(buffer+len, "/>\n", 4);
 			fputs(buffer, f);
 			return;
 		}
+		buffer[len++] = '>';
+		buffer[len] = 0;
 		prefix = buffer;
 	}
 	show_utf8(f, dive->location, prefix,"</location>\n", 0);
-- 
1.8.0.dirty



More information about the subsurface mailing list