Golang 숫자형 타입: 정수, 실수, 불리언, 복소수 완벽 가이드

GolangBeginner
지금 연습하기

소개

새로운 장에 오신 Gopher 여러분, 환영합니다. 이 섹션에서는 숫자형 (numerical types) 에 대해 배우겠습니다. 내용은 일반적으로 사용되는 정수형 (integer types), 부동 소수점형 (floating-point types), 부울형 (boolean types) 뿐만 아니라 복소수 (complex numbers) 와 버전 1.13 에 도입된 리터럴 값 구문 (literal value syntax) 을 포함합니다.

지식 포인트:

  • 정수형 (Integer types)
  • 부동 소수점형 (Floating-point types)
  • 부울형 (Boolean types)
  • 복소수 (Complex numbers)
  • 리터럴 값 구문 (Literal value syntax)

정수 (Integers)

정수형은 크게 부호 없는 정수형 (unsigned integers) 과 부호 있는 정수형 (signed integers) 으로 나눌 수 있습니다. 부호 있는 정수형이 가장 널리 사용됩니다.

부호 없음 (Unsigned) 은 0 과 양수만 표현할 수 있음을 의미하며, 부호 있는 (signed) 숫자는 음수와 0, 양수를 모두 표현할 수 있습니다.

부호 없는 정수형은 8 비트, 16 비트, 32 비트, 64 비트의 네 가지 크기로 나눌 수 있으며, 각각 uint8, uint16, uint32, uint64로 표현됩니다. 해당 부호 있는 정수형은 int8, int16, int32, int64입니다. 다음 표는 각 유형이 나타내는 다양한 범위를 보여줍니다.

유형 설명 범위
uint8 8 비트 부호 없는 정수 0 ~ 255
int8 8 비트 부호 있는 정수 -128 ~ 127
uint16 16 비트 부호 없는 정수 0 ~ 65535
int16 16 비트 부호 있는 정수 -32768 ~ 32767
uint32 32 비트 부호 없는 정수 0 ~ 4294967295
int32 32 비트 부호 있는 정수 -2147483648 ~ 2147483647
uint64 64 비트 부호 없는 정수 0 ~ 18446744073709551615
int64 64 비트 부호 있는 정수 -9223372036854775808 ~ 9223372036854775807

uint8int8을 예로 들어 보겠습니다. 둘 다 8 비트 정수이며 256 개의 값을 나타낼 수 있습니다. 부호 없는 정수형 uint8에서 표현할 수 있는 범위는 0 에서 255 까지인 반면, 부호 있는 정수형 int8에서 표현할 수 있는 범위는 -128 에서 127 까지입니다.

위의 8 가지 유형 외에도 uint, int, uintptr의 세 가지 특수한 정수형이 있습니다. 여기서 uintint는 서로 다른 플랫폼에서 서로 다른 범위를 나타낼 수 있으며, uintptr은 포인터 주소를 저장하는 데 사용됩니다.

유형 범위
uint 32 비트 시스템에서는 uint32, 64 비트 시스템에서는 uint64
int 32 비트 시스템에서는 int32, 64 비트 시스템에서는 int64
uintptr 포인터 주소를 저장하는 데 사용되는 부호 없는 정수형, 주로 unsafe 연산과 같은 저수준 프로그래밍에 사용됨

이제 integer.go라는 파일을 생성하여 정수형의 사용법을 시연해 보겠습니다.

cd ~/project
touch integer.go
package main

import (
    "fmt"
    "unsafe"
)

func main() {
    // 현재 환경에서 int 의 유형을 봅니다.
    // a 를 int 유형으로 선언합니다.
    var a int
    // unsafe.Sizeof() 를 사용하여 유형이 차지하는 메모리 크기를 출력합니다.
    fmt.Printf("The type int in the current environment is %d bits\n", unsafe.Sizeof(a)*8)

    var b int8 = 125
    // fmt.Printf 에서 %d 자리 표시자를 사용하여 정수 값을 출력합니다.
    // fmt.Printf 에서 %T 자리 표시자를 사용하여 변수의 유형을 출력합니다.
    fmt.Printf("The value of b is %d, and the type is %T\n", b, b)

    // 정수 연산
    // 정수 c 와 d 를 선언하고 합계를 계산합니다.
    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)

    // uintptr 사용 예시 - 주소 저장
    var ptr uintptr
    x := 42
    // x 의 포인터를 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 유형이 64 비트 (또는 8 바이트) 임을 보여주며, 이는 int64임을 나타냅니다. unsafe.Sizeof(a)는 변수 a의 크기를 바이트 단위로 반환하고, 8 을 곱하여 비트로 변환합니다. 즉, int 유형은 더 큰 정수 값을 저장할 수 있습니다.
  • The value of b is 125, and the type is int8: 여기서는 int8 유형의 변수 b를 선언하고 값 125 를 할당했습니다. 출력은 값과 데이터 유형을 모두 표시하여 이를 확인합니다.
  • c + d = 5, 10 - 5 = 5, 8 * 10 = 80: 이 줄은 기본적인 정수 산술 연산 (덧셈, 뺄셈, 곱셈) 을 보여줍니다. 출력은 이러한 계산의 정확한 결과를 확인합니다.
  • The address of x stored in ptr is: 824634818784: 이는 uintptr을 사용하여 메모리 주소를 저장하는 방법을 보여줍니다. 정수 변수 x에 대한 포인터를 uintptr 유형으로 변환하고 있습니다. 실제 주소 값은 프로그램이 실행될 때마다 다릅니다. 이는 일반적으로 unsafe 연산 및 시스템 프로그래밍에서 발견되는 고급 사용 사례입니다.

