Three word location

From Rosetta Code
Revision as of 11:47, 20 July 2020 by PureFox (talk | contribs) (Added C)
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.


C

Translation of: Go

<lang c>#include <stdio.h>

  1. include <stdlib.h>

typedef long long int64;

void to_word(char *ws, int64 w) {

   sprintf(ws, "W%05lld", w);

}

int64 from_word(char *ws) {

   return atoi(++ws);

}

int main() {

   double lat, lon;
   int64 latlon, ilat, ilon, w1, w2, w3;
   char w1s[7], w2s[7], w3s[7];
   printf("Starting figures:\n");
   lat = 28.3852;
   lon = -81.5638;
   printf("  latitude = %0.4f, longitude = %0.4f\n", lat, lon);

   // convert lat and lon to positive integers
   ilat = (int64)(lat*10000 + 900000);
   ilon = (int64)(lon*10000 + 1800000);

   // build 43 bit BigInt comprising 21 bits (lat) and 22 bits (lon)
   latlon = (ilat << 22) + ilon;
   // isolate relevant bits
   w1 = (latlon >> 28) & 0xefff;
   w2 = (latlon >> 14) & 0x7fff;
   w3 = latlon & 0x7fff;
   // convert to word format
   to_word(w1s, w1);
   to_word(w2s, w2);
   to_word(w3s, w3);

   // and print the results
   printf("\nThree word location is:\n");
   printf("  %s %s %s\n", w1s, w2s, w3s);
   /* now reverse the procedure */
   w1 = from_word(w1s);
   w2 = from_word(w2s);
   w3 = from_word(w3s);
   latlon = (w1 << 28) | (w2 << 14) | w3;
   ilat = latlon >> 22;
   ilon = latlon & 0xfffff;
   lat = (double)(ilat-900000) / 10000;
   lon = (double)(ilon-1800000) / 10000;
   // and print the results
   printf("\nAfter reversing the procedure:\n");
   printf("  latitude = %0.4f, longitude = %0.4f\n", lat, lon);
   return 0;

}</lang>

Output:
Starting figures:
  latitude = 28.3852, longitude = -81.5638

Three word location is:
  W18497 W27708 W01322

After reversing the procedure:
  latitude = 28.3852, longitude = -81.5638

Go

Translation of: Wren

Though no need for big integers as we have int64 built in. <lang go>package main

import (

   "fmt"
   "strconv"

)

func toWord(w int64) string { return fmt.Sprintf("W%05d", w) }

func fromWord(ws string) int64 {

   var u, _ = strconv.ParseUint(ws[1:], 10, 64)
   return int64(u)

}

func main() {

   fmt.Println("Starting figures:")
   lat := 28.3852
   lon := -81.5638
   fmt.Printf("  latitude = %0.4f, longitude = %0.4f\n", lat, lon)
   // convert lat and lon to positive integers
   ilat := int64(lat*10000 + 900000)
   ilon := int64(lon*10000 + 1800000)
   // build 43 bit BigInt comprising 21 bits (lat) and 22 bits (lon)
   latlon := (ilat << 22) + ilon
   // isolate relevant bits
   w1 := (latlon >> 28) & 0xefff
   w2 := (latlon >> 14) & 0x7fff
   w3 := latlon & 0x7fff
   // convert to word format
   w1s := toWord(w1)
   w2s := toWord(w2)
   w3s := toWord(w3)
   // and print the results
   fmt.Println("\nThree word location is:")
   fmt.Printf("  %s %s %s\n", w1s, w2s, w3s)
   /* now reverse the procedure */
   w1 = fromWord(w1s)
   w2 = fromWord(w2s)
   w3 = fromWord(w3s)
   latlon = (w1 << 28) | (w2 << 14) | w3
   ilat = latlon >> 22
   ilon = latlon & 0xfffff
   lat = float64(ilat-900000) / 10000
   lon = float64(ilon-1800000) / 10000
   // and print the results
   fmt.Println("\nAfter reversing the procedure:")
   fmt.Printf("  latitude = %0.4f, longitude = %0.4f\n", lat, lon)

}</lang>

Output:
Starting figures:
  latitude = 28.3852, longitude = -81.5638

Three word location is:
  W18497 W27708 W01322

After reversing the procedure:
  latitude = 28.3852, longitude = -81.5638

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

Idiomatic version

Output is the same as direct translation version. <lang julia> const LAT = 28.3852 const LON = -81.5638

  1. build word array W00000 ... W28125

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

function threewordencode(lat, lon) # returns vector of 3 strings

   i = (Int(lat * 10000 + 900000) << 22) | Int(lon * 10000 + 1800000)
   return map(x -> wordarray[x + 1], [(i >> 28) & 0xefff, (i >> 14) & 0x7fff, i & 0x7fff])

end

words = threewordencode(LAT, LON) println(join(words, " "))

function threeworddecode(w1, w2, w3) # returns pair of Float64

   (i1, i2, i3) = indexin([w1, w2, w3], wordarray) .- 1
   latlon = (i1 << 28) | (i2 << 14) | i3
   ilon, ilat = latlon & 0xfffff, latlon >> 22
   return  (ilon - 1800000) / 10000, (ilat - 900000) / 10000

end

lat, lon = threeworddecode(words...) println("latitude = $lat longitude = $lon") </lang>

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>

Wren

Library: Wren-fmt
Library: Wren-big

This just follows the steps in the task description though I couldn't see any point in creating a 28,126 element array when two simple functions will do.

Note that bitwise operations are limited to 32-bit unsigned integers in Wren which isn't big enough here so we use BigInts instead. <lang ecmascript>import "/fmt" for Fmt import "/big" for BigInt

// functions to convert to and from the word format 'W00000' var toWord = Fn.new { |w| Fmt.swrite("W$05d", w) } var fromWord = Fn.new { |w| Num.fromString(w[1..-1]) }

// set latitude and longitude and print them System.print("Starting figures:") var lat = 28.3852 var lon = -81.5638 Fmt.print(" latitude = $0.4f, longitude = $0.4f", lat, lon)

// convert lat and lon to positive BigInts var ilat = BigInt.new(lat * 10000 + 900000) var ilon = BigInt.new(lon * 10000 + 1800000)

// build 43 bit BigInt comprising 21 bits (lat) and 22 bits (lon) var latlon = (ilat << 22) + ilon

// isolate relevant bits and convert back to 'normal' ints var w1 = ((latlon >> 28) & 0xefff).toSmall var w2 = ((latlon >> 14) & 0x7fff).toSmall var w3 = (latlon & 0x7fff).toSmall

// convert to word format w1 = toWord.call(w1) w2 = toWord.call(w2) w3 = toWord.call(w3)

// and print the results System.print("\nThree word location is:") Fmt.print(" $s $s $s", w1, w2, w3)

/* now reverse the procedure */ w1 = BigInt.new(fromWord.call(w1)) w2 = BigInt.new(fromWord.call(w2)) w3 = BigInt.new(fromWord.call(w3)) latlon = (w1 << 28) | (w2 << 14) | w3 ilat = (latlon >> 22).toSmall ilon = (latlon & 0xfffff).toSmall lat = (ilat - 900000) / 10000 lon = (ilon - 1800000) / 10000

// and print the results System.print("\nAfter reversing the procedure:") Fmt.print(" latitude = $0.4f, longitude = $0.4f", lat, lon)</lang>

Output:
Starting figures:
  latitude = 28.3852, longitude = -81.5638

Three word location is:
  W18497 W27708 W01322

After reversing the procedure:
  latitude = 28.3852, longitude = -81.5638