眾所周知,計算機是從0開始計數,而不是我們平時常用的從1開始計數,但你有想過為什麼嗎?
其實不是計算機從0開始計數而是多數程式語言中的陣列都使用0作為起始下標,又是為什麼呢?
這個問題超綱了,程式喵不會,但是本著對科學的敬畏之心,經過大量的搜尋查證,我終於找到了答案。
故事還要從一位真正的大佬艾茲格·迪科斯徹(dijkstra)講起,
艾茲格·w·迪科斯徹dijkstra,結構程式設計之父,提出「goto有害論」。提出訊號量和pv原語,解決了「哲學家聚餐」問題;
dijkstra最短路徑演算法和銀行家演算法的創造者,the作業系統的設計者和開發者;,第乙個algol 60編譯器的設計者和實現者,與d. e. knuth並稱為我們這個時代最偉大的計算機科學家的人。
這裡貼出我翻譯後的大佬語錄:為了表示自然數1,2,3,4...14...的子串行,一般有四種序列的表示方法:
a) 2 ≤ i < 13
b) 1
c) 2 ≤ i ≤ 12
d) 1
以上的幾種表達方式裡,有哪一種比其他的好嗎?
是的,a和b有較為明顯的優點:他們上下界數值之間的差值就是這個序列的長度。在任何一種表示中,兩個子串行相鄰,最好是其中乙個的上界等於另外乙個的下界,但這還不能抉擇出a和b方式哪種更好,繼續分析;
假設序列裡要包含最小的自然數,如果使用b和d這種方式,那下界就必須是個非自然數,這就不太好看了,所以這裡更傾向於使用a和c的方式,即使用≤方式表示下界。這裡如果使用≤表示上界,那乙個空的子串行表示方式也將會很醜陋,所以對於上界,大佬的結論是更喜歡使用a和d中的《方式,結合上一小段的分析,a方式最終獲勝,繼續分析;
當需要表示乙個長度為n的序列時,如果想通過下標來區分其中的元素,那又來了乙個棘手的問題:初始元素的下標值應該用多少呢,如果從1開始,那範圍變成1 ≤ i < n+1,如果從0開始,那範圍會是0 ≤ i < n,顯然後一種方式更優雅更直觀,所以大佬最後的結論是自己更傾向於乙個序列的表示最好從0開始。
大佬語錄總結
在進行範圍表達的時候,使用左閉右開的方式更優雅,他思考過,在處理長度為n的序列時,到底第乙個元素的下標使用0更合適還是使用1更合適?他的出發點很簡單,那就是哪種方式更優雅。首先確定使用左閉右開的方式,當下標從1開始時,下標範圍為1<=i難道只有優雅這乙個原因嗎?其實下標從0開始主要的意義是表示偏移,下面舉例:
陣列為什麼起始下標是0?其實陣列是一種線性結構,它有一段連續的記憶體空間,儲存一組具有相同型別的資料。
如圖,拿乙個長度為10的int型別陣列舉例,系統就會為該資料分配一段連續的記憶體空間,空間大小為40個位元組,其中記憶體塊首位址base_address = 100。
第i個元素位址=base_address + i * data_type_size
其中data_type_size表示陣列中元素型別的大小,int型別大小是4位元組,所以公式裡data_type_size等於4。在這裡,下標可以理解為偏移,陣列的首位址就是base_address,其中a[0]就是偏移為0的位置,a[i]就是偏移了i個data_type_size大小的位置,所以計算a[i]位址的公式為:
a[i]位址=base_address + i * data_type_size
a[i]位址=base_address + (i - 1) * data_type_size
兩個公式顯而易見,下標從0開始的更加簡單,後者從1開始,每次訪問陣列元素都需要額外做一次減法操作,效率更低。
我們知道在python中陣列也是將0作為起始下標,對此python之父guido van rossum也給出過正面回答,下面貼出他的翻譯後的語錄:
大佬語錄
關於這個問題之前就有人在twitter上詢問過我,我給出過回答。這個問題我思考過很久:abc語言是python的祖先之一,使用的索引就是從1開始的,而另一門對python有重要影響的c語言,它的索引就是從0開始。之前的幾門程式語言(algol,fortran, pascal)有使用1作為起始索引的,有使用某個變數作為索引。而推動我使用0作為起始索引的原因之一就是切片語法。
讓我們先來看看切片的用例,可能關於切片最常見的用法就是「取前n個元素」和「取從i開始的後n個元素」,如果在使用這兩種用法時不需要帶有+1或者-1的補償操作,那**會很優雅。
使用基於0的索引方式,那上面兩種切片用法就會非常漂亮:a[:n]和a[i:i+n],前者是a[0:n]的縮寫。
使用基於1的索引方式,如果你想用a[:n]表示取前n個元素的意思,要麼使用閉合區間切片語法,要麼使用起始索引加切片長度作為引數的方法。半開區間切片方法如果和基於1的索引方式結合起來那**將會變得不優雅。而如果使用閉合區間切片語法的話,為了從第i位索引開始取n個元素,那就需要把表示式寫成a[i, i+n-1]。這樣看來也許使用切片起始位+長度的方式在基於1的索引方法中更合適?這樣你可以寫成a[i:n],並且abc語言就是這麼做的,你可以寫成a@i|n這種特別的語法。
但是,index:length這種方式在其它情況下也適用嗎?我有點記不清了,但我認為我確實是被半開區間這種優雅的語法迷住啦。特別是當兩個切片操作相鄰時,第乙個切片的終點索引是第二個切片的起始索引時,這種語法簡直太漂亮啦。例如你想要將乙個字串使用i和j分成三部分,這三部分會是a[:i],a[i:j]和a[j:],真是太漂亮啦。
這就是為什麼python使用0作為起始索引的原因。
看到這裡你知道為什麼很多程式語言都是從0開始計數了嗎?
文中如果有翻譯的不妥之處還請大家指正(可以私聊或在後台發給我),十分感謝!
參考資料
科普 為什麼電腦科學裡面計數要從0開始?
眾所周知,計算機是從0開始計數,而不是我們平時常用的從1開始計數,但你有想過為什麼嗎?其實不是計算機從0開始計數而是多數程式語言中的陣列都使用0作為起始下標,又是為什麼呢?經過大量的搜尋查證,我終於找到了答案。故事還要從一位真正的大佬艾茲格 迪科斯徹 dijkstra 講起,艾茲格 w 迪科斯徹di...
從0開始製造計算機 1
參考書籍 計算機系統概論 原書第2版 yale n.patt著 pdf 編碼 隱匿在計算機軟硬體背後的語言 1 三極體 三極體像乙個漢堡,中間是半導體a,兩邊是半導體b。三極體的特性是乙個開關。中間加高電壓,則導致導通,變為二極體。npn型三極體,採用高純矽,中間加磷,兩邊加磞。pnp型,採用鍺材料...
計算機基礎 計算機為什麼要使用補碼?
三 為什麼使用反碼?四 為什麼使用補碼?五 原碼 反碼 補碼優缺點 六 總結 n位補碼能表示的範圍 原碼中的符號位僅用來表示數的正 負,不參加運算,進行運算的只是數值部分。原碼運算時,應首先比較兩個數的符號,若兩數的符號相同,則可將兩個數的數值相加,最後給結果附上相應的符號 若兩數的符號不同,則需比...