본문 바로가기
프로그램 개발해서 돈벌기/flutter

부동 소수점 연산 버그로 발생한 실제 사건을 Dart 코드로 검증 해 보고 해결해 보기

by ubmuhan 2023. 1. 25.
반응형

부동 소수점 계산 시 오류 현상

https://dartpad.dev/

 

DartPad

 

dartpad.dev

 

void main(){
  if(1.1 + 0.1 == 1.2) {
    print("true");
  } else {
    print("false")
  }
  
  // 위 if 구문이 왜 false 되었는지 확인
  print(1.1 + 0.1);
  
  // 원하는 값을 얻고 싶으면 정수로 변환 후 계산 진행
  // 이후 소수로 변환
  print(((1.1 * 10) + (0.1 * 10)) / 10);
}

// 실행 결과
// false
// 1.2000000000000002
// 1.2

버그로 실제 발생한 사건

1991년 미육군 MIM-104 패트리어트 미사일 소프트웨어의 숫자 전환 라운드오프 에러

미 육군이 사용하는 모바일 지대공 미사일(a surface-to-air missile) 시스템으로 미국 Raytheon 사에서 제작

 

패트리어트 작동 순서

  1. 레이더가 속도, 위도, 경도, 방위각 등의 정보를 기반으로 스커드 미사일의 특징을 가진 공중 물체를 찾아냄
  2. 레인지 게이트라 불리는 레이더 시스템 내의 전자 기기가 미사일이 다음에 나타나게 될 영공의 구역을 계산하며(시스템이 다가오는 미사일을 계속 추적)
  3. 적의 미사일이 계산된 레인지 게이트 영역에 들어오면 패트리어트가 미사일을 발사

 

버그 원인

  • 레인지 게이트는 목표물의 속도(Velocity)와 레이더에서 발견된 최종 시간을 기반으로 목표물이 다음에 어디에 나타날지를 예측(이 예측 알고리즘은 속도와 시간 모두가 실시간으로 표현될 것을 요구함)
  • 시스템에서 속도는 십진 정수로 표현 가능한 실수 형식임(예, 시간당 3750.2563 마일)
  • 시스템에서 시간은 내부 클락에 의해 1/10초 단위로 측정되고 1/10을 곱하여 정수 형식으로 컴퓨터에 저장됨(예, 32, 33, 34...). 부팅 후 시스템의 런 시간이 길어질 수록 시간을 나타낸 숫자도 점차 커짐
  • 1/10은 무한한 이진 전개(a non-terminating binary expansion)를 가지는 반면 패트리어트 컴퓨터는 24비트 고정 소수점 레지스터(fixed-point registers)만을 사용하므로 시간 값을 정수에서 실수로 전환 시 24 비트 이후 소수점 뒷부분이 잘리는 라운드오프 에러가 발생
1/10의 이진 전개는  0.0001100110011001100110011001100....
패트리어트의 24 비트 레지스터가 저장한 것은  0.00011001100110011001100
오차를 바이너리로 표현하면   0.0000000000000000000000011001100...
이 오차를 십진법으로 표현하면  약 0.000000095
  • 시간을 나타낸 값이 커질수록(시스템 런 시간이 길어질수록이 오차도 커진다다하란의 패트리어트 미사일 시스템은 약 100 시간 연속해서 가동되었으므로 라운드오프 에러로 인한 시간 오차는 약 0.34
    0.000000095×100(시간)×60()×60()×10=0.34
  • 결국 패트리어트의 레인지 게이트는 목표물의 속도와 시스템 런 시간에 정비례하는 오차를 가지게 된다. 다하란에서 스커드가 초 당 약 1,676 미터 속도로 이동했으므로 오차 시간인 0.34초 동안 약 687 미터를 더 이동하여 레인지 게이트의 추적에서 벗어나게 됨

 

사우디 아라비아 다하란에서 버그로 요격 실패로 사망자 발생

  • 1991 2 25일 사우디 아라비아 다하란에서 사용 중이던 패트리어트 배터리는 날아오는 이라크 스커드 미사일을 요격하는데 실패하였고 이것이 미 육군 막사에 떨어져 28명이 죽고 98명이 부상당함
  • 레이더가 날아오는 스커드를 일차적으로 탐지하였지만 이 미사일의 다음 위치를 예측한 레인지 게이트에서 스커드가 발견되지 않아 가짜 경보로 판단한 것이 참사로 이어짐
  • 조사 결과 소프트웨어에서 시간 값의 형식을 전환하면서 생긴 라운드오프 에러로 시간 오차가 발생하였고 이것이 레인지 게이트의 부정확한 계산으로 이어져 엉뚱한 위치에서 적의 미사일을 찾는 결과를 낳음

 

소수점 이진수로 변환 방법

예) 68.625

  1. 정수부(68)는 그대로 이진수로 변환한다.
    64 + 4 -> 100 0100
  2. 소수부(0.625)만 가져온다.
    0.625
  3. 소수부에 2를 곱하는데그 결과가 1로 떨어질 때까지혹은똑같은 소수점이 나올 때까지반복한다.
    0.625 x 2 = 1.250 (정수부는 버린다)
    0.250 x 2 = 0.500
    0.500 x 2 = 1.000
  4. 위에서부터 차례로 가져온다.
    결과: 101
  5. 정수부와 소수부를 합친다.
    1000100.101

예) 125.3

64 + 32 + 16 + 8 + 4 + 1 -> 111 1101

 

0.3 x 2 = 0.6
0.6 x 2 = 1.2
0.2 x 2 = 0.4
0.4 x 2 = 0.8
0.8 x 2 = 1.6  (첫번째 결과의 소수점과 동일하므로 중단)

 

결과: 01001

125.3 = 1111101.01001

 

 

부동 소수점 자료 구조

부동 소수점의 표현 방법에 대해서는 IEEE754에서 32bit single-precision과 64bit double-precision 표준을 정하고 있습니다. float와 double의 규격입니다.

기본적인 구조는 최상의 비트는 부호를 표시하는데 사용하고 지수부분(Exponet)과 가수부분(Fraction/Mantissa)로 구성되어 있습니다. 

그림 1.과 그림 2.와 같은 자료 구조로 되어 있습니다.

그림 1. 32bit 부동 소수점(float)

 

그림 2. 64bit 부동 소수점(double)

 

 
 
반응형

댓글