수치해석을 모르면 생기는 사고들

수치해석을 모르면 푸틴이 미사일을 잘못 쏴요

우리 학교에는 학생들 사이에서 인기가 많은 교수님이 한 분 계신다. 강의 시간에 뜬금없거나 재밌는 이야기를 많이 해서, 호불호가 갈릴 지언정 취향에 맞는 사람들에게는 인기가 항상 높다(귀엽다는 평가가 많다). 교수님은 수치해석 강의 시간에 농담 삼아서 위 이야기를 자주 말하신다.

 

갑자기 뜬금없이 미사일 이야기가 나와서, 많은 학생들은 의아해하기도 한다. 갑자기 수치해석에 관한 수업에서 왜 미사일에 관한 이야기가 나오는가?

 

이를 알기 위해선 한 가지 역사적 사건을 꼭 알아야 한다.

패트리어트 미사일 격추 실패 사건

미국 회계감사원(GAO)에서 발표한 다란 패트리어트 격추 실패 사건 조사 보고서
미국 회계감사원(GAO)에서 발표한 다란 패트리어트 격추 실패 사건 조사 보고서

 

때는 1991년 2월 25일, 이라크 전쟁 시기.

 

지금도 그렇고, 미국은 동맹국 사우디 아라비아에 파병을 보낸 상태였다.

다란(Dhahran) 시에 주둔 중인 미군은 저녁 휴식을 준비하던 중이었다.

 

그날 저녁, 미군 기지로 한 대의 스커드 미사일이 날아왔다.

 

굉음과 화염, 그리고 그로 인한 연쇄 폭발. 기지는 아수라장이 되었고, 이 폭격으로 인해 28명의 미군이 사망하였고, 97명이 부상을 당했다.

 

당시 기지는 패트리어트 방공 미사일에 의해 방어되고 있었다. 그러나 미사일 공격 당시 패트리어트는 작동하지 않았다.

 

한국에서도 핵심 자산으로 사용되는 이 패트리어트 미사일은, 마하 2의 속도의 미사일 혹은 기타 공중 위협으로부터 기지를 수호할 수 있도록 설계된 지대공 단거리 미사일 방어 체계 시스템이다. 유럽 전역, 한국과 일본, 중동 등에서 널리 쓰이고 있는 무기 체계이다.

패트리어트 방공 미사일
패트리어트 방공 미사일

그 명성에도 불구하고, 패트리어트 방공 요격 시스템은 기지로 날아오는 스커드 미사일을 탐지조차 하지 못 했고, 그로 인해 125명의 사상자가 발생하는 비극을 겪어야만 했다. 어떻게 된 일일까?

패트리어트 레이더 시스템

정상적인 경우 패트리어트 레이더 시스템의 작동 과정
정상적인 경우 패트리어트 레이더 시스템의 작동 과정

 

사건의 원인을 알기 위해서는, 먼저 패트리어트 방공 시스템의 눈을 담당하는 레이더 시스템에 대해 알아야 한다.

 

패트리어트 레이더는 크게 세 가지 단계로 미사일을 추적한다.

  1. Search Action(검색) - 비행체(목표물, 여기서는 스커드 미사일)의 속도, 위치, 방위각 등을 파악하여 적대적 물체(미사일)인 지 판단한다.
  2. Validation Action(평가) - 목표물의 속도, 위치 등을 검증한다.
  3. Track Action(추적) - 목표물이 날아올 위치를 예측하여 레인지 게이트 범위(RGA)를 설정, 이 범위에 들어온 비행체를 추적한다.

이후에 실제 비행체를 격추하는 요격 행동으로 이어진다.

이때 RGA는 실제 미사일이 날아왔을 때의 예상 위치 범위로, 이 범위에서 목표물을 추적하여 요격 행동에 나서게 된다.

레이더 시스템의 오류

패트리어트 레이더 시스템의 오류 1패트리어트 레이더 시스템의 오류
패트리어트 레이더 시스템의 오류(우측 그림에서 RGA가 이동하여 표적과 전혀 다른 곳을 추적하고 있음을 알 수 있다)

 

문제가 발생한 곳은 3번 추적 단계였다. 당시 패트리어트 레이더의 레인지 게이트 범위는 엉뚱한 곳을 가르키고 있었다. 당시 패트리어트는 스커드 미사일로부터 687m 떨어진 곳의 빈 하늘을 RGA로 설정하여 추적하고 있었다. 스커드 미사일은 프리패스로 방공망을 뚫고 나아갔다.

