Go/コードギャラリー
このコードギャラリーは、さまざまなGoの機能やパターン、ベストプラクティスを示すためのサンプルコード集です。
エラトステネスの篩
[編集]package main import "fmt" func eratosthenes(n int) { sieve := make([]bool, n+1) for i := range sieve { sieve[i] = true } sieve[0] = false sieve[1] = false for i, isPrime := range sieve { if isPrime { for j := i * 2; j <= n; j += i { sieve[j] = false } } if i*i >= n { break } } for i, isPrime := range sieve { if isPrime { fmt.Print(i, " ") } } } func main() { eratosthenes(100) }
このGoのコードは、エラトステネスの篩を使って与えられた上限値以下の素数を見つけるものです。エラトステネスの篩は、素数を見つけるための古典的なアルゴリズムで、与えられた範囲内の素数を効率的に見つけることができます。
コードの主なポイントは次のとおりです:
eratosthenes
関数は、与えられた上限値n
以下の素数を見つけるための関数です。sieve
というブール型のスライスを作成し、初期値はすべてtrue
に設定されます。このスライスは素数かどうかを示すために使用されます。
sieve[0]
と sieve[1]
は素数ではないため、それぞれ false
に設定されます。
i
が2から始まり、n
までループします。もしisPrime
がtrue
(素数である)場合は、#i
を素数として出力し、その後の倍数をfalse
にします。これにより、素数の倍数は素数ではないとマークされます。- 内側のループでは、
i
の倍数をすべて篩い落とすため、j
をi
の倍数として増やしながらsieve[j]
をfalse
にしています。 main
関数では、eratosthenes
関数を呼び出して上限値が100以下の素数を見つけ、それを出力します。
このコードでは、エラトステネスの篩を用いて効率的に素数を見つける方法が示されています。
最大公約数と最小公倍数
[編集]package main import "fmt" func reduce(operation func(int, int) int, values []int) int { result := values[0] for _, value := range values[1:] { result = operation(result, value) } return result } func gcd2(m, n int) int { if n == 0 { return m } return gcd2(n, m%n) } func gcd(ints ...int) int { return reduce(gcd2, ints) } func lcm2(m, n int) int { return m * n / gcd2(m, n) } func lcm(ints ...int) int { return reduce(lcm2, ints) } func main() { fmt.Printf("gcd2(30, 45) => %d\n", gcd2(30, 45)) fmt.Printf("gcd(30, 72, 12) => %d\n", gcd(30, 72, 12)) fmt.Printf("lcm2(30, 72) => %d\n", lcm2(30, 72)) fmt.Printf("lcm(30, 42, 72) => %d\n", lcm(30, 42, 72)) }
このGoのコードは、最大公約数(GCD)と最小公倍数(LCM)を計算する関数を提供しています。これらの関数は、与えられた整数の配列を処理し、それぞれの計算を行います。
reduce
関数は、2つの引数を取り、指定された二項演算(operation
)をスライスの要素に対して適用するためのものです。result
は初期値として最初の要素(values[0]
)を取り、それ以降の要素に対してoperation
を適用していきます。- スライスの範囲演算子
values[1:]
を使用して、最初の要素を除いた残りの要素に対して操作を行います。
二分法
[編集]package main import ( "fmt" "math" ) func bisection(low, high float64, f func(float64) float64) float64 { x := (low + high) / 2 fx := f(x) if math.Abs(fx) < 1.0e-10 { return x } if fx < 0.0 { low = x } else { high = x } return bisection(low, high, f) } func main() { result1 := bisection(0, 3, func(x float64) float64 { return x - 1 }) fmt.Println(result1) result2 := bisection(0, 3, func(x float64) float64 { return x*x - 1 }) fmt.Println(result2) }
- 旧課程(-2012年度)高等学校数学B/数値計算とコンピューター#2分法の例を Go に移植しました。
このGoのコードは、2分法を用いて与えられた関数の数値解を求める方法を示しています。
bisection
関数
[編集]bisection
関数は、与えられた上限値と下限値の範囲内で数値解を見つけるためのものです。low
とhigh
は、数値解を探す範囲を示します。f
は、数値解を求めたい関数です。x := (low + high) / 2
で、範囲の中間点を計算します。fx := f(x)
で、関数f
を中間点x
に適用し、その結果をfx
に代入します。math.Abs(fx) < 1.0e-10
は、絶対値が非常に小さい値となった場合、つまり数値解が見つかった場合の条件です。この場合、x
を返して探索を終了します。fx < 0.0
の場合は、low
の範囲をx
に設定し、それ以外の場合はhigh
の範囲をx
に設定します。これにより、次の探索範囲を絞り込んでいきます。- 最後に、絞り込まれた新しい範囲で再帰的に
bisection
関数を呼び出します。
main
関数
[編集]main
関数では、bisection
関数を使用して数値解を求めます。- まず、
x - 1
という関数に対して2分法を適用し、数値解を見つけます。次に、x^2 - 1
という関数に対しても同様の手順で数値解を見つけます。 - それぞれの数値解を出力しています。
このコードは、数値解を見つけるための2分法を実装し、与えられた関数に対して数値解を計算する方法を示しています。
構造体とメソッド
[編集]Goにクラスはありませんが、構造体がメソッドを持つことが出来ます。
package main import "fmt" // Hello 構造体 type Hello struct { s string // 挨拶文に含める文字列 } // NewHello Hello構造体のコンストラクタ func NewHello(s string) *Hello { if s == "" { s = "world" // デフォルト値を設定 } return &Hello{s: s} } // ToString 挨拶文を文字列で表現するメソッド func (h *Hello) ToString() string { return fmt.Sprintf("Hello %s!", h.s) } // Print 挨拶文を出力するメソッド func (h *Hello) Print() { fmt.Println(h.s) } func main() { hello1 := NewHello("") fmt.Println(hello1.ToString()) hello1.Print() hello2 := NewHello("my friend") fmt.Println(hello2.ToString()) hello2.Print() fmt.Printf(` Hello.constructor.name => Hello hello1 => %+v hello2.s => %s `, hello1, hello2.s) }
このGoのコードは、Hello
構造体を定義し、それに関連する関数とメソッドを使って挨拶文を扱う方法を示しています。
Hello
構造体と NewHello
コンストラクタ
[編集]Hello
構造体は、挨拶文に含める文字列s
を持ちます。NewHello
関数は、Hello
構造体のコンストラクタです。引数が空の場合はデフォルトで "world" を設定します。
ToString
メソッド
[編集]ToString
メソッドは、Hello
構造体のメソッドです。挨拶文を文字列で表現します。
Print
メソッド
[編集]Print
メソッドは、Hello
構造体のメソッドで、挨拶文を出力します。
main
関数
[編集]main
関数では、NewHello
コンストラクタを使って2つのHello
インスタンスを作成します。- それぞれのインスタンスに対して
ToString
メソッドを呼び出し、挨拶文を表示します。 - 同様に、
Print
メソッドを呼び出して挨拶文を出力します。 Printf
関数を使用して、コンストラクタの名前、hello1
の詳細情報、およびhello2
の文字列を出力します。
このコードは、Go言語でクラスの代わりに構造体とメソッドを使用して、オブジェクト指向プログラミングの概念を模倣しています。それぞれのメソッドは、構造体のインスタンスに結びついており、そのインスタンスに対して操作を行います。
逆ポーランド記法の解析と評価
[編集]逆ポーランド記法は、数式の演算子を後置記法で表現する方法です。通常の中置記法では演算子がオペランドの間に置かれますが、逆ポーランド記法では演算子がオペランドの後ろに置かれます。これにより、括弧や演算子の優先順位を考える必要がなくなり、計算機で容易に評価できる形式になります。
例えば、中置記法での式 3 + 4 * 5
は、逆ポーランド記法では 3 4 5 * +
と表現されます。この記法では、演算子が対象のオペランドに対して順番に適用されます。
package main import ( "fmt" "strconv" "strings" ) func evaluateExpression(expression string) (int, error) { tokens := strings.Fields(expression) stack := make([]int, 0) for _, token := range tokens { switch token { case "+", "-", "*", "/": if len(stack) < 2 { return 0, fmt.Errorf("invalid expression: not enough operands for %s operator", token) } operand2 := stack[len(stack)-1] operand1 := stack[len(stack)-2] stack = stack[:len(stack)-2] var result int switch token { case "+": result = operand1 + operand2 case "-": result = operand1 - operand2 case "*": result = operand1 * operand2 case "/": if operand2 == 0 { return 0, fmt.Errorf("division by zero") } result = operand1 / operand2 } stack = append(stack, result) default: num, err := strconv.Atoi(token) if err != nil { return 0, fmt.Errorf("invalid expression: %v is not a number", token) } stack = append(stack, num) } } if len(stack) != 1 { return 0, fmt.Errorf("invalid expression: too many operands or operators") } return stack[0], nil } func main() { expression := "5 3 2 * + 8 2 / -" result, err := evaluateExpression(expression) if err != nil { fmt.Println("Error:", err) } else { fmt.Println("Result:", result) } }
このGoのコードは、逆ポーランド記法(逆ポーランド式、Postfix Notation)を使用して算術式を評価します。
evaluateExpression
関数
[編集]evaluateExpression
関数は、逆ポーランド記法の式を受け取り、計算結果とエラーを返す関数です。- 式をトークンに分割し、それぞれのトークンをスタックに積んでいきます。
- 演算子を見つけた場合は、スタックから必要な数のオペランドを取り出して、演算を行います。その結果をスタックに戻します。
- 数字を見つけた場合は、文字列から整数に変換してスタックに積みます。
- 除算 (
/
) の際にゼロで割り算が発生しないように注意しています。
main
関数
[編集]main
関数では、evaluateExpression
関数を使用して、与えられた逆ポーランド記法の式を評価します。- 式
"5 3 2 * + 8 2 / -"
を評価し、結果を出力します。
このプログラムは、逆ポーランド記法を使用して四則演算を行う方法を示しています。それぞれの演算子や数値をトークンとして扱い、スタックを使用して計算を進めます。計算結果を正しく得るために、演算子とオペランドの関係性を考慮して処理しています。