Elixir は先月うまくいかなくてめげてしまったので、ここ最近は Go 言語に手を出している。ま、Web ページを見ながら見様見真似でやってるんだけど、言語の雰囲気はなんとなくわかったってところかな。OS ネイティブの実行ファイルが作れるのはいいね。ツールを作って他人に配るのにはいい。goroutine はよくわかんない。
で、ちょっと整数の素因数分解をするプログラムを作ってみた。
package main
import (
"fmt"
"os"
"flag"
"strconv"
)
func primes(n int) []int {
p := make([]bool, n + 1)
// スライス p はゼロ値(false)で初期化されるので、2 と 3 以上の奇数だけ true に初期化する。
if 2 < n {
p[2] = true
for i := 3; i <= n; i += 2 {
p[i] = true
}
}
// 3 以上の奇数を順にふるいにかける。
for i := 3; i * i < n; i += 2 {
if p[i] {
for j := i + i; j <= n; j += i {
p[j] = false
}
}
}
// 素数だけ pn に追加。
pn := make([]int, 0)
for i := 2; i <= n; i++ {
if p[i] {
pn = append(pn, i)
}
}
return pn
}
func primeFactors(n int) []int {
// n が合成数だと仮定すると、可能性として考えられる最大の素因数は n/2。
ps := primes(n / 2)
// n/2 以下の素数の中から素因数を探す。
facts := make([]int, 0)
for _, p := range ps {
for n != 1 {
if n % p == 0 {
facts = append(facts, p)
n = n / p
} else {
break
}
}
}
// n/2 までに素因数が見つからない場合、n 自身が素数。
if len(facts) == 0 {
facts = append(facts, n)
}
return facts
}
func main() {
Usage := func() {
fmt.Fprintf(os.Stderr, "Usage: %s \n", os.Args[0])
}
opt_help := flag.Bool("h", false, "Help message")
flag.Parse()
if *opt_help || flag.NArg() < 1 {
Usage() os.Exit(0)
}
n, err := strconv.Atoi(flag.Arg(0))
if err != nil {
fmt.Fprintln(os.Stderr, "Invalid argument.")
os.Exit(1)
}
if n < 2 {
fmt.Println("Nothing prime factors.")
} else {
f := primeFactors(n)
s := fmt.Sprintf("%v", f)
l := len(s) fmt.Println(s[1:l-1])
}
}
コンパイルせずにそのまま実行するには go run
コマンド。
^o^ > go run primefactors.go 12345
3 5 823
コンパイルするには go build
コマンド。
^o^ > go build primefactors.go
^o^ > ls
primefactors.exe primefactors.go
^o^ > primefactors 12345
3 5 823