사건 보고서 발췌사건 보고서 발췌

이 당시 패트리어트 시스템에는 심각한 소프트웨어 오류가 있었다. 패트리어트 시스템을 8시간 연속 가동하면 RGA가 정상 위치에서 20%씩 이동하는 버그였다.

 

이러한 RGA의 위치 변화는 곧 RGA의 정가운데에 목표물(스커드 미사일)이 위치하지 않음을 의미한다. 목표물이 RGA의 가운데에 있어야 요격 가능성이 높아지는 데, 목표물이 이 범위의 가운데에 있지 않다는 것은 다시 말해 그만큼 요격 가능성이 떨어진다는 것을 의미했다.

만약 RGA가 50% 이상 이동한다면, 패트리어트 시스템은 스커드 미사일을 더 이상 추적하지 못 한다. 패트리어트 시스템이 8시간 연속 가동할 때마다 20% 이동하므로, 20시간을 가동하면 50%가 이동한다. 즉 20시간 연속으로 가동하게 된다면 패트리어트 시스템은 불능이 된다는 다소 황당한 이야기이다.

놀랍게도 패트리어트 미사일도 하루 8시간 노동을 주장한다
놀랍게도 패트리어트 미사일도 하루 8시간 노동을 주장한다

그렇다면 사건이 발생한 2월 25일, 패트리어트는 얼마나 오래 가동되고 있었을까?

 

사후 조사에 의하면 당시 패트리어트 시스템은 무려 100시간 연속으로 가동되고 있었다. 그 결과 RGA는 빈 허공을 가르고 있었고, 비극이 발생했다.

문제의 원인

당시 패트리어트 시스템은 내부적으로 1/10초마다 1/10을 곱하는 연산을 수행했다.

 

이 계산은 24비트 고정 소수점 레지스터(24-bits Fixed Point Register)를 통해 수행된다.

 

1/10을 이진수로 바꾸면 $\frac{1}{24}+\frac{1}{25}+\frac{1}{28}+\frac{1}{29}+\frac{1}{212}+\frac{1}{213} + \cdots$ 으로 0.0001 1001 1001 1001 1001 1001 1001 100... 이 된다. 24비트에 맞춰야 하므로 25비트 이하 소수점을 버리면 0.0001 1001 1001 1001 1001 100이 된다.

  0.0001 1001 1001 1001 1001 1001 1001 100...
- 0.0001 1001 1001 1001 1001 100
---------------------------------------------
  0.0000 0000 0000 0000 0000 0001 1001 100...

곧 0.1초마다 0.0000 0000 0000 0000 0000 0001 1001 100...만큼의 오차가 발생한다. 이를 10진수로 표현하면 0.0000 0009 5 초이다.

 

따라서 1시간 동안 이 오차가 누적된다고 하면, 0.000000095 × 60(minutes) × 60(secs) × 10(operations per seconds) = 0.0034 초 만큼의 오차가 발생한다.

 

0.0034초라는 시간은 인간에게 있어서는 찰나의 시간이다. 하지만 상대가 마하 5, 초속 1.7km의 속력을 가지는 스커드 미사일이라면 어떨까? 스커드 미사일에 있어서 이 시간은 7m를 이동할 수 있는 시간이다.

 

만약 20시간 연속 시스템을 가동하게 된다면, 누적 시간 오차는 0.0687초로 RGA는 목표물로부터 137m 떨어진 공간을 가리키게 된다. 이때는 이미 목표물이 RGA 범위 자체를 벗어나게 되므로, 20시간이 지나게 된다면 목표물 추적이 아예 불가능해지는 것이다.

 

다란의 패트리어트는 100시간 연속 가동 중이었고, 0.34초의 오차가 발생하게 되었다. 이때의 RGA는 목표물로부터 무려 687m 벗어나 있었다.

 

Hours Seconds Calculated Time (Secs) Inaccuracy (Secs) Approximate Shift In Range Gate (Meters)
0 0 0 0 0
1 3600 3599.9966 .0034 7
8 28800 28799.9725 .0275 55
20 72000 71999.9313 .0687 137
48 172800 172799.8352 .1648 330
72 259200 259199.7528 .2472 494
100 360000 359999.6667 .3433 687

아쉬웠던 대응, 막을 수 있었던 사고

