From ec172e1745c640f01c42d1e81b14f4c2ea69acd4 Mon Sep 17 00:00:00 2001
From: David Byers <david.byers@liu.se>
Date: Tue, 21 Jul 2020 21:17:23 +0200
Subject: [PATCH] Rewrote olc-decode to use integer math.

---
 CHANGELOG       |  3 +++
 olc.el          | 35 ++++++++++++++++++++++-------------
 test/olctest.el |  7 ++++---
 3 files changed, 29 insertions(+), 16 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index deef8f4..9caef53 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,8 @@
 2020-07-21  David Byers  <david.byers@liu.se>
 
+	More integer math:
+	(olc-decode): Converted to use integer math.
+
 	Wrote texinfo documentation:
 	* olc.el (olc-parse-length): Removed.
 	Updated documentation comment.
diff --git a/olc.el b/olc.el
index 64715dc..1b7273b 100644
--- a/olc.el
+++ b/olc.el
@@ -264,10 +264,13 @@ coordinates, an empty code, and so forth).
 Since this function uses floating point calculations, the results
 are not identical to e.g. the C++ reference implementation. The
 differences, however, are extremely small."
-  (let ((parse (olc-parse-code code))
-	(lat -90.0)
-	(lon -180.0)
-	(size 20.0))
+  (let* ((parse (olc-parse-code code))
+         (latscale (* (expt 20 4) (expt 5 5)))
+         (lonscale (* (expt 20 4) (expt 4 5)))
+         (lat (* latscale -90))
+         (lon (* lonscale -180))
+         (latsize (* latscale 20))
+         (lonsize (* lonscale 20)))
 
     ;; We only deal with long codes
     (when (olc-parse-short parse)
@@ -275,22 +278,28 @@ differences, however, are extremely small."
 
     ;; Process the pairs
     (mapc (lambda (pair)
-	    (setq lat (+ lat (* size (olc-digit-value (car pair))))
-		  lon (+ lon (* size (olc-digit-value (cdr pair))))
-		  width size
-		  height size
-		  size (/ size 20.0)))
+	    (setq lat (+ lat (* latsize (olc-digit-value (car pair))))
+		  lon (+ lon (* lonsize (olc-digit-value (cdr pair))))
+		  latsize (/ latsize 20)
+                  lonsize (/ lonsize 20)))
 	  (olc-parse-pairs parse))
 
+    ;; I'm too tired to figure out why
+    (setq latsize (* latsize 20) lonsize (* lonsize 20))
+
     ;; Process the grid
     (when (olc-parse-grid parse)
       (mapc (lambda (refine)
-	      (setq width (/ width 4.0) height (/ height 5.0))
+	      (setq latsize (/ latsize 5) lonsize (/ lonsize 4))
 	      (let ((coord (olc-digit-value refine)))
-		(setq lat (+ lat (* height (/ coord 4)))
-		      lon (+ lon (* width (% coord 4))))))
+		(setq lat (+ lat (* latsize (/ coord 4)))
+		      lon (+ lon (* lonsize (% coord 4))))))
 	    (olc-parse-grid parse)))
-    (olc-area-create :latlo lat :lonlo lon :lathi (+ lat height) :lonhi (+ lon width))))
+
+    (olc-area-create :latlo (/ lat (float latscale))
+                     :lonlo (/ lon (float lonscale))
+                     :lathi (/ (+ lat latsize) (float latscale))
+                     :lonhi (/ (+ lon lonsize) (float lonscale)))))
 
 
 (defun olc-encode (lat lon len)
diff --git a/test/olctest.el b/test/olctest.el
index bf2af42..e042345 100644
--- a/test/olctest.el
+++ b/test/olctest.el
@@ -18,8 +18,9 @@
 
 (require 'cl-lib)
 
-;; Decode still uses float arithmetic, so results can be slightly off
-;; from the test cases. This is deemed acceptable.
+;; Due to rounding and floating point representation we can't seem
+;; to get closer than 1e-10 to the reference test cases, but sinze
+;; it only affects decoding, that is an insignificant error level.
 
 (defvar olctest-decode-tolerance 0.0000000001)
 
@@ -196,7 +197,7 @@
 
 (defun olctest-run-all ()
   "Run all tests."
-  (and (olctest-decode)
+  (and (olctest-decode)q
        (olctest-encode)
        (olctest-shortcodes)
        (olctest-validity)
-- 
GitLab