Skip to content

Commit ae0f176

Browse files
authored
use floor for integer conversion (#727)
1 parent 3506d50 commit ae0f176

File tree

3 files changed

+63
-11
lines changed

3 files changed

+63
-11
lines changed

c/openlocationcode_test.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ std::vector<EncodingTestData> GetEncodingDataFromCsv() {
122122
return data_results;
123123
}
124124

125-
// TolerantTestParams runs a test with the
125+
// TolerantTestParams runs a test with a permitted failure rate.
126126
struct TolerantTestParams {
127127
double allowed_failure_rate;
128128
std::vector<EncodingTestData> test_data;

cpp/openlocationcode.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const int kPositionLUT['X' - 'C' + 1] = {8, -1, -1, 9, 10, 11, -1, 12,
4949
-1, -1, -1, 17, 18, 19};
5050

5151
int64_t latitudeToInteger(double latitude) {
52-
int64_t lat = round(latitude * kGridLatPrecisionInverse);
52+
int64_t lat = floor(latitude * kGridLatPrecisionInverse);
5353
lat += kLatitudeMaxDegrees * kGridLatPrecisionInverse;
5454
if (lat < 0) {
5555
lat = 0;
@@ -60,7 +60,7 @@ int64_t latitudeToInteger(double latitude) {
6060
}
6161

6262
int64_t longitudeToInteger(double longitude) {
63-
int64_t lng = round(longitude * kGridLngPrecisionInverse);
63+
int64_t lng = floor(longitude * kGridLngPrecisionInverse);
6464
lng += kLongitudeMaxDegrees * kGridLngPrecisionInverse;
6565
if (lng <= 0) {
6666
lng = lng % (2 * kLongitudeMaxDegrees * kGridLngPrecisionInverse) +

cpp/openlocationcode_test.cc

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -136,12 +136,12 @@ INSTANTIATE_TEST_CASE_P(OLC_Tests, DecodingChecks,
136136
struct EncodingTestData {
137137
double lat_deg;
138138
double lng_deg;
139+
long long int lat_int;
140+
long long int lng_int;
139141
size_t length;
140142
std::string code;
141143
};
142144

143-
class EncodingChecks : public ::testing::TestWithParam<EncodingTestData> {};
144-
145145
const std::string kEncodingTestsFile = "test_data/encoding.csv";
146146

147147
std::vector<EncodingTestData> GetEncodingDataFromCsv() {
@@ -152,19 +152,71 @@ std::vector<EncodingTestData> GetEncodingDataFromCsv() {
152152
EncodingTestData test_data = {};
153153
test_data.lat_deg = strtod(csv_records[i][0].c_str(), nullptr);
154154
test_data.lng_deg = strtod(csv_records[i][1].c_str(), nullptr);
155-
test_data.length = atoi(csv_records[i][2].c_str());
156-
test_data.code = csv_records[i][3];
155+
test_data.lat_int = strtoll(csv_records[i][2].c_str(), nullptr, 10);
156+
test_data.lng_int = strtoll(csv_records[i][3].c_str(), nullptr, 10);
157+
test_data.length = atoi(csv_records[i][4].c_str());
158+
test_data.code = csv_records[i][5];
157159
data_results.push_back(test_data);
158160
}
159161
return data_results;
160162
}
161163

162-
TEST_P(EncodingChecks, Encode) {
164+
// TolerantTestParams runs a test with a permitted failure rate.
165+
struct TolerantTestParams {
166+
double allowed_failure_rate;
167+
std::vector<EncodingTestData> test_data;
168+
};
169+
170+
class TolerantEncodingChecks
171+
: public ::testing::TestWithParam<TolerantTestParams> {};
172+
173+
TEST_P(TolerantEncodingChecks, EncodeDegrees) {
174+
const TolerantTestParams& test_params = GetParam();
175+
int failure_count = 0;
176+
177+
for (EncodingTestData tc : test_params.test_data) {
178+
LatLng lat_lng = LatLng{tc.lat_deg, tc.lng_deg};
179+
// Encode the test location and make sure we get the expected code.
180+
std::string got_code = Encode(lat_lng, tc.length);
181+
if (tc.code.compare(got_code) != 0) {
182+
failure_count++;
183+
printf(" ENCODING FAILURE: Got: '%s', expected: '%s'\n",
184+
got_code.c_str(), tc.code.c_str());
185+
}
186+
}
187+
double actual_failure_rate =
188+
double(failure_count) / test_params.test_data.size();
189+
EXPECT_LE(actual_failure_rate, test_params.allowed_failure_rate)
190+
<< "Failure rate " << actual_failure_rate << " exceeds allowed rate "
191+
<< test_params.allowed_failure_rate;
192+
}
193+
194+
// Allow a 5% error rate encoding from degree coordinates (because of floating
195+
// point precision).
196+
INSTANTIATE_TEST_SUITE_P(OLC_Tests, TolerantEncodingChecks,
197+
::testing::Values(TolerantTestParams{
198+
0.05, GetEncodingDataFromCsv()}));
199+
200+
class EncodingChecks : public ::testing::TestWithParam<EncodingTestData> {};
201+
202+
TEST_P(EncodingChecks, OLC_EncodeIntegers) {
163203
EncodingTestData test_data = GetParam();
164-
LatLng lat_lng = LatLng{test_data.lat_deg, test_data.lng_deg};
165204
// Encode the test location and make sure we get the expected code.
166-
std::string actual_code = Encode(lat_lng, test_data.length);
167-
EXPECT_EQ(test_data.code, actual_code);
205+
std::string got_code = internal::encodeIntegers(
206+
test_data.lat_int, test_data.lng_int, test_data.length);
207+
EXPECT_EQ(test_data.code, got_code);
208+
}
209+
210+
TEST_P(EncodingChecks, OLC_LocationToIntegers) {
211+
EncodingTestData test_data = GetParam();
212+
int64_t got_lat = internal::latitudeToInteger(test_data.lat_deg);
213+
// Due to floating point precision limitations, we may get values 1 less than
214+
// expected.
215+
EXPECT_LE(got_lat, test_data.lat_int);
216+
EXPECT_GE(got_lat + 1, test_data.lat_int);
217+
int64_t got_lng = internal::longitudeToInteger(test_data.lng_deg);
218+
EXPECT_LE(got_lng, test_data.lng_int);
219+
EXPECT_GE(got_lng + 1, test_data.lng_int);
168220
}
169221

170222
INSTANTIATE_TEST_CASE_P(OLC_Tests, EncodingChecks,

0 commit comments

Comments
 (0)