한 가지 아쉬운 점이라면, 이러한 소프트웨어 오류에도 불구하고 이 사고는 막을 수 있던 기회가 있었다는 점이다.

 

사고는 1991년 2월 25일에 발생하였다. 그보다 2주 전인 2월 11일, 패트리어트 프로젝트 팀은 이스라엘 군이 넘겨진 시스템 로그를 분석했을 때 이미 RGA가 이동하는 문제를 발견했다.

 

팀은 즉시 버그 픽스에 들어갔다. 2월 16일, 버그를 확인한 지 5일 만에 개발 팀은 해당 오류를 수정한 소프트웨어를 배포하기 시작했다.

문제는 당시의 소프트웨어 수정과 배포가 지금처럼 물 흐르듯 빠르게 진행되지 못 했다는 점이다.

 

지금이야 웹 개발자들의 입장에선 소프트웨어 배포는 CI/CD 파이프라인을 통해 ‘딸깍’ 한 번에 끝난다. 데브옵스 개발자들이 만들어놓은 파이프라인과, 클라우드를 통해서 전 세계에 한 번에 소프트웨어를 배포시킬 수 있지만…

 

하지만 당시는 1991년. 미션은 네트워크에 연결되어 있지도 않은 전 세계에 흩어져 있는 군사 장비에 최대한 빠르게 수정된 소프트웨어 패키지를 설치해야 한다. 당시에 소프트웨어 패키지를 설치하려면 배나 비행기로 SW가 담긴 장비를 실어날라야 했다. 당연히 시간이 오래 걸릴 수 밖에 없었고, 패트리어트 프로젝트 팀은 시간과의 싸움에 직면했다.

 

패트리어트 프로젝트 팀은 2월 21일, 모든 패트리어트를 운용하는 부대에 장시간에 걸쳐 패트리어트를 운용하게 되면 RGA가 이동하게 되어 목표물 추적에 실패할 수 있음을 경고하였다. 동시에 이 버그를 해결한 소프트웨어 패키지를 배포 중이라는 메시지를 보냈다. 문제는 여기서 얼마나 ‘오래’ 패트리어트를 운용하게 되면 버그가 발생하는 지 언급하지 않았다는 점이다.

 

당시 다란에 있던 미군 역시 이 메시지를 받았지만, 얼마나 오래 패트리어트를 켜놔도 되는 지 그들은 알지 못 했다. 다란 기지 방어를 맡은 패트리어트 포대는 두 포대(각각 알파 포대와 브라보 포대)였는데, 이 중 브라보 포대는 레이더 문제를 해결하기 위해 가동을 중지했고 알파 포대만이 가동 중이었다. 문제는 이 알파 포대의 패트리어트 시스템이 100시간 연속해서 가동 중이었고, 그로 인해 비극이 발생했다.

 

마치 운명의 장난처럼, 수정된 소프트웨어가 다란에 도착한 것은 사건이 발생한 다음 날인 2월 26일이었다.

 

어쩌면 소프트웨어가 하루만 더 일찍 다란에 도착했었다면, 이 사건은 일어나지 않았을 지도 모른다.

시간 순서에 따른 사건 요약

  • 2월 11일 - 패트리어트 프로젝트 팀이 RGA가 이동하는 소프트웨어 오류 발견, 즉시 버그 수정 착수
  • 2월 16일 - 버그 수정 성공, 새로운 소프트웨어 패키지 배포 시작
  • 2월 21일 - 전세계 패트리어트 부대에 버그의 존재를 알리고 장기적인 패트리어트 시스템 가동에 대해서 경고, 그러나 구체적인 한계 시간을 명시하지는 않음
  • 2월 25일 - 다란에서 사건 발생, 패트리어트의 스커드 미사일 격추 실패로 28명의 미군 사망
  • 2월 26일 - 다란에 버그가 수정된 소프트웨어 패키지 도착

아리안5 로켓 폭발 사고

패트리어트 미사일 격추 실패 사건 외에, 한 가지 더 소수점에 관한 유명한 사고를 살펴보자. 바로 아리안5 로켓 폭발 사고이다.

아리안5 로켓
아리안5 로켓, 사진 출처: 위키피디아

