このコードギャラリーは、さまざまなGoの機能やパターン、ベストプラクティスを示すためのサンプルコード集です。

エラトステネスの篩

編集
// Package main は、エラトステネスの篩アルゴリズムを用いて
// 指定された範囲内の素数を列挙するプログラムを提供します。
package main

import "fmt"

// eratosthenes 関数は、エラトステネスの篩を用いて指定された上限 n までの
// 素数を計算し、結果を標準出力に表示します。
//
// n: 素数を計算する範囲の上限 (2 以上の整数)。
func eratosthenes(n int) {
	// 篩 (sieve) を表すスライスを作成し、初期値としてすべてを true に設定
	sieve := make([]bool, n+1)
	for i := 2; i < len(sieve); i++ {
		sieve[i] = true
	}

	// 素数判定を行い、合成数 (素数でない数) を false に設定
	for i, isPrime := range sieve {
		if isPrime {
			// i の倍数を合成数として篩い落とす
			for j := i * i; j <= n; j += i {
				sieve[j] = false
			}
		}
		// 最適化: i*i が n を超えた時点でループを終了
		if i*i >= n {
			break
		}
	}

	// 篩の結果に基づき、素数を標準出力に列挙
	for i, isPrime := range sieve {
		if isPrime {
			fmt.Print(i, " ")
		}
	}
}

// main 関数は、eratosthenes 関数を利用して、
// 100 以下の素数を列挙します。
func main() {
	eratosthenes(100) // 100 以下の素数を出力
}

このGoのコードは、エラトステネスの篩を使って与えられた上限値以下の素数を見つけるものです。エラトステネスの篩は、素数を見つけるための古典的なアルゴリズムで、与えられた範囲内の素数を効率的に見つけることができます。

最大公約数と最小公倍数

編集
// Package main は、2つ以上の整数に対して最大公約数 (GCD) と
// 最小公倍数 (LCM) を計算するユーティリティ関数を提供します。
package main

import "fmt"

// reduce 関数は、可変長引数で渡された値に対して指定された2引数関数 (operation) を
// 初期値 (result) を基点として順次適用し、累積結果を計算します。
//
// operation: 2つの整数を引数に取り結果を返す関数。
// result: 初期値。
// values: 可変長引数として渡される整数リスト。
func reduce(operation func(int, int) int, result int, values ...int) int {
	for _, value := range values {
		result = operation(result, value)
	}
	return result
}

// gcd2 関数は、2つの整数に対してユークリッドの互除法を用いて
// 最大公約数 (GCD) を計算します。
//
// m, n: 最大公約数を求める対象の2つの整数。
// 戻り値: m と n の最大公約数。
func gcd2(m, n int) int {
	if n == 0 {
		return m
	}
	return gcd2(n, m%n)
}

// gcd 関数は、2つ以上の整数に対して reduce 関数を利用して
// 順次 gcd2 を適用し、最終的な最大公約数を計算します。
//
// ints: 最大公約数を求める対象の整数リスト (可変長引数)。
// 戻り値: 引数で与えられた全ての整数の最大公約数。
func gcd(ints ...int) int {
	return reduce(gcd2, ints[0], ints[1:]...)
}

// lcm2 関数は、2つの整数に対して最大公約数 (GCD) を利用して
// 最小公倍数 (LCM) を計算します。
//
// m, n: 最小公倍数を求める対象の2つの整数。
// 戻り値: m と n の最小公倍数。
func lcm2(m, n int) int {
	return m * n / gcd2(m, n)
}

// lcm 関数は、2つ以上の整数に対して reduce 関数を利用して
// 順次 lcm2 を適用し、最終的な最小公倍数を計算します。
//
// ints: 最小公倍数を求める対象の整数リスト (可変長引数)。
// 戻り値: 引数で与えられた全ての整数の最小公倍数。
func lcm(ints ...int) int {
	return reduce(lcm2, ints[0], ints[1:]...)
}

