Golang における数値型 (Numerical Types)

GolangBeginner
オンラインで実践に進む

はじめに

Gopher の皆さん、新しい章へようこそ。このセクションでは、数値型について学びます。内容には、一般的に使用される整数型、浮動小数点型、ブール型、そして複素数、およびバージョン 1.13 で導入されたリテラル値の構文が含まれます。

学習ポイント:

  • 整数型 (Integer types)
  • 浮動小数点型 (Floating-point types)
  • ブール型 (Boolean types)
  • 複素数 (Complex numbers)
  • リテラル値の構文 (Literal value syntax)

整数型 (Integers)

整数 (Integers) は、大きく分けて符号なし整数 (Unsigned integers) と符号付き整数 (Signed integers) の 2 つのカテゴリに分類できます。符号付き整数 (Signed integers) が最も広く使用されています。

符号なし (Unsigned) とは、非負の数 (0 と正の数) のみを表現できることを意味し、符号付き (Signed) の数は、負の数と非負の数の両方を表現できます。

符号なし整数 (Unsigned integers) は、8 ビット、16 ビット、32 ビット、および 64 ビットの 4 つのサイズに分割でき、それぞれ uint8uint16uint32、および uint64 で表されます。対応する符号付き整数 (Signed integers) は、int8int16int32、および int64 です。次の表は、各型が表現できるさまざまな範囲を示しています。

型 (Type) 説明 (Description) 範囲 (Range)
uint8 8 ビット符号なし整数 (8-bit unsigned int) 0 ~ 255
int8 8 ビット符号付き整数 (8-bit signed int) -128 ~ 127
uint16 16 ビット符号なし整数 (16-bit unsigned int) 0 ~ 65535
int16 16 ビット符号付き整数 (16-bit signed int) -32768 ~ 32767
uint32 32 ビット符号なし整数 (32-bit unsigned int) 0 ~ 4294967295
int32 32 ビット符号付き整数 (32-bit signed int) -2147483648 ~ 2147483647
uint64 64 ビット符号なし整数 (64-bit unsigned int) 0 ~ 18446744073709551615
int64 64 ビット符号付き整数 (64-bit signed int) -9223372036854775808 ~ 9223372036854775807

uint8int8 を例にとってみましょう。これらはどちらも 8 ビット整数 (8-bit integers) であり、256 個の値を表現できます。符号なし整数型 (Unsigned integer type) uint8 では、表現できる範囲は 0 から 255 ですが、符号付き整数型 (Signed integer type) int8 では、表現できる範囲は -128 から 127 です。

上記の 8 つの型に加えて、uintint、および uintptr の 3 つの特別な整数型 (integer types) があります。uintint はプラットフォームによって異なる範囲を表す場合があり、uintptr はポインタアドレス (pointer address) を格納するために使用されます。

型 (Type) 範囲 (Range)
uint 32 ビットシステムでは uint32、64 ビットシステムでは uint64
int 32 ビットシステムでは int32、64 ビットシステムでは int64
uintptr ポインタアドレス (pointer address) を格納するために使用される符号なし整数型 (Unsigned integer type)。主に unsafe 操作のような低レベルプログラミングで使用されます

次に、integer.go という名前のファイルを作成して、整数 (integers) の使用法を示します。

cd ~/project
touch integer.go
package main

import (
    "fmt"
    "unsafe"
)

func main() {
    // View the type of int in the current environment
    // Declare a as the type int
    var a int
    // Use unsafe.Sizeof() to output the memory size occupied by the type
    fmt.Printf("The type int in the current environment is %d bits\n", unsafe.Sizeof(a)*8)

    var b int8 = 125
    // Use the %d placeholder in fmt.Printf to output the value of the integer
    // Use the %T placeholder in fmt.Printf to output the type of the variable
    fmt.Printf("The value of b is %d, and the type is %T\n", b, b)

    // Integer operations
    // Declare integers c and d, and calculate their sum
    c, d := 2, 3
    fmt.Printf("c + d = %d\n", c+d)
    // 10 - 5
    fmt.Printf("10 - 5 = %d\n", 10-5)
    // 8 * 10
    fmt.Printf("8 * 10 = %d\n", 8*10)

    // Example of uintptr usage - storing an address
    var ptr uintptr
    x := 42
    // Convert the pointer to x to uintptr
    ptr = uintptr(unsafe.Pointer(&x))
    fmt.Printf("The address of x stored in ptr is: %v\n", ptr)
}

