Go言語(Golang)は、Googleによって開発された非常にシンプルで効率的なプログラミング言語です。
システム開発からクラウドネイティブなアプリケーション開発まで幅広く利用されており、その計算処理の基本となるのが四則演算です。
プログラミングを学ぶ上で、数値計算は避けて通れない要素であり、Go言語特有の厳密な型システムを理解することが重要になります。
本記事では、Go言語における基本的な四則演算から、演算子の使い方、型変換(キャスト)時の注意点について詳しく解説します。
これからGo言語を学び始める方や、計算処理の実装で迷っている方は、ぜひ参考にしてください。
Go言語における基本的な四則演算子
Go言語で数値を扱う際、最も頻繁に使用するのが四則演算子です。
四則演算子には、加算、減算、乗算、除算、そして剰余の5種類が存在します。
これらの演算子は数学で使われる記号とほぼ同じですが、プログラミング特有の挙動も含まれています。
まずは、それぞれの演算子がどのような役割を持つのかを整理しましょう。
| 演算子 | 意味 | 使用例 |
|---|---|---|
+ | 加算(足し算) | a + b |
- | 減算(引き算) | a - b |
* | 乗算(掛け算) | a * b |
/ | 除算(割り算) | a / b |
% | 剰余(割り切った余り) | a % b |
これらの演算子は、整数(int型)だけでなく、浮動小数点数(float型)にも使用できます。
ただし、剰余演算子(%)については整数型のみに適用可能であり、浮動小数点数には使用できない点に注意してください。
実際のコード例を見て、どのように記述するかを確認しましょう。
package main
import "fmt"
func main() {
// 変数の宣言
a := 10
b := 3
// 各演算の実行
fmt.Println("加算:", a + b)
fmt.Println("減算:", a - b)
fmt.Println("乗算:", a * b)
fmt.Println("除算:", a / b)
fmt.Println("剰余:", a % b)
}
加算: 13
減算: 7
乗算: 30
除算: 3
剰余: 1
上記の実行結果を見ると、除算の結果が「3」になっていることがわかります。
これは、整数同士の計算結果は必ず整数になるというGo言語の仕様によるものです。
小数点以下の結果が必要な場合は、後述する型変換を適切に行う必要があります。
代入演算子と複合代入演算子の使い方
計算結果を同じ変数に再代入する場合、コードを簡潔に書くための「複合代入演算子」が用意されています。
例えば、a = a + 5 という記述は、a += 5 と短縮して書くことが可能です。
これにより、タイピング量を減らすだけでなく、コードの可読性を高めることができます。
| 演算子 | 意味 | 展開した形 |
|---|---|---|
+= | 加算代入 | a = a + b |
-= | 減算代入 | a = a - b |
*= | 乗算代入 | a = a * b |
/= | 除算代入 | a = a / b |
%= | 剰余代入 | a = a % b |
複合代入演算子を利用する際も、元の変数のデータ型が維持される点に留意してください。
以下に、具体的なプログラム例を示します。
package main
import "fmt"
func main() {
count := 10
count += 5 // 10 + 5
fmt.Println("加算代入後:", count)
count *= 2 // 15 * 2
fmt.Println("乗算代入後:", count)
count /= 3 // 30 / 3
fmt.Println("除算代入後:", count)
}
加算代入後: 15
乗算代入後: 30
除算代入後: 10
このように、一つの変数値を変形させていくような処理(カウンタの更新など)では、複合代入演算子が非常に便利です。
インクリメント・デクリメントの注意点
変数の値を 1 増やしたり減らしたりする操作を、インクリメント(++)およびデクリメント(–)と呼びます。
Go言語におけるこれらの演算子は、他の言語(C言語やJavaなど)とは異なる制約があります。
まず、Go言語のインクリメント・デクリメントは「文(Statement)」であり「式(Expression)」ではありません。
そのため、fmt.Println(i++) のように、他の関数の中や代入式の右辺に直接記述することはできません。
また、前置インクリメント(++i)は存在せず、後置インクリメント(i++)のみが許可されています。
package main
import "fmt"
func main() {
i := 0
i++ // 正しい使い方
fmt.Println("iの値:", i)
// j := i++ // これはエラーになります
// ++i // これもエラーになります
}
このように制限を設けることで、コードの意図が明確になり、複雑な副作用を避ける設計になっています。
Go言語における厳密な型システムと四則演算
Go言語の最大の特徴の一つは、異なる型同士の計算が厳密に禁止されている点です。
たとえ int32 型と int64 型のように、同じ整数同士であっても、明示的な型変換なしに計算することはできません。
これは、意図しない精度の損失やバグを防ぐための強力な仕組みです。
整数と浮動小数点数の混在
例えば、整数の変数と浮動小数点数の変数を掛け合わせる場合、コンパイルエラーが発生します。
計算を行う前に、どちらかの型にもう一方を合わせる必要があります。
package main
import "fmt"
func main() {
var price int = 100
var tax float64 = 1.1
// 以下の行はコンパイルエラーになります
// total := price * tax
// float64型に変換して計算する
total := float64(price) * tax
fmt.Println("合計金額:", total)
}
計算の精度を重視する場合は、より精度の高い float64 型に合わせるのが一般的です。
逆に、結果を整数で得たい場合は、最終的な結果を int() で囲んで変換します。
除算における精度の注意点
先ほど触れた通り、整数同士の除算(/)は、結果も整数になります。
例えば 5 / 2 は 2.5 ではなく 2 になります。
もし 2.5 という結果を得たい場合は、計算対象の数値を浮動小数点数として扱う必要があります。
package main
import "fmt"
func main() {
a := 5
b := 2
fmt.Println("整数除算:", a / b)
fmt.Println("浮動小数点除算:", float64(a) / float64(b))
}
整数除算: 2
浮動小数点除算: 2.5
リテラル(定数)を用いた計算の場合、型推論によって自動的に適切に処理されることもあります。
しかし、変数を通した計算では常に型を意識することが、Go言語のコーディングにおける鉄則です。
mathパッケージを利用した高度な計算
基本的な四則演算子だけでは、べき乗(累乗)や平方根、絶対値などの計算を行うことができません。
これらの高度な数学的計算には、Go言語の標準ライブラリである math パッケージを利用します。
math パッケージの多くの関数は float64 型を引数に取り、結果も float64 型で返します。
package main
import (
"fmt"
"math"
)
func main() {
x := 2.0
y := 8.0
fmt.Println("2の3乗:", math.Pow(x, 3))
fmt.Println("64の平方根:", math.Sqrt(64))
fmt.Println("-10の絶対値:", math.Abs(-10))
fmt.Println("xとyの大きい方:", math.Max(x, y))
}
浮動小数点数を扱う際は、値の切り上げ(Ceil)や切り捨て(Floor)なども頻繁に利用されます。
これらの関数もすべて math パッケージに含まれているため、数値計算が中心のプログラムでは必ずインポートすることになるでしょう。
浮動小数点数の計算と精度の問題
コンピュータ内部では数値をバイナリ(2進数)で管理しているため、浮動小数点数の計算には常に「精度誤差」が伴います。
例えば、0.1 + 0.2 が正確に 0.3 にならないという問題は、Go言語に限らず多くのプログラミング言語で共通の事象です。
package main
import "fmt"
func main() {
fmt.Println(0.1 + 0.2)
}
0.30000000000000004
金銭計算など、1円の狂いも許されないシステムにおいて float64 を直接使用するのは避けるべきです。
そのような場合は、値を最小単位(「円」ではなく「セント」や「ミリ単位」)まで整数にして扱うか、多倍長精度演算をサポートするパッケージを利用します。
Go言語では標準で math/big パッケージが提供されており、非常に大きな数値や精度の高い計算が可能です。
演算の優先順位(優先順位表)
複数の演算子が混在する数式では、どの計算が先に行われるかのルールが決まっています。
数学のルールと同様に、掛け算や割り算は足し算や引き算よりも先に計算されます。
意図した順序で計算させたい場合は、()(丸括弧)を使用して明示的に優先順位を指定しましょう。
| 優先順位 | 演算子 |
|---|---|
| 5 (高い) | *, /, %, <<, >>, &, &^ |
| 4 | +, -, |, ^ |
| 3 | ==, !=, <, <=, >, >= |
| 2 | && |
| 1 (低い) | || |
例えば、result := (10 + 5) * 2 と記述すれば、足し算が最初に行われ、結果は 30 になります。
括弧がない 10 + 5 * 2 の場合は 20 になるため、計算式が複雑になる場合は常に括弧を使う習慣をつけるのが安全です。
オーバーフローへの対策
整数型には扱える数値の範囲が決まっており、その範囲を超えると「オーバーフロー」が発生します。
例えば、uint8 型は 0 から 255 までの数値しか保持できません。
255 に 1 を加算すると、エラーにならずに 0 に戻ってしまうのがGo言語のデフォルトの挙動です。
package main
import "fmt"
func main() {
var n uint8 = 255
fmt.Println("加算前:", n)
n = n + 1
fmt.Println("加算後(オーバーフロー):", n)
}
大規模なデータを扱う場合や累積値を計算する場合は、十分な容量を持つ int64 型や float64 型を選択することが重要です。
実行時にエラーを投げないため、数値の範囲を事前に把握しておく設計が必要となります。
まとめ
Go言語における四則演算は、非常にシンプルでありながら、型システムに関しては非常に厳格な設計思想を持っています。
整数同士の計算では結果が切り捨てられる点や、異なる型を混ぜて計算できない点は、初心者が最初につまずきやすいポイントです。
しかし、この厳格さこそが、大規模なプロジェクトにおいて計算ミスの少ない堅牢なコードを維持するための鍵となります。
まずは int と float64 の変換に慣れ、必要に応じて math パッケージを使いこなせるようになりましょう。
本記事で学んだ基本を土台に、実際のプログラムの中で正確な数値処理を実装してみてください。
