Skip to content

Commit f72e2a7

Browse files
authored
java: use floor for conversion, add integer tests (#730)
* java: use floor for conversion, add integer tests * syntax errors * missing arguments * fix rate check * fix test data parsing * fix string comparison and degree to integer args * java formatting
1 parent 3543e6f commit f72e2a7

2 files changed

Lines changed: 80 additions & 36 deletions

File tree

java/src/main/java/com/google/openlocationcode/OpenLocationCode.java

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -188,13 +188,6 @@ public OpenLocationCode(String code) {
188188
* @throws IllegalArgumentException if the code length is not valid.
189189
*/
190190
public OpenLocationCode(double latitude, double longitude, int codeLength) {
191-
// Limit the maximum number of digits in the code.
192-
codeLength = Math.min(codeLength, MAX_DIGIT_COUNT);
193-
// Check that the code length requested is valid.
194-
if (codeLength < PAIR_CODE_LENGTH && codeLength % 2 == 1 || codeLength < MIN_DIGIT_COUNT) {
195-
throw new IllegalArgumentException("Illegal code length " + codeLength);
196-
}
197-
198191
// Compute the code.
199192
long[] integers = degreesToIntegers(latitude, longitude);
200193
this.code = encodeIntegers(integers[0], integers[1], codeLength);
@@ -207,8 +200,16 @@ public OpenLocationCode(double latitude, double longitude, int codeLength) {
207200
* @param lng The longitude as a positive integer.
208201
* @param codeLength The requested number of digits.
209202
* @return The OLC for the location.
203+
* @throws IllegalArgumentException if the code length is not valid.
210204
*/
211-
private static String encodeIntegers(long lat, long lng, int codeLength) {
205+
static String encodeIntegers(long lat, long lng, int codeLength) {
206+
// Limit the maximum number of digits in the code.
207+
codeLength = Math.min(codeLength, MAX_DIGIT_COUNT);
208+
// Check that the code length requested is valid.
209+
if (codeLength < PAIR_CODE_LENGTH && codeLength % 2 == 1 || codeLength < MIN_DIGIT_COUNT) {
210+
throw new IllegalArgumentException("Illegal code length " + codeLength);
211+
}
212+
212213
// Store the code - we build it in reverse and reorder it afterwards.
213214
StringBuilder revCodeBuilder = new StringBuilder();
214215
// Compute the grid part of the code if necessary.
@@ -663,9 +664,9 @@ public static boolean isShortCode(String code) {
663664
* @param longitude The longitude in decimal degrees.
664665
* @return A list of [latitude, longitude] in clipped, normalised integer values.
665666
*/
666-
private static long[] degreesToIntegers(double latitude, double longitude) {
667-
long lat = (long) roundAwayFromZero(latitude * LAT_INTEGER_MULTIPLIER);
668-
long lng = (long) roundAwayFromZero(longitude * LNG_INTEGER_MULTIPLIER);
667+
static long[] degreesToIntegers(double latitude, double longitude) {
668+
long lat = (long) Math.floor(latitude * LAT_INTEGER_MULTIPLIER);
669+
long lng = (long) Math.floor(longitude * LNG_INTEGER_MULTIPLIER);
669670

670671
// Clip and normalise values.
671672
lat += LATITUDE_MAX * LAT_INTEGER_MULTIPLIER;
@@ -685,20 +686,6 @@ private static long[] degreesToIntegers(double latitude, double longitude) {
685686
return new long[] {lat, lng};
686687
}
687688

688-
/**
689-
* Round numbers like C does. This implements rounding away from zero (see
690-
* https://en.wikipedia.org/wiki/Rounding).
691-
*
692-
* @param num A number to round.
693-
* @return The rounded value.
694-
*/
695-
private static Long roundAwayFromZero(double num) {
696-
if (num >= 0) {
697-
return Math.round(num);
698-
}
699-
return -1 * Math.round(Math.abs(num));
700-
}
701-
702689
private static double clipLatitude(double latitude) {
703690
return Math.min(Math.max(latitude, -LATITUDE_MAX), LATITUDE_MAX);
704691
}

java/src/test/java/com/google/openlocationcode/EncodingTest.java

Lines changed: 68 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,24 @@ public class EncodingTest {
2323

2424
private static class TestData {
2525

26-
private final double latitude;
27-
private final double longitude;
26+
private final double latitudeDegrees;
27+
private final double longitudeDegrees;
28+
private final long latitudeInteger;
29+
private final long longitudeInteger;
2830
private final int length;
2931
private final String code;
3032

3133
public TestData(String line) {
3234
String[] parts = line.split(",");
33-
if (parts.length != 4) {
35+
if (parts.length != 6) {
3436
throw new IllegalArgumentException("Wrong format of testing data.");
3537
}
36-
this.latitude = Double.parseDouble(parts[0]);
37-
this.longitude = Double.parseDouble(parts[1]);
38-
this.length = Integer.parseInt(parts[2]);
39-
this.code = parts[3];
38+
this.latitudeDegrees = Double.parseDouble(parts[0]);
39+
this.longitudeDegrees = Double.parseDouble(parts[1]);
40+
this.latitudeInteger = Long.parseLong(parts[2]);
41+
this.longitudeInteger = Long.parseLong(parts[3]);
42+
this.length = Integer.parseInt(parts[4]);
43+
this.code = parts[5];
4044
}
4145
}
4246

@@ -56,14 +60,67 @@ public void setUp() throws Exception {
5660
}
5761

5862
@Test
59-
public void testEncodeFromLatLong() {
63+
public void testEncodeFromDegrees() {
64+
double allowedErrorRate = 0.05;
65+
int failedEncodings = 0;
66+
for (TestData testData : testDataList) {
67+
String got =
68+
OpenLocationCode.encode(
69+
testData.latitudeDegrees, testData.longitudeDegrees, testData.length);
70+
if (!testData.code.equals(got)) {
71+
failedEncodings++;
72+
System.out.printf(
73+
"ENCODING DIFFERENCE: encode(%f,%f,%d) got %s, want %s\n",
74+
testData.latitudeDegrees,
75+
testData.longitudeDegrees,
76+
testData.length,
77+
got,
78+
testData.code);
79+
}
80+
}
81+
double gotRate = (double) failedEncodings / (double) testDataList.size();
82+
Assert.assertTrue(
83+
String.format(
84+
"Too many encoding errors (actual rate %f, allowed rate %f), see ENCODING DIFFERENCE"
85+
+ " lines",
86+
gotRate, allowedErrorRate),
87+
gotRate <= allowedErrorRate);
88+
}
89+
90+
@Test
91+
public void testDegreesToIntegers() {
92+
for (TestData testData : testDataList) {
93+
long[] got =
94+
OpenLocationCode.degreesToIntegers(testData.latitudeDegrees, testData.longitudeDegrees);
95+
Assert.assertTrue(
96+
String.format(
97+
"degreesToIntegers(%f, %f) returned latitude %d, expected %d",
98+
testData.latitudeDegrees,
99+
testData.longitudeDegrees,
100+
got[0],
101+
testData.latitudeInteger),
102+
got[0] == testData.latitudeInteger || got[0] == testData.latitudeInteger - 1);
103+
Assert.assertTrue(
104+
String.format(
105+
"degreesToIntegers(%f, %f) returned longitude %d, expected %d",
106+
testData.latitudeDegrees,
107+
testData.longitudeDegrees,
108+
got[1],
109+
testData.longitudeInteger),
110+
got[1] == testData.longitudeInteger || got[1] == testData.longitudeInteger - 1);
111+
}
112+
}
113+
114+
@Test
115+
public void testEncodeFromIntegers() {
60116
for (TestData testData : testDataList) {
61117
Assert.assertEquals(
62118
String.format(
63-
"Latitude %f, longitude %f and length %d were wrongly encoded.",
64-
testData.latitude, testData.longitude, testData.length),
119+
"Latitude %d, longitude %d and length %d were wrongly encoded.",
120+
testData.latitudeInteger, testData.longitudeInteger, testData.length),
65121
testData.code,
66-
OpenLocationCode.encode(testData.latitude, testData.longitude, testData.length));
122+
OpenLocationCode.encodeIntegers(
123+
testData.latitudeInteger, testData.longitudeInteger, testData.length));
67124
}
68125
}
69126
}

0 commit comments

Comments
 (0)