Skip to content

Commit 70330af

Browse files
committed
Added uint64_t geohash implementation with float black magic
1 parent 88d4eea commit 70330af

File tree

5 files changed

+90
-201
lines changed

5 files changed

+90
-201
lines changed

C/include/Geohash.h

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,12 @@
44
#include <stdint.h>
55

66
static const int GEOHASH_MAX_PRECISION = 12;
7-
void GeohashEncode(double srcLat,
8-
double srcLon,
9-
char* geohash,
10-
uint8_t precision);
7+
8+
uint64_t GeohashEncodeU64(double lat, double lon);
9+
int GeohashComparePointsU64(double lon1, double lat1, double lon2, double lat2, int precision);
1110

1211
void GeohashDecode(const char* str,
1312
double *pLon,
1413
double *pLat);
1514

16-
int GeohashComparePoints(double lon1, double lat1,
17-
double lon2, double lat2,
18-
int precision);
19-
2015
#endif // GEOHASH_H

C/src/Coordinates.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,23 +44,23 @@ CoordFilterByGeoHash(std::vector<geopoint_t> &lstSrc,
4444
int32_t index;
4545
int32_t count;
4646
};
47-
static char buff[GEOHASH_MAX_PRECISION+1] = {0};
4847

4948
std::vector<geopoint_t> lstRes;
50-
std::map<std::string, AuxItem> dctHashCount;
51-
typedef std::map<std::string, AuxItem>::iterator dctIter;
49+
std::map<uint64_t, AuxItem> dctHashCount;
50+
typedef std::map<uint64_t, AuxItem>::iterator dctIter;
5251