プログラムを実行すると、次の出力が得られます。

go run integer.go
The type int in the current environment is 64 bits
The value of b is 125, and the type is int8
c + d = 5
10 - 5 = 5
8 * 10 = 80
The address of x stored in ptr is: 824634818784

出力の説明:

  • The type int in the current environment is 64 bits: この行は、コードが実行されているシステムの int 型 (type) が 64 ビット (または 8 バイト) であることを示しています。これは int64 であることを示しています。unsafe.Sizeof(a) は変数 a のサイズをバイト単位で返し、8 を掛けることでビットに変換します。これは、int 型 (type) がより大きな整数値 (integer values) を保持できることを意味します。
  • The value of b is 125, and the type is int8: ここでは、int8 型 (type) の変数 b を宣言し、それに値 125 を割り当てました。出力は、値とデータ型の両方を示すことで、これを確認します。
  • c + d = 5, 10 - 5 = 5, 8 * 10 = 80: これらの行は、基本的な整数演算 (integer arithmetic operations) (加算、減算、乗算) を示しています。出力は、これらの計算の正しい結果を確認します。
  • The address of x stored in ptr is: 824634818784: これは、uintptr を使用してメモリアドレス (memory address) を格納する方法を示しています。整数変数 (integer variable) x へのポインタ (pointer) を uintptr 型 (type) に変換しています。実際のアドレス値 (address value) は、プログラムが実行されるたびに異なります。これは、unsafe 操作やシステムプログラミングで通常見られる高度な使用例です。

このファイルでは、unsafe.Sizeof() 関数を使用して、現在の変数の型 (variable type) が占めるバイト数を取得できます。1 バイト (byte) は 8 ビットに等しいため、unsafe.Sizeof()*8 は、型 (type) が占めるビット数を取得できます。出力から、オンライン環境が 64 ビットであることがわかります。オンライン環境での int の実際の型 (type) は int64 です。

ターミナルで次のコマンドを使用して、現在のシステムアーキテクチャ (system architecture) を確認できます。

dpkg --print-architecture
amd64

浮動小数点数 (Floating-Point Numbers)

浮動小数点数 (Floating-point numbers) は、Go では float32float64 の 2 つの型を使用して、小数部を持つ実数を表します。デフォルトの浮動小数点型 (floating-point type) は float64 です。

float32float64 は、異なる精度 (precision) を表します。float64 のデフォルトの精度 (precision) は、float32 よりも高くなっています。

IEEE 754 規格 (IEEE 754 standard) は、コンピュータで最も広く使用されている浮動小数点計算規格 (floating-point calculation standard) であり、最新の CPU はすべてこの規格をサポートしています。他のプログラミング言語と同様に、Go も IEEE 754 を使用して浮動小数点数 (floating-point numbers) を格納します。

コンピュータの 1 バイト (byte) が 8 ビット (bits) を格納できることはご存知でしょう。float32 は単精度浮動小数点数 (single-precision floating-point number) であり、4 バイト (bytes) (32 ビット (bits)) を占有します。float64 は倍精度 (double-precision) であり、8 バイト (bytes) (64 ビット (bits)) を占有します。

float32 では、符号ビット (sign bit) が 1 ビット (bit) を占有し、指数部 (exponent) が 8 ビット (bits) を占有し、残りの 23 ビット (bits) が仮数部 (mantissa) を表すために使用されます。

float64 では、符号ビット (sign bit) も 1 ビット (bit) を占有し、指数部 (exponent) が 11 ビット (bits) を占有し、残りの 52 ビット (bits) が仮数部 (mantissa) を表すために使用されます。

float32 が表現できる最大値 (maximum value) は、科学表記法 (scientific notation) で約 3.4e+38 であり、最小値 (minimum value) は 1.4e-45 です。float64 が表現できる最大値 (maximum value) は、約 1.8e+308 であり、最小値 (minimum value) は 4.9e-324 です。浮動小数点値 (floating-point values) の範囲は、非常に小さい値から非常に大きい値まで可能であることがわかります。

