科学大院

美军爱国者导弹拦截失败,只因算错了这个“小数点”

Image

本篇文章正文共2435字

预计阅读时间约为7分钟

计算机对实数的理解,就像狗对π的理解一样肤浅。 

—— DeepSeek

飞来横祸

1991年2月25日,第一次海湾战争正如火如荼地进行着。当天晚上20时40分左右,突如其来的爆炸声划破了沙特达摩地区宁静的夜空——伊拉克发射的"飞毛腿"导弹精确命中美军位于达兰的空军基地。霎时间,原本秩序井然的军营化作一片火海,哀嚎遍野。

Image美军在化作废墟的军营中搜寻生还者

当时美军为了防范伊拉克的导弹袭击,早已在重要军事据点部署了以"爱国者"导弹为核心的拦截系统。不过在这场致命的袭击中,号称先进的"爱国者"系统忠实地充当了“吃瓜”群众的角色,对来袭的导弹毫无反应。最终,袭击导致28名美军士兵丧生,97人受伤,这成为海湾战争期间美军最惨重的单次伤亡事件。事后的调查显示,这场灾难的罪魁祸首是一个看似微不足道的数字计时器精度问题。

浮点运算的“迷惑”

实数在计算机中的表示,也就是浮点数,是科学计算操作的基本对象。可以想见,只具备有限存储空间的计算机永远也不能精确地表示不可数的实数集合。就像上文提到的爱国者,它的计时器只有24位精度。在连续运行100小时后,系统已经累计出了的0.34秒的误差。对于以6倍音速飞行的导弹而言,这相当于700米的定位偏差,足以让整个防御系统形同虚设。

浮点数表示的标准化肇始于上世纪80年代产生的IEEE754规范。随着体系架构的演进,近三十年来计算机工业完成了从32位至64位系统的变革。现代计算机系统已经普遍支持64位双精度浮点数,但这绝不意味着使用者可以忽视数值精度背后的复杂性。数值计算的艺术就是与误差共舞的艺术,"舞技"不好的表演者会在意想不到之处付出惨痛的代价……

读者对浮点数运算的性质了解多少呢?猜一猜下面这个表达式的结果:

>>> 0.1 + 0.1 == 0.2

试着在计算机上运行一下,返回结果为True,看起来一切正常。然而,很容易构造一个可能让人小吃一惊的案例:

>>> 0.1 + 0.2 == 0.3

返回的结果为False。事实上,双精度浮点计算下0.1+0.2的结果是

>>> 0.30000000000000004

浮点数的表示原理

人类使用十进制系统的原因很可能是我们拥有十根手指。但是在构造一个机器系统时,只有两种状态的比特位是最容易实现的。所以对于计算机,二进制表示是更自然的方式。在表示数时,十进制的位拥有10的若干次幂的权重。类似地,二进制(比特)位带有2的若干次幂权重。下面的一个从二进制转换至十进制的案例很好地说明了这一点:

十进制的有限小数并不总是二进制中的有限小数,比如十进制0.1在二进制中表示为(横线表示循环节)。当映照在计算机上时,二进制规格化浮点数以科学计数法的形式被存储:

对于64位双精度浮点数,计算机使用52位来存储的值,不能被表示的有效位采取就近舍入的规则(就近值的误差相等时向偶数舍入)。举一个例子,0.1会按照以下的方式舍入并存储。

1.1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 [1001...]  * 2^(-4)--------------------------------------------------------------------------------------1.1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010  * 2^(-4)

0.2正好是0.1的两倍,表示0.2只需要将0.1的e加1,F 部分则是完全相同的。计算0.1+0.1时,发生的是如下的事:

   1.1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010  * 2^(-4)+   1.1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010  * 2^(-4)--------------------------------------------------------------------------------   11.0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0100  * 2^(-4)=   1.1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010  * 2^(-3)

等号后的结果恰好是0.2的二进制表示。计算机并不能精确地存储0.1与0.2,但它正确地判断了0.1+0.1的结果是0.2!

为什么 0.1+0.2 ≠ 0.3

