《松本行弘的程序世界》讀書筆記(下)——文字編碼、整數、浮點小數

先貼上上一篇博客:這些基礎知識你都了解嗎?——《松本行弘的程序世界》讀書筆記(上)
上一篇講到:
- 面向對象
- 設計模式
- ajax
- MVC和猴子補丁
這一篇講《松本行弘的程序世界》書中提到的編碼、正則和數字。
7. 文字編碼
7.1 理解編碼
計算機只能處理二進制數據,從計算機被發明出來它是這樣,到現在還是這樣。那么我們要讓這個只能識別“010101...”二進制的家伙去處理文字,該怎么辦呢?——把文字表示成二進制。大家可以查看unicode(下文將介紹unicode)編碼表,看看其中中文編碼那一塊,比如,16進制的4e07表示“萬”字:

說到這里讓我想起來,平時我們在新聞留言、QQ聊天或者發短信的時候,可以發一些表情——
,大家可能都知道這些表情是用一些特殊的字符串規定好的。其實,這就是一個簡單的表情編碼,和計算機中文字編碼成二進制一個道理。
7.2 ASCII碼
當初計算機是美國人發明的,最早也在美國被應用。美國人用英語,所謂的字符只有26個英文字母,大小寫都算上,也不過52個,在算上鍵盤上那些亂七八糟的標點符號,最多100來個。于是他們發明了用7位二進制數構成的編碼表——ASCII碼。2的7次方=128。ASCII碼可表示128個字符。計算機中8位二進制是一個字節,還能剩下一位,用于附加錯誤碼(作者:不知錯誤碼為何意??)

上圖中,用二進制數“1000001”表示的是字母“A”,十進制是65,咱們學C語言的時候,估計都能背過——'A'轉換成int是65,現在知道什么意思了吧。。。
下圖是ASCII碼對應的值(十進制表示):

7.3 unicode字符集
世界上的文字有很多種,除了用A-Z表示的文字之外,還有許多歐洲、亞洲的文字是用其他圖形表示的,比如咱們的中文(簡體和繁體還不一樣)。于是,ASCII碼不能滿足要求之后,有出現了很多種編碼方式,例如中國的GB2312字符集。不過現在業界越來越統一到unicode字符集中。所以,就簡單介紹unicode字符集。
ASCII碼用7位二進制,可表示128個字符,而最初的unicode字符集用16位二進制表示,2的16次方=65536,可表示6萬多個字符。unicode字符集最初的設計者預計6W多個字符足以表示世界上所有語言文字了,可惜他們錯了。后來unicode字符集又擴充到了21位。
從網上可以查到所有unicode編碼表的內容,以下是截取的一個片段。例如,漢字“萬”的編碼是16進制數 4e07:

7.4 unicode的字符編碼方式
雖然unicode字符集將世界上的文字字符全部統一了編碼,但是這個編碼的存儲方式,卻又分為好幾種,例如大家常見的UTF-8、UTF-16、UTF-32。
例如,漢字“萬”的編碼值是16進制數 4e07 ,但是通過UTF-8計算出的存儲結構和UTF-16是不一樣的。所以,如果用UTF-16的方式去解析UTF-8編碼的數據,可能會出現亂碼。
至于每種編碼方式是怎樣的,這里就不再詳細介紹了。其實書中也只是講了一點皮毛。大家了解即可。
8 正則表達式
我接觸正則表達式是在學習js中接觸的,js應用正則表達式比較簡單,但是正則表達式本身的語法卻很復雜。
后來看jQuery源碼,被sizzle這塊的正則表達式給完全搞暈了,到現在都沒梳理好。
書中介紹的無非就是正則表達式的若干語法,以及Ruby如何支持。
其實學習正則表達式不用看這個,推薦一個:正則表達式30分鐘入門教程(提醒:說30分鐘是忽悠你,用倆小時全部看完并理解,就不錯了!)
9. 整數與浮點小數
整數和浮點小數,是程序開發中最常用的類型之一。如果你覺得程序對數字的操作非常簡單,無非就是加減乘除,那么請你耐心看完下面的文字。
9.1 整數是有范圍的
在C、C++、C#等靜態類型的語言中,int一般表示32位整數,也就是用32個二進制數表示一個整數,除去一個符號位,int所能表現的最大整數是有限的。
C#中,int32 和 int64 分別表示不同位數的整數,都有最大值和最小值的標志:

如果程序中的數字,超過了最大值,無法通過編譯,提示溢出。同理,如果運行時出現了這樣的情況,也會拋出異常。

另外,不光整數有范圍。浮點小數也有范圍大小,原理一樣。
不過浮點小數還有其他要說的內容,下文介紹。
9.2 為何Ruby中的整數沒有范圍
任何語言都無法從根本上行使整數沒有范圍。Ruby是動態類型的語言,當他遇到數字超過單個整數范圍時,它會把這個數分多個整數存儲。不過這一切都是Ruby自動幫你完成的,所以在你看來,你認為Ruby的整數大小是無限制的。
這是一種技巧,類似于數據庫的分表存儲。
9.3 浮點小數的誤差
其實我從很早以前就注意到,javascript中:0.1 + 0.2 = 0.30000000000000004 ,當時只是單純的認為js對小數的計算有誤差,以后得注意。但是看完書中本章節,發現不對。不光js,所以語言都會有誤差。以C#為例:

大家可以從上圖中很清楚的看到答案。程序第一行,雖然C#輸出的是 0.1 + 0.2 = 0.3 ,但是從下面的程序可以看出,這里的0.3只不過是個近似值。
針對浮點小數的這些計算的誤差,各個程序也都給出了他們認為的可控制的范圍。例如,C#的single類型(即float類型)中,允許誤差的可控范圍如下圖:

意思就是說,只要在這個范圍之內,就不認為有誤差。但是很遺憾,我還沒有用到過這個屬性。。。先了解一下吧。
9.4 計算機如何處理小數
上文說了半天的誤差,下面解釋計算機中為何對小數處理會產生誤差。原因還是一句話:計算機只能處理二進制。
所有的整數,都可以用二進制無誤差的表示出來,例如:65 --> 1000001,10 --> 1010 ,但是小數呢? 有的小數無法用二進制表示。
例如,十進制的0.5表示為二進制是 0.1, 但是十進制的0.2表示為二進制會出現一個無限循環的小數:0.001100110011....
這是計算機無法完全處理小數的根本!
對于計算機處理浮點數的現狀,暫時是無法改變的。它會帶來一些誤差,某些時候可能會因為一些不當的操作或者數據量的增加,而導致誤差過大,但是這也只能通過我們的算法和設計來減輕。
最后,小數在內存中肯定不是以“0.25”這樣帶小數點的形式表示的,因為它必須轉換成為二進制。書中提到了表示浮點數的IEEE745標準,也簡單介紹了如何將一個浮點小數表示為二進制串,但這不是我學習的重點。因為對于這一點,先了解就好,有必要時再去深入研究。
-----------------------------------------------------------------------------------------
順便,推薦一下我錄制的《asp.net petshop4.0源碼解讀》教程,免費學習!
-----------------------------------------------------------------------------------------
總結一下:
前文提到的文字編碼和數字,讓我想起了上一篇講過的一個詞——數據抽象化。
計算機本來只能識別二進制碼,通過這些年來的演變,使得它可以很友好的處理我們的語言和數學知識,這怎能不叫數據抽象呢。
再說個詳細的例子,我們現在能通過打印機幾秒鐘打印一頁文字,并輕松閱讀,但是一開始要閱讀計算機的語言,是打印紙帶,再翻譯紙帶。大家可以試著通過ASCII碼翻譯一下這幾個字母:


浙公網安備 33010602011771號