定数 math.MaxFloat32 を使用して、float32 の最大値 (maximum value) を表すことができます。定数 math.MaxFloat64 を使用して、float64 の最大値 (maximum value) を表します。

浮動小数点数 (Floating-Point Numbers) の表現

浮動小数点数 (Floating-point numbers) を出力するときは、fmt パッケージ (package) の Printf 関数の %f プレースホルダー (placeholder) を使用できます。次に例を示します。

cd ~/project
touch float.go
package main

import (
    "fmt"
    "math"
)

func main() {
    // Output without exponential form
    fmt.Printf("2.333 without exponential form: %f\n", 2.333)
    fmt.Printf("Pi without exponential form: %f\n", math.Pi)
    // Use %.2f to keep two decimal places for Pi
    fmt.Printf("Pi with two decimal places: %.2f\n", math.Pi)
    fmt.Printf("The maximum value of float32: %f\n", math.MaxFloat32)
    // Exponential form
    fmt.Printf("2.333 in exponential form: %e", 2.333)
}

コマンドを実行すると、次の出力が表示されます。

go run float.go
2.333 without exponential form: 2.333000
Pi without exponential form: 3.141593
Pi with two decimal places: 3.14
The maximum value of float32: 340282346638528859811704183484516925440.000000
2.333 in exponential form: 2.333000e+00

出力の説明:

  • 2.333 without exponential form: 2.333000: これは、%f プレースホルダー (placeholder) を使用して出力された数値 2.333 を示しています。デフォルトでは、%f プレースホルダー (placeholder) は小数点以下 6 桁を表示するため、2.3332.333000 になります。
  • Pi without exponential form: 3.141593: この行は、数学定数 π の近似値である定数 math.Pi の値を出力します。%f プレースホルダー (placeholder) は、それを完全な精度 (precision) で表示します。
  • Pi with two decimal places: 3.14: %.2f を使用することで、fmt.Printf に小数点以下 2 桁に数値をフォーマットするように指示し、その結果 3.14 になります。これは、出力に特定の精度 (precision) のみが必要な場合に非常に役立ちます。
  • The maximum value of float32: 340282346638528859811704183484516925440.000000: これは、float32 が表現できる最大値 (maximum value) を示しています。非常に大きな数値であり、%f で出力すると、多くの桁で表現されることに注意してください。
  • 2.333 in exponential form: 2.333000e+00: この行は、%e プレースホルダー (placeholder) を使用して、浮動小数点数 (floating-point number) を指数 (科学) 表記 (exponential (scientific) notation) で表現する方法を示しています。末尾の e+00 は、2.333000 に 10 の 0 乗を掛けることを示しており、これは単に 2.333 です。指数 (exponent) が e+02 の場合、数値は 10^2 (100) 倍され、その結果 233.3 になります。

ブール型 (Boolean Types)

bool 型 (type) は、true または false の 2 つの値のみを取り、デフォルトは false です。これには、次の特性があります。

  • 整数 (integer) をブール値 (boolean) に変換したり、ブール値 (boolean) を整数 (integer) に変換したりするなど、他の型 (type) に変換することはできません。
  • 算術演算 (arithmetic operations) に参加することはできません。

ブール型 (Boolean types) は、通常、=>< などの関係演算子 (relational operators) と組み合わせて使用されます。bool.go という名前のファイルを作成して、デモンストレーションを見てみましょう。

cd ~/project
touch bool.go
package main

import (
    "fmt"
)

func main() {
    // Use the %t placeholder in fmt.Printf to represent a boolean value
    fmt.Printf("Is 3 equal to 2? %t\n", 3 == 2)
    fmt.Printf("Is 2 equal to 2? %t\n", 2 == 2)

    // Determine whether a and b are equal
    a, b := 1, 2
    fmt.Printf("a is %d, b is %d\n", a, b)
    if a > b {
        fmt.Println("a is greater than b")
    } else if a == b {
        fmt.Println("a is equal to b")
    } else {
        fmt.Println("b is greater than a")
    }
}

プログラムを実行すると、次の出力が得られます。

go run bool.go
Is 3 equal to 2? false
Is 2 equal to 2? true
a is 1, b is 2
b is greater than a