// main 関数は、gcd2, gcd, lcm2, lcm 関数の使用例を示します。
// サンプルデータを使用して計算結果を標準出力に表示します。
func main() {
	fmt.Printf("gcd2(30, 45) => %d\n", gcd2(30, 45))       // 30と45の最大公約数を出力
	fmt.Printf("gcd(30, 72, 12) => %d\n", gcd(30, 72, 12)) // 30, 72, 12の最大公約数を出力
	fmt.Printf("lcm2(30, 72) => %d\n", lcm2(30, 72))       // 30と72の最小公倍数を出力
	fmt.Printf("lcm(30, 42, 72) => %d\n", lcm(30, 42, 72)) // 30, 42, 72の最小公倍数を出力
}

このGoのコードは、最大公約数(GCD)と最小公倍数(LCM)を計算する関数を提供しています。これらの関数は、与えられた整数の配列を処理し、それぞれの計算を行います。

二分法

編集

二分法

// Package main は、数値解析の手法である二分法を利用して関数の根 (ゼロ点) を
// 求めるユーティリティを提供します。
package main

import (
	"fmt"
	"math"
)

// bisection 関数は、与えられた範囲 [low, high] 内で関数 f の根を探索します。
// 二分法を用い、関数 f の値がゼロに収束する点を再帰的に計算します。
//
// low: 探索範囲の下限値。
// high: 探索範囲の上限値。
// f: 根を求めたい関数 (float64 を引数とし、float64 を返す関数)。
// 戻り値: 関数 f の根の近似値。
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)
}

// main 関数は、bisection 関数を利用してサンプル関数の根を求め、結果を出力します。
func main() {
	// サンプル関数 f(x) = x - 1 の根を探索
	result1 := bisection(0, 3, func(x float64) float64 {
		return x - 1
	})
	fmt.Println(result1) // 出力: 1.0 (近似値)

	// サンプル関数 f(x) = x^2 - 1 の根を探索
	result2 := bisection(0, 3, func(x float64) float64 {
		return x*x - 1
	})
	fmt.Println(result2) // 出力: 1.0 (近似値)
}
旧課程(-2012年度)高等学校数学B/数値計算とコンピューター#2分法の例を Go に移植しました。

このGoのコードは、2分法を用いて与えられた関数の数値解を求める方法を示しています。

構造体とメソッド

編集

Goにクラスはありませんが、構造体がメソッドを持つことが出来ます。

package main

import "fmt"

// Hello 構造体
type Hello struct {
	s string // 挨拶文に含める文字列
}

// Hello構造体を返す関数
// コンストラクタに相当しますがメソッドではありません
func NewHello(args ...string) (hello *Hello) {
	// デフォルト値
	hello = &Hello{
		s: "world",
	}
	if len(args) > 0 {
		hello.s = args[0]
	}
	return
}

// Stringerインターフェースを実装
// String()メソッドを定義すると string への暗黙型変換で使われます
func (h *Hello) String() string {
	return fmt.Sprintf("Hello %s!", h.s)
}

func main() {
	hello1 := NewHello()
	fmt.Println(hello1)

	hello2 := NewHello("my friend")
	fmt.Println(hello2)
}
  1. Goには「クラス」はありませんが、構造体にメソッドを定義できます。
  2. NewHello()関数は、コンストラクタに相当しますが、厳密にはGoのメソッドではなく、Hello構造体のインスタンスを生成する関数です。
  3. String()メソッドはStringerインターフェースを実装しており、文字列への暗黙の型変換で使用されます。
  4. メソッドは構造体のインスタンスに結びついており、そのインスタンスに対して操作を行います。
  5. レシーバ(h *Hello)を使用して、メソッドを特定の構造体型に関連付けています。

逆ポーランド記法の解析と評価

編集

逆ポーランド記法は、数式の演算子を後置記法で表現する方法です。通常の中置記法では演算子がオペランドの間に置かれますが、逆ポーランド記法では演算子がオペランドの後ろに置かれます。これにより、括弧や演算子の優先順位を考える必要がなくなり、計算機で容易に評価できる形式になります。

例えば、中置記法での式 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 / -" を評価し、結果を出力します。

このプログラムは、逆ポーランド記法を使用して四則演算を行う方法を示しています。それぞれの演算子や数値をトークンとして扱い、スタックを使用して計算を進めます。計算結果を正しく得るために、演算子とオペランドの関係性を考慮して処理しています。