5352
int idx = 0;
5453
for (auto ci = lstSrc.begin(); ci != lstSrc.end(); ++ci) {
55-
GeohashEncode(ci->Latitude, ci->Longitude, buff, precision);
56-
std::string geohash(buff, precision);
57-
dctIter it = dctHashCount.find(geohash);
54+
uint64_t gh = GeohashEncodeU64(ci->Latitude, ci->Longitude);
55+
gh >>= precision*5 + 4;
56+
57+
dctIter it = dctHashCount.find(gh);
5858
if (it == dctHashCount.end()) {
5959
AuxItem ni;
6060
ni.count = 0;
6161
ni.lat = ni.lon = 0.0;
6262
ni.index = NOT_VALID_POINT_INDEX;
63-
auto ir = dctHashCount.insert(std::pair<std::string, AuxItem>(geohash, ni));
63+
auto ir = dctHashCount.insert(std::pair<uint64_t, AuxItem>(gh, ni));
6464
if (!ir.second)
6565
continue;
6666
it = ir.first;

C/src/Geohash.cpp

Lines changed: 35 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -4,113 +4,50 @@
44
#include <string.h>
55
#include <stdio.h>
66

7+
#include <iostream>
78
#include <immintrin.h>
89
#include "Geohash.h"
910

10-
//where is 'A'???? oh my god, we lost 'I', 'L', 'O' too. :(
11-
#define BASE32_COUNT 32
12-
static const char base32Table[BASE32_COUNT] = {'0', '1', '2', '3', '4', '5', '6', '7',
13-
'8', '9', 'b', 'c', 'd', 'e', 'f', 'g',
14-
'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r',
15-
's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
16-
static int searchInBase32Table(char c) {
17-
int f, l, m;
18-
f = 0;
19-
l = BASE32_COUNT;
20-
while (f < l) {
21-
m = (f + l) >> 1;
22-
if (c <= base32Table[m])
23-
l = m;
24-
else
25-
f = m+1;
26-
}
27-
return l;
28-
}
29-
//////////////////////////////////////////////////////////////////////////
30-
31-
typedef struct interval {
32-
double min, max;
33-
} interval_t;
34-
///////////////////////////////////////////////////////
35-
36-
void GeohashEncode(double srcLat,
37-
double srcLon,
38-
char* geohash,
39-
uint8_t precision) {
40-
interval_t lat = {-90.0, 90.0};
41-
interval_t lon = {-180.0, 180.0};
42-
interval_t *ci;
43-
bool isEven = true;
44-
double mid, cd;
45-
int32_t idx = 0; // index into base32 map
46-
int8_t bit = 0; // each char holds 5 bits
11+
static uint64_t interleave(uint64_t x, uint64_t y) {
12+
x = (x | (x << 16)) & 0x0000ffff0000ffff;
13+
x = (x | (x << 8)) & 0x00ff00ff00ff00ff;
14+
x = (x | (x << 4)) & 0x0f0f0f0f0f0f0f0f;
15+
x = (x | (x << 2)) & 0x3333333333333333;
16+
x = (x | (x << 1)) & 0x5555555555555555;
4717

48-
while (precision) {
49-
if (isEven) {
50-
ci = &lon;
51-
cd = srcLon;
52-
} else {
53-
ci = &lat;
54-
cd = srcLat;
55-
}
18+
y = (y | (y << 16)) & 0x0000ffff0000ffff;
19+
y = (y | (y << 8)) & 0x00ff00ff00ff00ff;
20+
y = (y | (y << 4)) & 0x0f0f0f0f0f0f0f0f;
21+
y = (y | (y << 2)) & 0x3333333333333333;
22+
y = (y | (y << 1)) & 0x5555555555555555;
5623

57-
mid = (ci->min + ci->max) / 2.0;
58-
idx <<= 1; //idx *= 2
59-
if (cd >= mid) {
60-
ci->min = mid;
61-
idx += 1;
62-
} else {
63-
ci->max = mid;
64-
}
24+
return x | (y << 1);
6525

66-
isEven = !isEven;
67-
68-
if (++bit == 5) {
69-
*geohash++ = base32Table[idx];
70-
idx = bit = 0;
71-
--precision;
72-
}
73-
}
74-
*geohash++ = 0;
26+
//use pdep instructions
27+
// return _pdep_u64(x, 0x5555555555555555) | _pdep_u64(y, 0xaaaaaaaaaaaaaaaa);
7528
}
76-
//////////////////////////////////////////////////////////////////////////
77-
78-
void GeohashDecode(const char* str,
79-
double *pLon,
80-
double *pLat) {
81-
interval_t latInterval = {-90.0, 90.0};
82-
interval_t lonInterval = {-180.0, 180.0};
83-
interval_t *ci;
84-
bool isEven = true;
85-
int idx ;
86-
double mid;
29+
///////////////////////////////////////////////////////
8730

88-
for (; *str; ++str) {
89-
idx = searchInBase32Table(*str);
90-
for (int i = 0; i < 5; ++i) {
91-
ci = isEven ? &lonInterval : &latInterval;
92-
mid = (ci->max - ci->min) / 2.0;
93-
if ((idx << i) & 0x10) {
94-
ci->min += mid;
95-
} else {
96-
ci->max -= mid;
97-
}
98-
isEven = !isEven;
99-
}
100-
} //for c in str
101-
*pLat = latInterval.max - ((latInterval.max - latInterval.min) / 2.0);
102-
*pLon = lonInterval.max - ((lonInterval.max - lonInterval.min) / 2.0);
31+
uint64_t GeohashEncodeU64(double lat, double lon) {
32+
lat = lat/180.0 + 1.5;
33+
lon = lon/360.0 + 1.5;
34+
uint64_t ilat = *((uint64_t*)&lat);
35+
uint64_t ilon = *((uint64_t*)&lon);
36+
ilat >>= 20;
37+
ilon >>= 20;
38+
ilat &= 0x00000000ffffffff;
39+
ilon &= 0x00000000ffffffff;
40+
41+
return interleave(ilat, ilon);
10342
}
104-
//////////////////////////////////////////////////////////////////////////
10543

106-
int GeohashComparePoints(double lon1, double lat1,
107-
double lon2, double lat2,
108-
int precision) {
44+
int GeohashComparePointsU64(double lon1, double lat1,
45+
double lon2, double lat2,
46+
int precision) {
10947
assert(precision >= 1 && precision <= GEOHASH_MAX_PRECISION);
110-
static char geohash1[GEOHASH_MAX_PRECISION+1] = {0};
111-
static char geohash2[GEOHASH_MAX_PRECISION+1] = {0};
112-
113-
GeohashEncode(lat1, lon1, geohash1, precision);
114-
GeohashEncode(lat2, lon2, geohash2, precision);
115-
return memcmp(geohash1, geohash2, precision);
48+
uint64_t gh1 = GeohashEncodeU64(lat1, lon1);
49+
uint64_t gh2 = GeohashEncodeU64(lat2, lon2);
50+
gh1 >>= precision*5 + 4;
51+
gh2 >>= precision*5 + 4;
52+
return gh1 - gh2;
11653
}

C/src/mainwindow.cpp

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -101,33 +101,34 @@ static QString jsCoordsString(const std::vector<geopoint_t>& lst,
101101
static double filterDistanceRealTime(const std::vector<geopoint_t> &lst,
102102
int prec,
103103
int minPointCount) {
104+
static const double COORD_NOT_INITIALIZED = 361.0;
105+
104106
if (lst.empty() || lst.size() == 1)
105107
return 0.0;
106108

107109
double distance = 0.0;
108-
char buff1[GEOHASH_MAX_PRECISION+1] = {0};
109-
char buff2[GEOHASH_MAX_PRECISION+1] = {0};
110-
char *pbuff1 = buff1;
111-
char *pbuff2 = buff2;
112-
char **ppReadGeohash = &pbuff1;
113-
char **ppCompGeohash = &pbuff2;
114-
115110
int count;
116111
geopoint_t tmpGeo, laGeo;
117112
auto pi = lst.begin();
113+
uint64_t gh0, gh;
114+
uint64_t *tgh0, *tgh;
115+
tgh0 = &gh0;
116+
tgh = &gh;
118117

119-
static const double COORD_NOT_INITIALIZED = 361.0;
120118
laGeo.Latitude = laGeo.Longitude = COORD_NOT_INITIALIZED;
121-
GeohashEncode(pi->Latitude, pi->Longitude, *ppCompGeohash, prec);
119+
120+
*tgh0 = GeohashEncodeU64(pi->Latitude, pi->Longitude);
122121
tmpGeo.Latitude = pi->Latitude;
123122
tmpGeo.Longitude = pi->Longitude;
124123
count = 1;
125124

125+
*tgh >>= prec*5 + 4;
126126
for (++pi; pi != lst.end(); ++pi) {
127-
GeohashEncode(pi->Latitude, pi->Longitude, *ppReadGeohash, prec);
127+
*tgh = GeohashEncodeU64(pi->Latitude, pi->Longitude);
128+
*tgh >>= prec*5 + 4;
128129

129130
//if (ppCompGeohash != ppReadGeohash)
130-
if (memcmp(*ppCompGeohash, *ppReadGeohash, prec)) {
131+
if (*tgh - *tgh0) {
131132
if (count >= minPointCount) {
132133
tmpGeo.Latitude /= count;
133134
tmpGeo.Longitude /= count;
@@ -144,7 +145,7 @@ static double filterDistanceRealTime(const std::vector<geopoint_t> &lst,
144145
count = 1;
145146
tmpGeo.Latitude = pi->Latitude;
146147
tmpGeo.Longitude = pi->Longitude;
147-
std::swap(*ppCompGeohash, *ppReadGeohash);
148+
std::swap(*tgh0, *tgh);
148149
continue;
149150
}
150151

0 commit comments

Comments
 (0)