Three word location

From Rosetta Code
Three word location is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.
Three Word Location.
Display a location on the Earth with three words derived from a 
latitude longitude pair.
For:
latitude = 28.3852
longitude = -81.5638
Display: W18497 W11324 W01322 
Implementation:
Build a synthetic word array of 28126, 6 character words 
in the form W00000 thru W28125.
Convert latitude and longitude into positive integers.
Build a 43 bit integer containing latitude (21 bits) and longitude (22 bits).
Isolate most significant 15 bits for word 1 index.
Isolate next 14 bits for word 2 index.
Isolate next 14 bits for word 3 index.
Fetch each word from the word array.  
Display the words.
Reverse the procedure and display the original latitude and longitude.

Symsyn

<lang Symsyn> | Three Word Location - convert latitude and longitude to three words

lat : 28.3852 lon : -81.5638

| build word array W00000 ... W28125

i
if i <= 28125
   ~ i $r
   #$r szr
   'W00000' $t
   (6-szr) szr 
   szr #$t
   + $r $t
   + $t $wordarray 
   + i
   goif
endif

| make latitude and longitude positive integers

{lat * 10000 + 900000} ilat
{lon * 10000 + 1800000} ilon

| build 43 bit integer containing latitude (21 bits) and longitude (22 bits)

ilat latlon
shl latlon 22
+ ilon latlon

| isolate most significant 15 bits for word 1 index | next 14 bits for word 2 index | next 14 bits for word 3 index

latlon:42:15 w1
latlon:27:14 w2
latlon:13:14 w3

| fetch each word from word array

 (w1*6+1) w1
 $wordarray.w1 $w1 6
 (w2*6+1) w2
 $wordarray.w2 $w2 6
 (w3*6+1) w3
 $wordarray.w3 $w3 6

| display words

"$w1 ' ' $w2 ' ' $w3" []


| reverse the procedure


| look up each word

call bsearch 0 28125 $w1
result w1index
call bsearch 0 28125 $w2
result w2index
call bsearch 0 28125 $w3
result w3index

| build the latlon integer from the word indexes

w1index latlon
shl latlon 14
+ w2index latlon
shl latlon 14
+ w3index latlon

| isolate the latitude and longitude

latlon:21:22 ilon
latlon:42:21 ilat

| convert back to floating point values

{(ilon - 1800000) / 10000} lon
{(ilat - 900000) / 10000} lat

| display values

"'latitude = ' lat ' longitude = ' lon" [] 
stop

bsearch

param L H $word
if L <= H 
   ((L + H) shr 1) M
   (M*6+1) I
   $wordarray.I $w 6
   if $w > $word 
      - 1 M H
   else
      if $w < $word 
         + 1 M L
      else      
         return M
      endif
   endif
   goif
endif
return -1 

</lang>

Julia

Direct translation from the SymSyn example given by the task creator. though note that idiomatic Julia would usually code this as two small encode() and decode() functions. <lang julia>

  1. Three Word Location - convert latitude and longitude to three words

LAT = 28.3852 LON = -81.5638

  1. build word array W00000 ... W28125

wordarray = ["W" * string(x, pad=5) for x in 0:28125]

  1. make latitude and longitude positive integers

ILAT = Int(LAT * 10000 + 900000) ILON = Int(LON * 10000 + 1800000)

  1. build 43 bit integer containing latitude (21 bits) and longitude (22 bits)

LATLON = (ILAT << 22) + ILON

  1. isolate most significant 15 bits for word 1 index
  2. next 14 bits for word 2 index
  3. next 14 bits for word 3 index

W1 = (LATLON >> 28) & 0xefff W2 = (LATLON >> 14) & 0x7fff W3 = LATLON & 0x7fff

  1. fetch each word from word array

w1 = wordarray[W1 + 1] w2 = wordarray[W2 + 1] w3 = wordarray[W3 + 1]

  1. display words

println("$w1 $w2 $w3")


  1. reverse the procedure


  1. look up each word

(w1index, w2index, w3index) = indexin([w1, w2, w3], wordarray) .- 1

  1. build the latlon integer from the word indexes

latlon = (w1index << 28) | (w2index << 14) | w3index


  1. isolate the latitude and longitude

ilon = latlon & 0xfffff ilat = latlon >> 22

  1. convert back to floating point values

lon = (ilon - 1800000) / 10000 lat = (ilat - 900000) / 10000

  1. display values

println("latitude = $lat longitude = $lon")

</lang>

Output:
W18497 W27708 W01322
latitude = 28.3852 longitude = -81.5638