이 파일에서 unsafe.Sizeof() 함수를 사용하여 현재 변수 유형이 차지하는 바이트 수를 얻을 수 있습니다. 1 바이트 (byte) 는 8 비트와 같으므로 unsafe.Sizeof()*8은 유형이 차지하는 비트 수를 얻을 수 있습니다. 출력에서 온라인 환경이 64 비트임을 알 수 있습니다. 온라인 환경에서 int의 실제 유형은 int64입니다.

터미널에서 다음 명령을 사용하여 현재 시스템 아키텍처를 확인할 수 있습니다.

dpkg --print-architecture
amd64

부동 소수점 숫자 (Floating-Point Numbers)

부동 소수점 숫자는 Go 에서 분수 부분을 가진 실수 (real numbers) 를 float32float64의 두 가지 유형으로 나타냅니다. 기본 부동 소수점 유형은 float64입니다.

float32float64는 서로 다른 정밀도를 나타냅니다. float64의 기본 정밀도는 float32보다 높습니다.

IEEE 754 표준은 컴퓨터에서 가장 널리 사용되는 부동 소수점 계산 표준이며, 최신 CPU 는 모두 이 표준을 지원합니다. 다른 프로그래밍 언어와 마찬가지로 Go 도 IEEE 754 를 사용하여 부동 소수점 숫자를 저장합니다.

컴퓨터의 1 바이트는 8 비트를 저장할 수 있다는 것을 알고 있습니다. float32는 단정밀도 (single-precision) 부동 소수점 숫자이며 4 바이트 (32 비트) 를 차지합니다. float64는 배정밀도 (double-precision) 이며 8 바이트 (64 비트) 를 차지합니다.

float32에서 부호 비트는 1 비트를 차지하고, 지수는 8 비트를 차지하며, 나머지 23 비트는 가수 (mantissa) 를 나타내는 데 사용됩니다.

float64에서 부호 비트도 1 비트를 차지하고, 지수는 11 비트를 차지하며, 나머지 52 비트는 가수를 나타내는 데 사용됩니다.

float32가 나타낼 수 있는 최대값은 과학적 표기법으로 약 3.4e+38 이고, 최소값은 1.4e-45 입니다. float64가 나타낼 수 있는 최대값은 약 1.8e+308 이고, 최소값은 4.9e-324 입니다. 부동 소수점 값의 범위가 매우 작거나 매우 클 수 있음을 알 수 있습니다.

상수 math.MaxFloat32를 사용하여 float32의 최대값을 나타낼 수 있습니다. 상수 math.MaxFloat64를 사용하여 float64의 최대값을 나타낼 수 있습니다.

부동 소수점 숫자의 표현

부동 소수점 숫자를 출력할 때 fmt 패키지의 Printf 함수의 %f 자리 표시자를 사용할 수 있습니다. 다음은 예시입니다.

cd ~/project
touch float.go
package main

import (
    "fmt"
    "math"
)

