Three word location: Difference between revisions
(Added C) |
|||
Line 366: | Line 366: | ||
</lang> |
</lang> |
||
{{out}} |
|||
<pre> |
|||
W18497 W11324 W01322 |
|||
latitude = 28.3852 longitude = -81.5638 |
|||
</pre> |
|||
=={{header|Wren}}== |
=={{header|Wren}}== |
Revision as of 17:35, 20 July 2020
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
<lang c>#include <stdio.h>
- 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
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>
- Three Word Location - convert latitude and longitude to three words
LAT = 28.3852 LON = -81.5638
- build word array W00000 ... W28125
wordarray = ["W" * string(x, pad=5) for x in 0:28125]
- make latitude and longitude positive integers
ILAT = Int(LAT * 10000 + 900000) ILON = Int(LON * 10000 + 1800000)
- build 43 bit integer containing latitude (21 bits) and longitude (22 bits)
LATLON = (ILAT << 22) + ILON
- isolate most significant 15 bits for word 1 index
- next 14 bits for word 2 index
- next 14 bits for word 3 index
W1 = (LATLON >> 28) & 0xefff W2 = (LATLON >> 14) & 0x7fff W3 = LATLON & 0x7fff
- fetch each word from word array
w1 = wordarray[W1 + 1] w2 = wordarray[W2 + 1] w3 = wordarray[W3 + 1]
- display words
println("$w1 $w2 $w3")
- reverse the procedure
- look up each word
(w1index, w2index, w3index) = indexin([w1, w2, w3], wordarray) .- 1
- build the latlon integer from the word indexes
latlon = (w1index << 28) | (w2index << 14) | w3index
- isolate the latitude and longitude
ilon = latlon & 0xfffff ilat = latlon >> 22
- convert back to floating point values
lon = (ilon - 1800000) / 10000 lat = (ilat - 900000) / 10000
- 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
- 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>
- Output:
W18497 W11324 W01322 latitude = 28.3852 longitude = -81.5638
Wren
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