유럽우주국 ESA(European Space Agency)에서 만든 아리안5 로켓은 아리안스페이스(Ariane Space)를 대표하는 로켓이다. 1996년부터 2023년까지 운용되어 총 117번의 발사를 마쳤으며, 그 중 112번의 발사에 성공했다. 특히 2003년부터는 100번 연속 발사에 성공하여 놀라운 안전성을 입증했으며, 2021년 12월 25일 JWST의 발사에도 아리안5 로켓이 사용되었다.

 

하지만 이러한 모습의 아리안5가 있기까지, ESA는 초창기에 여러 시행착오를 겪어야만 했다. 그중 아리안5의 첫 번째 발사이자 실패인 아리안5 - 501편 폭발 사고를 소개하겠다.

아리안5 로켓의 폭발과 오버플로우 오류

아리안5 폭발 사고 장면
아리안5 폭발 사고 장면

1996년 6월 4일, 현지 시각 9시 33분 59초, 프랑스령 기아나, 아리안5 - 501편 로켓이 발사되었다. 발사 후 36초 후 로켓은 자세 제어 능력을 상실하여, 몸체가 기운 후 폭발하였다.

 

ESA는 이후 조사에서 이 사고의 원인이, 어이없게도 64bits 실수형에서 16bits 정수형으로의 형 변환 과정에서 일어난 오버플로우때문이라는 것을 알아냈다.

 

즉 8바이트 double 형에서 2바이트 short 형으로의 변환 과정에서 일어난 오버플로우 때문에 문제가 발생하였다(C언어로 쉽게 따지자면).

 

현대에서는, 만약 C/C++ 언어로 double에서 short로 type cast를 시도하려 한다면, 컴파일러 경고가 뜨면서 오버플로우 오류가 날 수 있음을 프로그래머가 알 수 있게 해줄 것이다. 하지만 이때 발생한 사고는 그리 단순한 문제는 아니었다.

소스 코드 분석

당시 문제가 발생했던 소스 코드를 살펴보자. 이 소스 코드는 아리안5에 탑재된 SRI(Inertial Reference System, 또는 IRS라 한다)라는 모듈에 사용되는 코드로, SRI는 로켓의 현재 고도와 속도를 측정한다. 소스 코드는 Ada 언어로 작성되어 있다.

L_M_BV_32 := TBD.T_ENTIER_32S ((1.0/C_M_LSB_BV) BV) * G_M_INFO_DERIVE(T_ALG.E_BV));

if L_M_BV_32 > 32767 then
        P_M_DERIVE(T_ALG.E_BV) := 16#7FFF#;
elsif L_M_BV_32 < -32768 then
        P_M_DERIVE(T_ALG.E_BV) := 16#8000#;
else
        P_M_DERIVE(T_ALG.E_BV) := UC_16S_EN_16NS(TDB.T_ENTIER_16S(L_M_BV_32));
end if;

P_M_DERIVE(T_ALG.E_BV) := UC_16S_EN_16NS (TDB.T_ENTIER_16S((1.0/C_M_LSB_BH) * G_M_INFO_DERIVE(T_ALG.E_BV)));

이를 우리에게 익숙한 C언어로 바꾸어보자.

int32_t L_M_BV_32 = (int32_t)((1.0 / C_M_LSB_BV) * G_M_INFO_DERIVE(T_ALG.E_BV));

if (L_M_BV_32 > 32767) {
    P_M_DERIVE(T_ALG.E_BV) = 0x7FFF; 
} else if (L_M_BV_32 < -32768) {
    P_M_DERIVE(T_ALG.E_BV) = 0x8000; 
} else {
    P_M_DERIVE(T_ALG.E_BV) = UC_16S_EN_16NS((uint16_t)L_M_BV_32); 
}

P_M_DERIVE(T_ALG.E_BV) = UC_16S_EN_16NS((uint16_t)((1.0 / C_M_LSB_BH) * G_M_INFO_DERIVE(T_ALG.E_BV)));

오버플로우 문제가 발생한 곳은 마지막 줄이다. 바로 위에서는 if-else 구문으로 오버플로우에 대한 에러 처리를 하고 있다. 그러나 마지막 줄에서는 예외 처리를 하지 않고, 64bits 실수형에서 16bits 정수형으로 바로 변환하면서 문제가 발생했다.

 

조사위원회는 이러한 연산자 변환 오류의 위험을 앉고 있는 변수를 7개 발견하였고, 이중 4개는 if - else에 의한 예외 처리로 보호되어 있지만 3개는 보호되지 않았음을 확인했다.

 