func main() {
    // 지수 형태 없이 출력
    fmt.Printf("2.333 without exponential form: %f\n", 2.333)
    fmt.Printf("Pi without exponential form: %f\n", math.Pi)
    // %.2f 를 사용하여 Pi 를 소수점 두 자리로 유지합니다.
    fmt.Printf("Pi with two decimal places: %.2f\n", math.Pi)
    fmt.Printf("The maximum value of float32: %f\n", math.MaxFloat32)
    // 지수 형태
    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 자리 표시자를 사용하여 출력된 숫자 2.333을 보여줍니다. 기본적으로 %f 자리 표시자는 소수점 뒤에 6 자리를 표시하므로 2.3332.333000이 됩니다.
  • Pi without exponential form: 3.141593: 이 줄은 수학 상수 π의 근사값인 상수 math.Pi의 값을 출력합니다. %f 자리 표시자는 전체 정밀도로 표시합니다.
  • Pi with two decimal places: 3.14: %.2f를 사용하면 fmt.Printf에게 소수점 뒤 두 자리로 숫자를 형식화하도록 지시하여 3.14가 됩니다. 이는 출력에 특정 정밀도만 필요한 경우 매우 유용합니다.
  • The maximum value of float32: 340282346638528859811704183484516925440.000000: 이는 float32가 나타낼 수 있는 최대값을 보여줍니다. 매우 큰 숫자이며, %f로 출력하면 많은 자릿수로 표시됩니다.
  • 2.333 in exponential form: 2.333000e+00: 이 줄은 %e 자리 표시자를 사용하여 부동 소수점 숫자를 지수 (과학적) 표기법으로 나타내는 방법을 보여줍니다. 마지막의 e+002.333000에 10 의 0 제곱을 곱한다는 것을 나타내며, 이는 단순히 2.333입니다. 지수가 e+02인 경우 숫자는 10^2 (100) 을 곱하여 233.3이 됩니다.

부울 타입 (Boolean Types)

bool 유형은 true 또는 false의 두 가지 값만 가질 수 있으며, 기본값은 false입니다. 다음과 같은 특징이 있습니다.

  • 다른 유형으로 변환할 수 없습니다. 예를 들어 정수를 부울로 변환하거나 부울을 정수로 변환하는 것은 불가능합니다.
  • 산술 연산에 참여할 수 없습니다.

부울형은 일반적으로 =, >, <와 같은 관계 연산자와 함께 사용됩니다. bool.go라는 파일을 생성하여 시연을 살펴보겠습니다.

cd ~/project
touch bool.go
package main

import (
    "fmt"
)

func main() {
    // 부울 값을 나타내기 위해 fmt.Printf 에서 %t 자리 표시자를 사용합니다.
    fmt.Printf("Is 3 equal to 2? %t\n", 3 == 2)
    fmt.Printf("Is 2 equal to 2? %t\n", 2 == 2)

    // a 와 b 가 같은지 확인합니다.
    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 자리 표시자를 사용하여 출력됩니다.
  • Is 2 equal to 2? true: 표현식 2 == 2true로 평가되며, 이는 %t 자리 표시자를 사용하여 출력됩니다.
  • a is 1, b is 2: 이 줄은 정수 변수 ab에 할당된 값을 출력합니다.
  • b is greater than a: if-else if-else 조건문은 a < b로 평가되며, 이는 1 < 2 (true) 이므로 else 문이 실행되어 프로그램이 "b is greater than a"를 출력합니다.

이 프로그램에서는 먼저 fmt.Printf에서 %t를 사용하여 부울 값을 나타낸 다음, if 문을 사용하여 두 값의 관계를 결정합니다. fmt.Printf에서 %d 자리 표시자를 사용하여 정수를 나타내고, %f 자리 표시자를 사용하여 부동 소수점 숫자를 나타내며, %t 자리 표시자를 사용하여 부울 값을 나타낼 수 있습니다.

복소수 (Complex Numbers)

Go 는 또한 complex64complex128 유형으로 나눌 수 있는 내장 복소수 유형을 가지고 있습니다. complex64에서 실수부와 허수부는 모두 32 비트인 반면, complex128에서는 실수부와 허수부가 모두 64 비트입니다. Go 에서 복소수 연산을 쉽게 수행할 수 있습니다.

complex.go라는 파일을 생성하고 다음 코드를 입력합니다.

cd ~/project
touch complex.go
package main

import (
    "fmt"
)

func main() {
    // 다양한 방식으로 복소수를 초기화합니다.
    c1 := complex(3, 1)
    c2 := 4 + 5i

    // 복소수 연산
    c3 := c1 + c2
    c4 := c1 * c2
    // real() 함수를 사용하여 복소수의 실수부를 얻고, imag() 함수를 사용하여 복소수의 허수부를 얻습니다.
    fmt.Printf("The real part of c1 is %v, the imaginary part is %v\n", real(c1), imag(c1))
    // fmt.Printf 의 %v는 복소수를 나타내는 데 사용할 수 있습니다.
    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)은 복소수 c1의 실수부를 추출하며, 이는 3입니다. imag(c1)c1의 허수부를 추출하며, 이는 1입니다. 이러한 값은 %v 자리 표시자를 사용하여 출력됩니다.
  • c1 + c2 is (7+6i): 이 줄은 복소수 c1c2를 더한 결과를 보여줍니다. c13 + 1i로 정의되고 c24 + 5i로 정의됩니다. 실수부와 허수부를 별도로 더하면 (3 + 4) + (1 + 5)i 또는 7 + 6i가 됩니다.
  • c1 * c2 is (7+19i): 이 줄은 복소수 c1c2를 곱한 결과를 보여줍니다. (3 + 1i) * (4 + 5i)(3*4 - 1*5) + (3*5 + 1*4)i로 계산되며, 이는 (12-5) + (15+4)i로 단순화되고, 최종적으로 7+19i가 됩니다.

이 프로그램에서는 complex 함수와 +* 연산자를 사용하여 복소수를 초기화하고 연산을 수행하는 방법을 시연했습니다. real()imag()는 각각 복소수의 실수부와 허수부를 추출하는 데 사용됩니다. fmt.Printf%v 동사는 복소수를 표시하기 위한 일반적인 자리 표시자로 사용됩니다.

리터럴 값 구문 (Literal Value Syntax)

Go 1.13 버전에서 Numeric Literal Syntax가 도입되었습니다. 이는 다양한 진법에서 숫자를 표현하는 방식을 정의합니다. 규칙을 살펴보겠습니다.

  • 이진수 (Binary): 정수 앞에 0b를 추가합니다. 예를 들어, 0b101은 십진수 5와 같습니다.
  • 팔진수 (Octal): 정수 앞에 0o 또는 0O를 추가합니다. 예를 들어, 0o11은 십진수 9와 같습니다.
  • 16 진수 (Hexadecimal): 정수 앞에 0x 또는 0X를 추가합니다. 예를 들어, 0x1b는 십진수 27과 같습니다.
  • _를 사용하여 정수의 자릿수를 구분합니다. 예를 들어, 0b1000_0100_0010_00010b1000010000100001과 같습니다. 이는 가독성을 향상시킬 수 있습니다.

자세히 시연해 보겠습니다.

cd ~/project
touch literals.go
package main

import "fmt"

func main() {
    // 이진수, 앞에 0b 를 추가합니다.
    var a int = 0b101
    fmt.Printf("Binary a is %b, decimal is %d\n", a, a)

    // 팔진수, 앞에 0o 또는 0O 를 추가합니다.
    var b int = 0o11
    fmt.Printf("Octal b is %o, decimal is %d\n", b, b)

    // 16 진수, 앞에 0x 또는 0X 를 추가합니다.
    var c int = 0x1b
    fmt.Printf("Hexadecimal c is %x, decimal is %d\n", c, c)

    // 구분 기호 사용
    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의 이진수 표현인 101과 십진수 값인 5를 보여줍니다. %b 자리 표시자는 a의 이진수 값을 표시하고, %d는 십진수 표현을 표시합니다.
  • Octal b is 11, decimal is 9: 팔진수 0o11은 십진수로 1*8^1 + 1*8^0 = 8 + 1 = 9와 같습니다. %o 자리 표시자는 b의 팔진수 표현을 표시하고, %d는 십진수 값을 표시합니다.
  • Hexadecimal c is 1b, decimal is 27: 16 진수 0x1b는 십진수로 1*16^1 + 11*16^0 = 16 + 11 = 27과 같습니다. %x 자리 표시자는 c의 16 진수 표현을 표시하고, %d는 십진수 값을 표시합니다.
  • d is equal to e: 이는 이진수 리터럴 0b1000_0100_0010_0001이 값으로 0b1000010000100001과 같음을 보여줍니다. 밑줄은 순전히 가독성을 위한 것이며 숫자의 값을 변경하지 않습니다. if 조건은 올바르게 true로 평가됩니다.

이 프로그램에서는 다양한 진법의 선언 및 출력을 시연하고 구분 기호의 사용법을 보여주었습니다. fmt.Printf에서 다양한 자리 표시자를 사용하여 서로 다른 진법을 나타냈습니다. 예를 들어, %b는 이진수를 나타내고 %x는 16 진수를 나타냅니다. 이를 숙달하면 프로그래밍 효율성을 향상시킬 수 있습니다.

요약

이번 섹션에서 배운 내용을 복습해 보겠습니다.

  • 정수는 부호 있는 정수 (signed integers) 와 부호 없는 정수 (unsigned integers) 로 나눌 수 있습니다.
  • 기본 정수 타입인 intuint는 플랫폼에 따라 범위가 달라집니다.
  • 부동 소수점 숫자 (floating-point numbers) 의 표현
  • 복소수 (complex numbers) 를 사용하는 방법
  • 리터럴 값 구문 (literal value syntax) 소개
  • 다양한 자리 표시자 (placeholders) 를 사용하는 방법

이 섹션에서는 일반적인 정수 타입, 부동 소수점 타입 및 부울 타입 (boolean types) 을 설명하고 시연했습니다. 크기, 범위 및 사용법에 대해 논의했습니다. 또한 복소수와 리터럴 상수 (literal constants) 를 소개했습니다. 숫자 타입은 Go 프로그램의 초석이며, 학습자가 이를 잘 연구하는 것이 중요합니다.