出力の説明:

  • Is 3 equal to 2? false: 式 3 == 2false と評価され、%t プレースホルダー (placeholder) を使用して出力されます。
  • Is 2 equal to 2? true: 式 2 == 2true と評価され、%t プレースホルダー (placeholder) を使用して出力されます。
  • a is 1, b is 2: この行は、整数変数 (integer variables) ab に割り当てられた値を出力します。
  • b is greater than a: if-else if-else 条件文 (conditional statement) は a < b と評価され、これは 1 < 2 (true) であるため、else ステートメント (statement) が実行され、その結果、プログラムは "b is greater than a" を出力します。

このプログラムでは、最初に fmt.Printf%t を使用してブール値 (boolean value) を表し、次に if ステートメント (statement) を使用して 2 つの値の関係を判断します。fmt.Printf では、%d プレースホルダー (placeholder) を使用して整数 (integer) を表し、%f プレースホルダー (placeholder) を使用して浮動小数点数 (floating-point number) を表し、%t プレースホルダー (placeholder) を使用してブール値 (boolean value) を表すことができます。

複素数 (Complex Numbers)

Go には、組み込みの複素数型 (complex number types) もあり、complex64 型 (type) と complex128 型 (type) に分けられます。complex64 では、実部 (real part) と虚部 (imaginary part) の両方が 32 ビット (bits) であるのに対し、complex128 では、実部 (real part) と虚部 (imaginary part) の両方が 64 ビット (bits) です。Go では、複素数演算 (complex number operations) を簡単に行うことができます。

complex.go という名前のファイルを作成し、次のコードを入力します。

cd ~/project
touch complex.go
package main

import (
    "fmt"
)

func main() {
    // Initialize complex numbers in different ways
    c1 := complex(3, 1)
    c2 := 4 + 5i

    // Complex number operations
    c3 := c1 + c2
    c4 := c1 * c2
    // Use the real() function to obtain the real part of a complex number, and the imag() function to obtain the imaginary part of a complex number
    fmt.Printf("The real part of c1 is %v, the imaginary part is %v\n", real(c1), imag(c1))
    // %v in fmt.Printf can be used to represent complex numbers
    fmt.Printf("c1 + c2 is %v\n", c3)
    fmt.Printf("c1 * c2 is %v\n", c4)
}

プログラムを実行すると、次の出力が得られます。

go run complex.go
The real part of c1 is 3, the imaginary part is 1
c1 + c2 is (7+6i)
c1 * c2 is (7+19i)

出力の説明:

  • The real part of c1 is 3, the imaginary part is 1: 関数 real(c1) は、複素数 (complex number) c1 の実部 (real part) である 3 を抽出し、imag(c1) は、c1 の虚部 (imaginary part) である 1 を抽出します。これらの値は、%v プレースホルダー (placeholder) を使用して出力されます。
  • c1 + c2 is (7+6i): この行は、複素数 (complex numbers) c1c2 を加算した結果を示しています。c13 + 1i として定義され、c24 + 5i として定義されています。実部 (real part) と虚部 (imaginary part) を別々に追加すると、(3 + 4) + (1 + 5)i、つまり 7 + 6i になります。
  • c1 * c2 is (7+19i): この行は、複素数 (complex numbers) c1c2 を乗算した結果を示しています。(3 + 1i) * (4 + 5i) は、(3*4 - 1*5) + (3*5 + 1*4)i として計算され、これは (12-5) + (15+4)i に簡略化され、最終的に 7+19i になります。

このプログラムでは、complex 関数 (function) と + および * 演算子 (operators) を使用して、複素数 (complex numbers) を初期化し、演算を実行する方法を示しました。real()imag() は、それぞれ複素数 (complex number) の実部 (real part) と虚部 (imaginary part) を抽出するために使用されます。fmt.Printf%v 動詞 (verb) は、複素数 (complex numbers) を表示するための一般的なプレースホルダー (placeholder) として使用されます。

リテラル値の構文 (Literal Value Syntax)

