Three word location: Difference between revisions

From Rosetta Code
Content added Content deleted
(changed an "language" section header to a "entry/solution version".)
(Added Wren)
Line 220: Line 220:


</lang>
</lang>

=={{header|Wren}}==
{{libheader|Wren-fmt}}
{{libheader|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>

{{out}}
<pre>
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
</pre>

Revision as of 10:03, 20 July 2020

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.


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