프로그래머가 if-else문을 작성하는 것을 까먹었을까? 아니다.

 

당시 기능 명세에 적힌 목표 조건 중 하나는, SRI 모듈의 목표 CPU 최대 부하치가 80%에 맞춰져 있었기 때문이다.

 

만약에 모든 구문을 if-else문으로 감싸게 된다면, 최대 CPU 부하치가 80%를 넘길 수 있었다. 그렇기에 기능 명세를 맞추기 위해서 일부 if-else 문을 제외할 수 밖에 없었고, 이로 인해 사고가 발생하였다.

아리안5의 구조

하지만 사고가 발생하게 된 더 근본적인 원인이 하나 더 있다. 이를 알기 위해서는 아리안5 로켓의 구조와, 자세한 사고 경위에 대해서 알아야 한다.

 

아리안5는 기본적으로 아리안4 로켓을 계승하기 위해 만들어진 로켓이다. 완전히 새롭게 설계하기는 했지만, 일부 부품은 아리안4 로켓의 그것을 재활용했다. 그 중 하나가 바로 SRI이다. 아리안4 로켓 역시 116번의 발사 중 113번을 성공했을 정도로 매우 신뢰성 높은 로켓이었기에, 아리안4의 SRI 모듈을 재활용하는 것은 경제적으로 현명한 선택이었을 것이다.

SRI의 역할
SRI는 OBC에게 가속도, 각속도, 고도 등을 전송한다.

아리안5는 두 대의 SRI을 탑재하고 있다. 하나는 메인으로 사용되고, 다른 하나는 메인으로 쓰이는 SRI가 정상 작동하지 않을 경우를 대비해서 예비용으로 사용된다. SRI는 매우 중요한 부품이기에 예비용 SRI는 메인 SRI가 정지할 경우 즉각 가동할 수 있도록, hot-standby 모드로 가동 중이었고, 이를 위해 두 대의 SRI는 동일한 데이터를 입력받고 있었다.

 

SRI의 제어는 OBC(On Board Computer)가 제어한다. OBC는 SRI가 넘겨주는 데이터를 바탕으로 엔진 노즐의 각도와 추력을 조절해 비행 궤도를 유지한다. 이러한 OBC 역시 이중화되어 있었다.

사고의 발생 과정

사고의 자세한 발생 과정을 추적하겠다. $H_0$는 발사 시각을 의미한다.

  • $H_0 - 3$ 초: SRI가 Alignment 모드에서 Flight 모드로 전환.
    • 이때부터 이미 SRI의 소프트웨어는 오작동하기 시작했다.
    • Flight 모드로 전환된 후에도, 작동하지 말아야 할 Alignment 모드의 일부 기능들이 계속해서 작동했기 때문이다.
  • $H_0 + 36.672$초: SRI-2의 동작 정지.
    • 16bits 정수형을 사용하는 SRI-2가 64bits 실수형 데이터를 입력받으면서, 오버플로우 에러로 인해 SRI-2가 동작을 정지하였다.
    • 이 문제는 Flight 모드의 소프트웨어에서 발생한 것이 아니라, 실행되지 않았어야 하는 Alignment 모드의 소프트웨어에서 발생되었다.
  • $H_0 + 36.744$초: OBC가 SRI-1으로의 전환 시도 - 실패
    • OBC가 SRI-2로부터 데이터를 받지 못하자, 즉시 SRI-1으로의 전환을 시도했다.
    • 문제는… SRI 둘 다 똑같은 SW를 쓰는데, hot-standby를 위해 둘 다 똑같은 데이터를 입력받는다. 당연히 SRI-1 역시 동일한 64bits 실수형 데이터를 입력받고 오버플로우 문제로 작동을 정지한 상태였다.
  • $H_0+37.032$초: OBC는 SRI로부터 정상적인 데이터를 받지 못 하자 엔진 노즐을 정상적으로 컨트롤하지 못 하고, 기체가 기울기 시작했다.
  • $H_0 + 39.3$초: OBC-1의 기능 중지. 시스템은 곧바로 OBC-2로 전환
    • 이때 이미 로켓이 기울어, 부하를 견디지 못한 로켓에 손상이 가기 시작했다.
  • $H_0 +40.45$초: 로켓 부스터 1기 소실. 로켓이 파괴되기 시작
  • $H_0 + 40.55$초: 로켓이 화염에 휩싸임.
  • $H_0+66$초: 관제소는 임무의 실패를 판단, 자폭 명령 송신. 로켓은 자폭 명령 수신 후 자폭.

