반응형
부동 소수점 계산 시 오류 현상
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 사에서 제작
패트리어트 작동 순서
- 레이더가 속도, 위도, 경도, 방위각 등의 정보를 기반으로 스커드 미사일의 특징을 가진 공중 물체를 찾아냄
- ‘레인지 게이트’라 불리는 레이더 시스템 내의 전자 기기가 미사일이 다음에 나타나게 될 영공의 구역을 계산하며(시스템이 다가오는 미사일을 계속 추적)
- 적의 미사일이 계산된 레인지 게이트 영역에 들어오면 패트리어트가 미사일을 발사
버그 원인
- 레인지 게이트는 목표물의 속도(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
- 정수부(68)는 그대로 이진수로 변환한다.
64 + 4 -> 100 0100 - 소수부(0.625)만 가져온다.
0.625 - 소수부에 2를 곱하는데그 결과가 1로 떨어질 때까지혹은똑같은 소수점이 나올 때까지반복한다.
0.625 x 2 = 1.250 (정수부는 버린다)
0.250 x 2 = 0.500
0.500 x 2 = 1.000 - 위에서부터 차례로 가져온다.
결과: 101 - 정수부와 소수부를 합친다.
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.와 같은 자료 구조로 되어 있습니다.
반응형
'프로그램 개발해서 돈벌기 > flutter' 카테고리의 다른 글
flutter 버튼 중 onFocusChange를 갖고 있는 버튼들은? (0) | 2023.03.23 |
---|---|
flutter에서 OutlinedButton width 변경 방법 (0) | 2023.03.23 |
10. 클래스 (class) - 완전 초보 Dart 언어 기초 문법 : flutter (0) | 2022.12.31 |
flutter에서 Named route 화면 전환을 이용하여 첫(시작) 로딩 화면( Splash Screen ) 만들기 (0) | 2022.12.30 |
flutter material button - The method 'FlatButton' isn't defined (0) | 2022.12.30 |
댓글