前一陣iPhone變磚問題引起很多人的關(guān)注惩妇,還有好奇寶寶去嘗試,結(jié)果......
有一種Bug叫時(shí)間Bug厦章,現(xiàn)在今野,我們來解析下,那些讓計(jì)算機(jī)難以理解的人類的時(shí)間計(jì)算問題饺鹃。
20世紀(jì)后期致盟,全世界都沉浸在對(duì)21世紀(jì)的希望和憧憬之中。但是尤慰,關(guān)注計(jì)算機(jī)的人們卻在為一個(gè)問題大傷腦筋,就是計(jì)算機(jī)系統(tǒng)將2000年當(dāng)作1900年處理的“Y2KBug”(千年蟲)難題雷蹂∥岸耍“末日論”擁護(hù)者們甚至擔(dān)心計(jì)算機(jī)會(huì)全體罷工,而人類則走向滅亡匪煌。好在人們事先考慮到了這個(gè)問題责蝠,并做出了應(yīng)對(duì)措施,這才安然無恙地迎來了新千年萎庭。
正如在陽光強(qiáng)烈的白晝看不到星光一樣霜医,與時(shí)間有關(guān)的Bug中,Y2KBug太有名了驳规,以至于其他事件在它面前都不足以成為人們茶余飯后的談資肴敛。但事實(shí)上,和時(shí)間有關(guān)的Bug是軟件誕生以來最為頻發(fā)的Bug類型之一吗购。自軟件誕生起到現(xiàn)在医男,仍然不時(shí)有此類Bug發(fā)生。與時(shí)間有關(guān)的Bug類型主要有:對(duì)閏年現(xiàn)象處理不當(dāng)導(dǎo)致的Bug捻勉、Y2KBug镀梭、源于計(jì)算機(jī)結(jié)構(gòu)的先天性Bug等。
閏年
雖然人們常說1年有365天踱启,但事實(shí)上报账,地球圍繞太陽公轉(zhuǎn)一周所用的時(shí)間并非365天,嚴(yán)格來說需要365天5小時(shí)48分46秒埠偿。公歷上減去365天后透罢,余下的時(shí)間約為4年累計(jì)1天,故每4年于2月加1天冠蒋,變?yōu)?9天琐凭,使當(dāng)年的長度為366天,該年就為閏年浊服。
但是统屈,規(guī)定每4年必須有一閏年的日歷是儒略歷胚吁,其制定者就是說出那句“布魯圖斯,連你也……”名言的羅馬的尤利烏斯·愷撒愁憔。不過腕扶,儒略歷隨著時(shí)間的推移會(huì)產(chǎn)生一定誤差。而彌補(bǔ)這一缺陷的便是現(xiàn)在大多數(shù)國家正在使用的格里高利歷吨掌,其制定者是教皇格里高利十三世半抱。
儒略歷規(guī)定4年一閏。也就是說膜宋,400年中有100年是閏年窿侈,且400年中共增加100天。這種方法雖然可以糾正地球公轉(zhuǎn)引起的偏差秋茫,但還不夠精確史简。而彌補(bǔ)了這一點(diǎn)的格里高利歷中,400年間肛著,閏年只有97次圆兵,比儒略歷少了3次。這樣人們?cè)跁r(shí)間的計(jì)算上就精確多了枢贿,但與4年無條件有1次閏年的儒略歷相比殉农,它的閏年計(jì)算方法更為復(fù)雜。
以下是計(jì)算閏年的公式:
- 可以被4整除的年份是閏年(2008年局荚、2012年超凳、2016年……)
- 其中能被100整除的年份為平年(2100年、2200年耀态、2300年……)
- 平年中可以被400整除的年份是閏年(1600年聪建、2000年、2400年……)
如果隨便問一個(gè)路人什么是閏年茫陆、如何計(jì)算閏年金麸,十個(gè)人中有九個(gè)會(huì)答不上來。因?yàn)橛?jì)算的公式本身比較復(fù)雜簿盅,而且就算不知道也不會(huì)影響自己的日常生活挥下。不知計(jì)算機(jī)程序員是否也沒將這個(gè)問題放在眼里,從而忽略了和閏年相關(guān)的軟件Bug桨醋,導(dǎo)致其成為軟件Bug界的“撑镂粒客”。
微軟的野心之作與閏年Bug
已經(jīng)去世的史蒂夫·喬布斯被人們稱為“創(chuàng)新符號(hào)”和“怪才”喜最,他回歸“蘋果”公司后取得的首次巨大成功就是便攜式媒體播放器(一般稱為MP3播放器)——iPod偎蘸。看到這款產(chǎn)品在世界范圍內(nèi)掀起了一股風(fēng)潮,而且銷量驚人迷雪,全世界的家電企業(yè)都開始進(jìn)軍便攜式MP3播放器市場(chǎng)限书。在便攜式媒體播放器領(lǐng)域從未嘗到過甜頭的三星公司曾經(jīng)將便攜式MP3播放器領(lǐng)域的管理部門作為子公司分離了出去,在iPod風(fēng)潮的沖擊下章咧,三星公司重新合并了子公司倦西,決定向該領(lǐng)域發(fā)起沖擊。
軟件公司微軟也不想錯(cuò)過“這塊蛋糕”赁严,推出了名為“Zune”的產(chǎn)品扰柠,想要制衡“蘋果”公司。
但是疼约,曾通過推出Windows而壟斷個(gè)人計(jì)算機(jī)操作系統(tǒng)的微軟在iPod面前也敗下陣來卤档。禍不單行,美國當(dāng)?shù)貢r(shí)間2008年12月31日0時(shí)起程剥,微軟公司30GB 版Zune音樂播放器同時(shí)出現(xiàn)了大規(guī)模的無法啟動(dòng)故障劝枣。微軟公司發(fā)布聲明稱:“正在努力解決這個(gè)問題,將會(huì)通過Zune官方網(wǎng)站盡快公布解決方法倡缠。”為控制事態(tài)發(fā)展茎活,微軟可謂大傷腦筋昙沦。
其實(shí),原因就出在閏年上载荔。Zune中內(nèi)置的日期計(jì)算軟件計(jì)算當(dāng)前日期時(shí)盾饮,閏年計(jì)算出現(xiàn)錯(cuò)誤,導(dǎo)致機(jī)器無法啟動(dòng)懒熙。既然找明了原因丘损,解決起來就容易了。出現(xiàn)故障24小時(shí)后工扎,2009年1月1日徘钥,日期不同了,年份也變了肢娘,Zune也就恢復(fù)了正常呈础。
之后,微軟到2011年為止又相繼推出多款產(chǎn)品橱健,但最終都沒能超越iPod而钞。終于,2011年3月拘荡,微軟宣布停止生產(chǎn)Zune 播放器臼节。
讓全世界游戲玩家備受煎熬的PS3閏年Bug
2010年3月1日,日本索尼公司的電視游戲機(jī)Play Station3(以下簡稱PS3)出現(xiàn)了死機(jī)現(xiàn)象。出現(xiàn)問題的并非當(dāng)時(shí)最新款的PS3薄版网缝,而是舊版PS3巨税。這個(gè)故障使全世界眾多玩家一整天都沒能玩到游戲。而這天是韓國的公休日(三一節(jié))途凫,正是玩游戲的大好時(shí)間垢夹,所以韓國的玩家們才更倒霉。很多韓國玩家這一天只能對(duì)著屏幕上的故障畫面發(fā)呆维费、抓狂果元。
2010年3月1日啟動(dòng)PS3 后,韓國等亞洲國家的時(shí)間會(huì)變更為2000年1月1日犀盟,而美國等北美國家則變?yōu)?999年12月31日而晒。而且玩家無法聯(lián)網(wǎng),達(dá)到一定等級(jí)后積累的個(gè)人游戲記錄和名下的獎(jiǎng)品亦告消失阅畴,同時(shí)屏幕彈出“獎(jiǎng)品信息登錄失敗倡怎。游戲結(jié)束。(8001050F)”的消息贱枣。這個(gè)故障也是閏年Bug引起的监署。到了第二天,3月2日纽哥,問題自動(dòng)解決钠乏,機(jī)器又恢復(fù)正常。
醫(yī)院系統(tǒng)故障春塌,紙筆代替電腦
1989年9月19日上午晓避,位于賓夕法尼亞州的醫(yī)療共享系統(tǒng)(Shared?Medical Systems,以下簡稱SMS)公司的電話鈴聲此起彼伏只壳。打電話的雖然不是同一個(gè)人俏拱,但說的話都一樣:
“醫(yī)院系統(tǒng)停止工作了『鹁洌”
這一天锅必,美國全境一百多家醫(yī)院不得不放棄之前一直使用的計(jì)算機(jī)系統(tǒng),改為用紙筆記賬惕艳。使用SMS提供的軟件和系統(tǒng)的所有醫(yī)院都出現(xiàn)了這樣的情況况毅。SMS技術(shù)人員認(rèn)定這是突發(fā)狀況,作為權(quán)宜之計(jì)尔艇,他們建議所有醫(yī)院都關(guān)閉計(jì)算機(jī)尔许,然后開始尋找事故原因。
幾小時(shí)后终娃,人們查明了原因味廊。SMS開發(fā)的軟件出現(xiàn)錯(cuò)誤,計(jì)算機(jī)無法識(shí)別1989年9月19日這個(gè)日期,所以出現(xiàn)故障余佛。那為什么是9月19日呢柠新?原因就在于16位數(shù)據(jù)結(jié)構(gòu)。當(dāng)時(shí)醫(yī)院使用的電腦是以1900年1月1日為起點(diǎn)計(jì)算日期的辉巡。故障發(fā)生的1989年9月19日在起點(diǎn)基礎(chǔ)上又過了32 768(即215)天恨憎,已經(jīng)超出了16位數(shù)據(jù)結(jié)構(gòu)可以承受的數(shù)字范圍0~32 767。因此郊楣,計(jì)算機(jī)無法識(shí)別這個(gè)數(shù)字憔恳,系統(tǒng)就出現(xiàn)故障。
這次故障并沒有造成數(shù)據(jù)丟失或者醫(yī)療器械停止工作從而危及患者生命的事故净蚤,但另一個(gè)不能忽視的問題是钥组,今后仍然存在發(fā)生此類問題的隱患。尤其是現(xiàn)在大多數(shù)服務(wù)器都在使用的Unix 操作系統(tǒng)在時(shí)間計(jì)算上還存在著以下問題:SMS的計(jì)算機(jī)系統(tǒng)時(shí)間起點(diǎn)是1900年1月1日今瀑,而Unix是以1970年1月1日為起點(diǎn)計(jì)算日期的程梦。Unix在此基礎(chǔ)上加上系統(tǒng)時(shí)間(秒)計(jì)算日期,但問題在于橘荠,保存系統(tǒng)時(shí)間的數(shù)據(jù)類型是“32位帶符號(hào)整數(shù)”屿附。
32位帶符號(hào)整數(shù)可以存儲(chǔ)-231~231-1的數(shù)字,也就是-2 147 483 648 ~2 147 483 647哥童。1970年1月1日0時(shí)00分挺份,在UTC的基礎(chǔ)上再過2 147 483 647 秒就是2038年1月19日3時(shí)14分7秒(UTC)。從這一刻起再過1秒如蚜,也就是2038年1月19日3時(shí)14分8秒開始压恒,系統(tǒng)存儲(chǔ)的時(shí)間值不是從2 147 483 647 變?yōu)? 147 483 648影暴,而是變?yōu)椋? 147 483 648错邦。
因?yàn)榇鎯?chǔ)時(shí)間值的空間只有32位,所以無法存儲(chǔ)2 147 483 648 這個(gè)數(shù)字型宙。這樣撬呢,從2038年1月19日3時(shí)14分8秒(UTC)開始,Unix操作系統(tǒng)會(huì)將當(dāng)前時(shí)間計(jì)算為1901年12月13日20時(shí)45分53秒(UTC)妆兑。如果不盡快解決此問題魂拦,類似事件將會(huì)重演。
解決的方法其實(shí)很簡單搁嗓。只要將系統(tǒng)時(shí)間從現(xiàn)有的帶符號(hào)32位整數(shù)擴(kuò)大到64位或者128位即可芯勘。當(dāng)然也不能盲目擴(kuò)大,因?yàn)檫@涉及與時(shí)間改變相關(guān)的代碼兼容問題腺逛。最近開發(fā)的64位操作系統(tǒng)中荷愕,存儲(chǔ)時(shí)間的數(shù)據(jù)類型使用的都是64位帶符號(hào)數(shù)。使用64位帶符號(hào)數(shù)后,可以表示的最后時(shí)間是292 277 026 596 年12月4日(約2920億年)安疗。但與現(xiàn)有代碼實(shí)現(xiàn)兼容的常規(guī)解決方案尚未出現(xiàn)抛杨。
罷工的導(dǎo)航儀
2012年3月31日,美國荐类、澳大利亞怖现、英國等地使用的TOMTOM導(dǎo)航儀突然停止工作,屏幕上出現(xiàn)“無法連接到GPS衛(wèi)星”的消息玉罐,此外不顯示任何信息屈嗤。幾天后,TOMTOM的生產(chǎn)廠家發(fā)布了用于修復(fù)的補(bǔ)丁程序厌小。引起這次故障的元兇就是GPS接收器所用的軟件恢共。軟件出現(xiàn)閏年Bug,使整個(gè)導(dǎo)航儀變?yōu)闊o用之物璧亚。本來TOMTOM 就在與智能手機(jī)內(nèi)置導(dǎo)航系統(tǒng)(谷歌地圖等)的競(jìng)爭中節(jié)節(jié)敗退讨韭,苦不堪言,這次事件讓他們又挨了當(dāng)頭一棒癣蟋。
日常生活中的Y2KBug
1992年的一天透硝,美國的瑪麗·班達(dá)爾接到了去明尼蘇達(dá)州威諾納的幼兒園上學(xué)的通知。但是疯搅,出生于1888年的瑪麗·班達(dá)爾在1992年已經(jīng)104歲了濒生。這是一個(gè)典型的Y2KBug。計(jì)算機(jī)只處理了出生年份四位數(shù)中的后兩位幔欧,以此為標(biāo)準(zhǔn)尋找學(xué)齡前兒童罪治,所以才發(fā)生了這樣的怪事。
布洛杰特101歲時(shí)礁蔗,他的汽車保險(xiǎn)費(fèi)突然上漲了3倍觉义!查明原委后發(fā)現(xiàn),還是Y2K問題在作怪浴井。電腦竟然將布洛杰特的年齡識(shí)別為1歲晒骇。這次的Y2K問題還牽出了之前一直未引起人們注意的政策性錯(cuò)誤:20歲以下一律視為青少年,所以汽車保險(xiǎn)費(fèi)上漲了3倍……等等磺浙,1歲也算是青少年嗎洪囤?
寫給軟件開發(fā)者的話
Zune 媒體播放器的用戶論壇ZuneBoard 上,有人提出撕氧,2008 年12 月31 日發(fā)生的硬件故障來自Zune 的時(shí)鐘驅(qū)動(dòng)器瘤缩。ID 名為“isnotabigtruck”的用戶在網(wǎng)站公布了飛思卡爾處理器的時(shí)鐘驅(qū)動(dòng)源代碼,并做出說明:“Zune 在啟動(dòng)過程的最后一個(gè)階段第一次訪問時(shí)鐘驅(qū)動(dòng)伦泥,將時(shí)鐘變更為日期和時(shí)間剥啤『文海” 他給出的下列代碼是從日期中計(jì)算年份。
請(qǐng)留意第9行代碼铐殃。2008年是共有366 天的閏年海洼,2008年12月31日是2008年的第366天。days 變量中輸入366后富腊,第9行的if語句會(huì)判斷為false坏逢,然后移動(dòng)到第20行。而days變量仍然是366赘被,這樣就會(huì)進(jìn)入無限while 循環(huán)是整。
以上是飛思卡爾MC13783PMIC 處理器的驅(qū)動(dòng)代碼。當(dāng)時(shí)民假,使用該處理器的東芝公司的Gigabeat S媒體播放器也曾出現(xiàn)類似情況浮入。
本文選自《致命Bug》。
作者:金鐘河
譯者:葉蕾蕾
《致命Bug》通過軟件史上的經(jīng)典案例羊异,介紹了軟件故障引發(fā)的宇宙事秀、航空、軍事野舶、通信易迹、金融、醫(yī)療平道、生活等多領(lǐng)域的事故睹欲。即使不具備軟件相關(guān)的專業(yè)知識(shí),平時(shí)關(guān)注歷史事件或熱點(diǎn)話題的普通人也能受益匪淺一屋。尤其是希望編寫無Bug軟件的開發(fā)人員或測(cè)試人員窘疮、經(jīng)營軟件公司的管理人員或高層人士等,更能從本書中獲得豐富感受冀墨。
點(diǎn)擊書名查看完整目錄與試讀闸衫。