반응형

Go의 숫자형과 부동소수점 오류

  • Go는 매우 엄격한 문법을 갖고 있기 때문에 동일한 값을 지녀도 형이 다르다면 연산이 불가
  • Go 역시 부동소수점 오류를 갖기 때문에 연산을 위한 형변환 과정에서 주의가 필요

I. Go의 숫자형

1. 종류

  1. uint
  • unsigned integers 로 0 ~ max value 까지 표현
  • uint8/16/32/64
  • uint로 선언할 경우 32 or 64bit으로 설정
  • uint8은 byte와 동일한 값을 가짐
package main

import (
"fmt"; 
"math"
)

func main() {
    uint8_num := uint8(3)
    byte_num := byte(3)

    fmt.Println("uint8 : ", uint8_num, ", byte : ", byte_num)
    fmt.Println(uint8_num + byte_num)
}
>>> uint8 :  3 , byte :  3
>>> 6
  1. int
  • signed integers 로 max_value의 보수까지 표현
  • int8/16/32/64
  • int로 선언할 경우 32 or 64bit으로 설정
  • int32는 rune과 동일한 값을 가짐
package main

import (
"fmt"; 
"math"
)

func main() {
    int32_num := int32(3)
    rune_num := rune(3)

    fmt.Println("int32 : ", int32_num, ", rune : ", rune_num)
    fmt.Println(int32_num + rune_num)
}
>>> int32 :  3 , rune :  3
>>> 6
  1. float/complex
  • 실수형(float32/64) 과 복소수형(complex64/128)
  • complex64는 float32로 표현된 실수부와 허수부로 구성

II. Go 숫자형 연산

1. Overflow/Underflow

  • 선언된 데이터 타입이 갖는 최대/최소값을 벗어나는 경우 발생하는 에러
  • 사용할 데이터 범위가 정해져있는 상황에서는 데이터 타입을 지정하여 데이터 범위를 완벽히 제한하고 메모리 측면에서 살짝 이익을 볼 수 있으나, 그렇지 않은 경우 되도록 큰 비트수를 사용하는게 좋음
package main

import (
"fmt"; 
"math"
)

func main() { 
  var maxuint8 uint8 = math.MaxUint8 // 255
  var overflow uint8 = math.MaxUint8 + 1
}
>>> constant 256 overflows uint8

2. 산술연산 예시

package main

import (
"fmt"
)

func main() {
  n3 := int64(4)
  n4 := int64(6)

  fmt.Println("덧셈", n3+n4)
  fmt.Println("뺄셈", n3-n4)
  fmt.Println("나눗셈(몫)", n3/n4)
  fmt.Println("나눗셈(나머지)", n3%n4)
  fmt.Println("곱셈", n3*n4)
  fmt.Println("비트이동 왼쪽", n3<<2)
  fmt.Println("비트이동 오른쪽", n3>>2)
  fmt.Println("보수", ^n3)  
  }
>>> 덧셈 10
>>> 뺄셈 -2
>>> 나눗셈(몫) 0
>>> 나눗셈(나머지) 4
>>> 곱셈 24
>>> 비트이동 왼쪽 16
>>> 비트이동 오른쪽 1
>>> 보수 -5

3. 부동소수점 오류

  • 동일한 0.1 - 0.1 도 32비트에서와 64비트에서는 전혀 다른 결과를 출력
  • 컴퓨터는 2진수로 모든 것을 표현하기 때문에 실수는 딱 떨어지는 숫자로 나타나지 않고 특정 비트까지 잘라서 표현하게되어 발생하는 오류
  • 서로 다른 타입의 숫자형을 연산할 때는 정수보단 실수형에 맞추고, 큰 비트수에 맞추는게 좋음
package main

import (
"fmt"
)

func main() {
    n1 := float32(.1)
    n2 := float64(.1)
    fmt.Println("float32 : ",n1)
    fmt.Println("float32->float64 : ", float64(n1))
    fmt.Println("float64 형변환 연산",float64(n1)-n2)
    fmt.Println("float32 형변환 연산",n1-float32(n2))
}
>>> float32 : 0.1
>>> float32->float64 :  0.10000000149011612
>>> float64 형변환 연산 1.4901161138336505e-09
>>> float32 형변환 연산 0
  • 부동소수점 차이는 항상 머신 입실론 값 이하
package main

import (
"fmt";
"math"
)

func main() {
    epsilon := math.Nextafter(1,2)-1 
    fmt.Println("Go 의 머신 입실론 값 : ", epsilon)
}
>>> Go 의 머신 입실론 값 : 2.220446049250313e-16

** 머신입실론 : 컴퓨터의 부동 소수점 연산에서 1보다 큰 최소의 수와 1과의 차아로 반올림에 기인하는 상대 오차의 상한값.

반응형
복사했습니다!