한 짤 요약 가능하다.

 

좌: 사고 발생 과정 요약 / 우: 주요 사건 발생 과정(36~37초 대 SRI 모듈의 정지)

두 번째 원인 - 명세 실패와 테스트 실패

결론적으로 아리안4 로켓의 SRI 모듈을 아리안5 로켓에 어거지로 우겨넣은 게 문제의 시작이었다.

 

ESA는 이를 SRI 시스템 명세서의 인터페이스 부문 명세의 실패라 지적하였다. SRI 시스템 명세서에는 아리안4 외의 사용에 대한 어떤 제약 사항도 명시해놓고 있지 않았다.

 

동시에 테스트 부족에 대해서도 문제가 많았다. SRI에 대해 카운트다운, 비행, 궤도 진입에 대한 테스트를 실시하지 않았던 것이 밝혀졌다. 이때 시뮬레이션을 통해서 테스트를 했었더라면, SRI에서 발생하고 있는 문제점들을 미리 파악할 수 있었을 것이란 지적이다.

 

그러나 당시 ESA는 SRI이라는 모듈 자체에 대해, 이미 아리안4에서 안정성이 검증되었으므로 기기 자체가 안전할 것이라 믿었다. 아리안4에서 잘 작동했으므로 아리안5에서도 잘 작동하리라 막연히 생각할 뿐이었다.

 

실제로 SRI에 대해 테스트한 부분은 아리안5의 OBC와 잘 연결되는 지, 호환성 부분만 검증되었다.

결론적으로 이 문제의 근본적인 시발점은, 호환되지도 않는 SRI를 아리안5 로켓에 아무런 테스트 없이 재사용했다는 것이다.

사고 이후 ESA의 대응

사고 조사 보고서에서 발췌한 대응 방안사고 조사 보고서에서 발췌한 대응 방안 2
사고 조사 보고서에서 발췌한 대응 방안

한편 사고 이후 ESA의 대응은 주목할 만하다. 문제의 원인을 파악하자 마자, 곧바로 조사 보고서에서 SW 시스템 테스팅에 관한 가이드라인을 새로 짤 것을 지시했다. 근본적인 문제의 원인인 소프트웨어의 명세 부분을 새롭게 문서화하고, 임베디드 소프트웨어를 포함한 모든 비행 소프트웨어를 다시 검토하였다. 특히 Single Point Failure을 가진 부품들, 곧 critical components(반드시 성공이 보장되어야 하는 부품들)에 대한 검증이 이루어졌다. 외부에도 코드와 명세 문서를 공개하여, 외부로부터도 리뷰를 받을 수 있게 하였다.

 

즉 전반적인 리뷰/테스트/기능 명세와 문서화에 대한 가이드라인이 강화되었다. 즉 실수로부터 시스템을 보완하여, 다시 같은 실수를 반복하지 않으려는 의지가 느껴진다.

 

실제로 이러한 노력 끝에 아리안5는 2023년 은퇴하기까지 세상에서 가장 신뢰받는 로켓으로 평가받았다. 일반인들에게 있어 가장 유명한 로켓 세 개를 뽑으라 하면 아마 러시아의 소유즈, SpaceX의 팔콘, 그리고 아리안5 로켓이 아닐까 싶다.

 

지금은 아니겠지만, 예전에 우리나라였으면, 아마 담당자에게 책임을 물어 해고한 뒤에, 시스템적으로는 아무 변화가 없었을 가능성도 있다. 단순히 개인의 책임에서 끝나지 않고, 시스템을 개선하려는 이러한 모습은 본받을 만하다.

📚 참고자료

  • GENERAL ACCOUNTING OFFICE WASHINGTON DC INFORMATION MANAGEMENT AND TECHNOLOGY DIV. Patriot Missile Defense: Software Problem Led to System Failure at Dhahran, Saudi Arabia. 1992.
  • 김종하. 역사 속의 소프트웨어 오류 : 부실한 소프트웨어가 초래한 위험천만한 사건 사고들. 에이콘출판사, 2014.
  • LIONS, Jacques-Louis, et al. Flight 501 failure. Report by the Inquiry Board, 1996.
  • Some disasters attributable to bad numerical computing