对于0.3,它的二进制科学计数法表示是,舍入后得到

 1.0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 * 2^(-2)

由于0.2和0.1的指数 E 不同,计算两数的和时要先对齐指数,0.1先转化成

0.1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1101  * 2^(-3)

然后进行加法和舍入:

1.1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010  * 2^(-3)+   0.1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1101  * 2^(-3)--------------------------------------------------------------------------------   10.0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0111  * 2^(-3)=   1.0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0100  * 2^(-2) 

这个结果与先前提到的0.3的位级表示并不相同,所以0.1+0.2的结果便不等于0.3。它转化成十进制后是

在此,我们恢复了先前计算产生的结果。

爱国者导弹

“爱国者”导弹系统内置了一个用于计时的钟——每0.1秒进行一次更新。与IEEE规则不同,这个运算是通过24位固定小数点寄存器实现的——在不采用科学计数法的情况下直接存储0.1的二进制表示。按理说,与0.1最接近的计算机近似表示是它的过剩值:

0.00011001100110011001100[1100...]-------------------------------0.00011001100110011001101

可是“爱国者”系统莫名其妙地使用了直接截断的不足近似值:

0.00011001100110011001100

这一选择让误差又被放大了4倍!计时器的每一次自增造成的误差是

事实上,在2月11日,“爱国者”导弹项目组在分析以色列军方提供的系统日志时已经发现了这个软件错误:当系统连续工作8小时以上时,定位目标就会偏离正常位置的20%。他们在21日向所有使用“爱国者”的部队发出了消息:在“长时间”启动“爱国者“系统的情况下,射程就会发生偏离,导致追踪目标的失败。也许是项目组觉得军方肯定不会让导弹系统的运行时间长到无法成功追踪目标,他们在发出的通告中完全没有解释这个“长时间”究竟是多长时间……

2月26日,也就是事故发生后的第二天,修复后的软件被运抵了达兰空军基地。

结语

从现在的视角来看,"爱国者"导弹的悲剧并不是源于什么深奥的技术谜题,但是简单的bug依然可以让人们付出惨痛的代价。人类认识世界、改造世界的步伐就是以这样一种蜿蜒曲折的方式前进着。浮点运算像是布满暗礁的海域,理解了潮汐规律的人才能安全航行。在数字化浪潮席卷一切的今天,每个0与1的抉择都可能成为命运的转折点。我们无法彻底消除误差,但每一次跌倒后的反思都将让我们在下一次跌倒前走得更稳、更远——只要我们永不停止从错误中学习的脚步。

参考文献:

[1] Randal E. Bryant, David R. O’Hallaron. Computer Systems: A Programmer’s Perspective (3rd edition). Pearson. 2015.

[2] ⾦钟河,叶蕾蕾译. 致命Bug,软件缺陷的灾难与启示. 人民邮电出版社. 2016.

[3]Wikipedia https://en.wikipedia.org/wiki/Iraqi_ballistic_missile_attacks_on_Saudi_Arabia.

作者简介

姜洋,中国科学院理论物理研究所2022级博士研究生。

Image

版权说明:未经授权严禁任何形式的媒体转载和摘编,并且严禁转载至微信以外的平台!


文章转载自“中国科学院理论物理研究所”,仅代表作者观点,不代表科学大院立场。转载请联系[email protected]

Image

推荐阅读

诺贝尔物理学奖颁给了计算机学家? >>

“碳中和”这道计算题有多复杂?>>

π日说π:π能不能被算尽?>>

光速为什么正好是299792458米/秒>>

Image

推荐资源

关注使用“科学与中国”小程序,可观看以院士科普视频为代表的优秀科普视频,第一时间获取中国科学院公众科学日、科学节等科普活动报名信息。

Image

科学大院是中国科学院官方科普微平台,致力于最新科研成果的深度解读、社会热点事件的科学发声

主办机构:中国科学院学部工作局

运行机构:中国科学院计算机网络信息中心

技术支持:中国科普博览

转载授权、合作、投稿事宜请联系[email protected]

大院er拍了拍你:不要忘记 

点亮这里的 赞 和 在看 噢~