소개
새로운 장에 오신 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 |
uint8과 int8을 예로 들어 보겠습니다. 둘 다 8 비트 정수이며 256 개의 값을 나타낼 수 있습니다. 부호 없는 정수형 uint8에서 표현할 수 있는 범위는 0 에서 255 까지인 반면, 부호 있는 정수형 int8에서 표현할 수 있는 범위는 -128 에서 127 까지입니다.
위의 8 가지 유형 외에도 uint, int, uintptr의 세 가지 특수한 정수형이 있습니다. 여기서 uint와 int는 서로 다른 플랫폼에서 서로 다른 범위를 나타낼 수 있으며, 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) 를 float32와 float64의 두 가지 유형으로 나타냅니다. 기본 부동 소수점 유형은 float64입니다.
float32와 float64는 서로 다른 정밀도를 나타냅니다. 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.333은2.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+00은2.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 == 2는false로 평가되며, 이는%t자리 표시자를 사용하여 출력됩니다.Is 2 equal to 2? true: 표현식2 == 2는true로 평가되며, 이는%t자리 표시자를 사용하여 출력됩니다.a is 1, b is 2: 이 줄은 정수 변수a와b에 할당된 값을 출력합니다.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 는 또한 complex64 및 complex128 유형으로 나눌 수 있는 내장 복소수 유형을 가지고 있습니다. 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): 이 줄은 복소수c1과c2를 더한 결과를 보여줍니다.c1은3 + 1i로 정의되고c2는4 + 5i로 정의됩니다. 실수부와 허수부를 별도로 더하면(3 + 4) + (1 + 5)i또는7 + 6i가 됩니다.c1 * c2 is (7+19i): 이 줄은 복소수c1과c2를 곱한 결과를 보여줍니다.(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_0001은0b1000010000100001과 같습니다. 이는 가독성을 향상시킬 수 있습니다.
자세히 시연해 보겠습니다.
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) 로 나눌 수 있습니다.
- 기본 정수 타입인
int와uint는 플랫폼에 따라 범위가 달라집니다. - 부동 소수점 숫자 (floating-point numbers) 의 표현
- 복소수 (complex numbers) 를 사용하는 방법
- 리터럴 값 구문 (literal value syntax) 소개
- 다양한 자리 표시자 (placeholders) 를 사용하는 방법
이 섹션에서는 일반적인 정수 타입, 부동 소수점 타입 및 부울 타입 (boolean types) 을 설명하고 시연했습니다. 크기, 범위 및 사용법에 대해 논의했습니다. 또한 복소수와 리터럴 상수 (literal constants) 를 소개했습니다. 숫자 타입은 Go 프로그램의 초석이며, 학습자가 이를 잘 연구하는 것이 중요합니다.