Go のバージョン 1.13 では、数値リテラル構文 (Numeric Literal Syntax) が導入されました。これは、異なる数値システム (number systems) での数の表現を定義します。そのルールを見てみましょう。

  • 2 進数 (Binary): 整数の前に 0b を追加します。たとえば、0b101 は 10 進数 (decimal) の 5 に相当します。
  • 8 進数 (Octal): 整数の前に 0o または 0O を追加します。たとえば、0o11 は 10 進数 (decimal) の 9 に相当します。
  • 16 進数 (Hexadecimal): 整数の前に 0x または 0X を追加します。たとえば、0x1b は 10 進数 (decimal) の 27 に相当します。
  • 整数内の桁を区切るために _ を使用します。たとえば、0b1000_0100_0010_00010b1000010000100001 と同じです。これにより、可読性 (readability) が向上します。

詳細にデモンストレーションしてみましょう。

cd ~/project
touch literals.go
package main

import "fmt"

func main() {
    // Binary, add 0b at the beginning
    var a int = 0b101
    fmt.Printf("Binary a is %b, decimal is %d\n", a, a)

    // Octal, add 0o or 0O at the beginning
    var b int = 0o11
    fmt.Printf("Octal b is %o, decimal is %d\n", b, b)

    // Hexadecimal, add 0x or 0X at the beginning
    var c int = 0x1b
    fmt.Printf("Hexadecimal c is %x, decimal is %d\n", c, c)

    // Use separators
    d := 0b1000_0100_0010_0001
    e := 0b1000010000100001
    if d == e {
        fmt.Println("d is equal to e")
    }
}

プログラムを実行すると、次の出力が得られます。

go run literals.go
Binary a is 101, decimal is 5
Octal b is 11, decimal is 9
Hexadecimal c is 1b, decimal is 27
d is equal to e

出力の説明:

  • Binary a is 101, decimal is 5: この行は、0b101 の 2 進数表現 (binary representation) である 101 と、その 10 進数 (decimal) に相当する 5 を示しています。%b プレースホルダー (placeholder) は a の 2 進数 (binary) の値を表示し、%d は 10 進数表現 (decimal representation) を表示します。
  • Octal b is 11, decimal is 9: 8 進数 (octal number) 0o11 は、10 進数 (decimal) で 1*8^1 + 1*8^0 = 8 + 1 = 9 に相当します。%o プレースホルダー (placeholder) は b の 8 進数表現 (octal representation) を表示し、%d はその 10 進数 (decimal) の値を表示します。
  • Hexadecimal c is 1b, decimal is 27: 16 進数 (hexadecimal number) 0x1b は、10 進数 (decimal) で 1*16^1 + 11*16^0 = 16 + 11 = 27 に相当します。%x プレースホルダー (placeholder) は c の 16 進数表現 (hexadecimal representation) を表示し、%d はその 10 進数 (decimal) の値を表示します。
  • d is equal to e: これは、2 進数リテラル (binary literal) 0b1000_0100_0010_0001 が値として 0b1000010000100001 と等しいことを示しています。アンダースコア (underscores) は純粋に可読性 (readability) のためのものであり、数値の値を変更しません。if 条件 (condition) は正しく true と評価されます。

このプログラムでは、異なる数値システム (number systems) の宣言と出力、および区切り文字 (separators) の使用法を示しました。fmt.Printf では、異なる数値システム (number systems) を表すために異なるプレースホルダー (placeholders) を使用しました。たとえば、%b は 2 進数 (binary) を表し、%x は 16 進数 (hexadecimal) を表します。それらを習得すると、プログラミング効率 (programming efficiency) が向上します。

まとめ

このセクションで学んだことを復習しましょう。

  • 整数 (Integers) は、符号付き整数 (signed integers) と符号なし整数 (unsigned integers) に分けられます。
  • デフォルトの整数型 (integer types) である intuint は、プラットフォーム (platform) に依存する範囲 (range) を持ちます。
  • 浮動小数点数 (floating-point numbers) の表現 (representation)
  • 複素数 (complex numbers) の使い方
  • リテラル値構文 (literal value syntax) の紹介
  • さまざまなプレースホルダー (placeholders) の使い方

このセクションでは、一般的な整数型 (integer types)、浮動小数点型 (floating-point types)、およびブール型 (boolean types) について説明し、デモンストレーションしました。それらのサイズ (size)、範囲 (range)、および使用法 (usage) について説明しました。また、複素数 (complex numbers) とリテラル定数 (literal constants) についても紹介しました。数値型 (numerical types) は Go プログラム (program) の基礎であり、学習者はそれらをよく学ぶことが重要です。