Hero Image
球面三角法による2点間の距離計算をGoで実装してみた

はじめに バックエンドエンジニアのロードマップに沿ってエンジニアとしての自己肯定感を養うシリーズです。 地球上の2点間の距離計算ってアプリだと Google Map API を使えば完了!だと思いますが、どう計算してるかって気になりますよね? 今回は球面三角法を利用した地球上の2点間の距離計算を Go で実装します。(調べたらフツーにあるんですが) 球面三角法とは その名の通り、三角関数を利用して球面上の辺や角の大きさを導出するものです。平面と球面とでの違いは辺の大きさが 球面では中心角によって表されることにあります。 よって、球面三角法を使用して算出した弧の長さ(中心角)と赤道の半径を乗算すると距離が求まります。 球面三角法の証明については、球面三角形の定理を参考にしました! (“高校生に向けて"とある通り、非常にわかりやすかったです) 球面三角法の余弦定理を利用して実際に距離を算出する方法は球面三角法の余弦定理がわかりやすいです。 実装 実装したソースコードは Github でも確認できます。 球面三角法を利用した2点間の距離計算 package main import "math" // Coordinate 緯度経度 type Coordinate struct { Longitude float64 Latitude float64 } // EarthRadius 赤道半径 const EarthRadius = 6378140 // DistanceOnTheEarth 地球上の 2 点間の距離を出す(球面三角法) func DistanceOnTheEarth(from, to Coordinate) float64 { fromLadLon := from.Longitude * math.Pi / 180 fromLadLat := from.Latitude * math.Pi / 180 toLadLon := to.Longitude * math.Pi / 180 toLadLat := to.Latitude * math.Pi / 180 alpha := math.Sin(fromLadLat)*math.Sin(toLadLat) + math.Cos(fromLadLat)*math.Cos(toLadLat)*math.Cos(fromLadLon-toLadLon) arcAlpha := math.Acos(alpha) return arcAlpha * EarthRadius / 1000 } 動かしてみる それでは実装した Go の関数を呼び出す簡単なアプリを動かしていきます。

Hero Image
ソートアルゴリズムをGoで実装してみた

はじめに バックエンドエンジニアのロードマップに沿ってエンジニアとしての自己肯定感を養うシリーズです。 マージソート マージソートは、ソートのアルゴリズムで、既に整列してある複数個の列を 1 個の列にマージする際に、小さいものから先に新しい列に並べれば、新しい列も整列されている、というボトムアップの分割統治法による。大きい列を多数の列に分割し、そのそれぞれをマージする作業は並列化できる。 出典:wikipedia「マージソート」より引用 最悪の計算量が O(n log n) であるから少なくとも O(n^2)よりは速いんだろうなという印象(雑すぎるか) 以下「ソートを極める! 〜 なぜソートを学ぶのか 〜」を元に実装してみた(なるべくソースを見ないで実装を試みたがマージする箇所は折れた、、) package main import ( "fmt" "time" "github.com/uh-zz/traning/algorithm/shuffle" ) func main() { // ランダムな要素 n 個のスライス取得 input := shuffle.RandomIntList(n) inputLength := len(input) // マージソート MergeSort(&input, 0, inputLength) } // MergeSort マージソート func MergeSort(input \*[]int, left, right int) { // 要素数1つの場合は抜ける if right-left == 1 { return } // 配列を2つに分けるインデックス middle := left + (right-left)/2 // 配列左側 MergeSort(input, left, middle) // 配列右側 MergeSort(input, middle, right) var buffer []int // 左側と右側をバッファにためる(右側反転) for index := left; index < middle; index++ { buffer = append(buffer, (*input)[index]) } for index := right - 1; index >= middle; index-- { buffer = append(buffer, (*input)[index]) } // マージする scopeLeft := 0 scopeRight := len(buffer) - 1 for index := left; index < right; index++ { if buffer[scopeLeft] <= buffer[scopeRight] { // 左側採用 (*input)[index] = buffer[scopeLeft] scopeLeft++ } else { // 右側採用 (*input)[index] = buffer[scopeRight] scopeRight-- } } } これ考えたのぶっ飛んでるなあと思って Wikipedia 見てたら、考案者がフォン・ノイマンでやっぱりぶっ飛んでた(凄すぎ)