2012年9月28日 13時(shí)32分 新增
最近看本文評(píng)論,爭(zhēng)議很多,我先說(shuō)說(shuō)這篇文章的前世今生吧。
我原文標(biāo)題是『代碼之謎 - 開(kāi)篇/前言/序』,副標(biāo)題是『其實(shí),你不懂代碼』,本來(lái)打算用“其實(shí),代碼中的運(yùn)算符不等價(jià)于數(shù)學(xué)符號(hào)”。原文我寫于2010年底,當(dāng)時(shí)寫在 evernote 中,用了”群“、”域“、”集合“、”關(guān)系“的概念解釋了計(jì)算機(jī)中用二進(jìn)制表示的離散的數(shù)和現(xiàn)實(shí)中連續(xù)的數(shù)之間的關(guān)系和區(qū)別。
前幾天QQ群里有人問(wèn)道,遂打算寫一個(gè)系列,用比較「貧」的語(yǔ)言把他們講述出來(lái)。
原文首發(fā)在我的博客:?http://justjavac.com/codepuzzle/2012/09/25/codepuzzle-introduction.html, 因?yàn)槲乙膊荒鼙WC我的博客空間總是穩(wěn)定的,所以,如果博客訪問(wèn)不了, 可以到?iteye?或?CSDN?查看這篇文章,還可以順便看看熱心網(wǎng)友的評(píng)論。
正文分割線
答應(yīng)了群里的兄弟們要更新博客,結(jié)果回家又是洗衣服做飯的,轉(zhuǎn)眼已經(jīng)10點(diǎn)多了。
趁洗衣機(jī)正在轉(zhuǎn)的功夫,打開(kāi) Evernote 找到了以前的幾段 javascript 代碼,本著人性本賤(咳,咳,該死的輸入法,更正「人性本薦」)的精神, 給大家共享一下,不定期更新,算是我「代碼之謎」系列的開(kāi)篇吧。
我喜歡讀一些讓人震驚的書,比如『哥德?tīng)?、艾舍爾、巴赫書:集異璧之大?/a>』,比如『從一到無(wú)窮大』,讀完后張大嘴巴,「哇噻,太不可思議了,太令我震驚了」。 本系列博客的目的之一就是讓每個(gè)閱讀過(guò)的人在思維方式上有所改變,變得更理性,更加會(huì)思考,會(huì)學(xué)習(xí)。
本系列說(shuō)來(lái)話長(zhǎng),從10年開(kāi)始構(gòu)思,當(dāng)時(shí)寫在 evernote 里面,名字叫『理性,像數(shù)學(xué)家一樣思考』,廢話少說(shuō),言歸正傳,貼代碼吧
第一段代碼:
function foo1(a){
return a + '01';
}
foo1(01);
第二段代碼:
function foo2(a){
return a + '010';
}
foo2(010);
第三段代碼: (注: 這不是 javascript 的問(wèn)題,而且所有語(yǔ)言的問(wèn)題,歸根結(jié)底是 IEEE 標(biāo)準(zhǔn)中二進(jìn)制浮點(diǎn)運(yùn)算的問(wèn)題,關(guān)于浮點(diǎn)數(shù)的詳細(xì)問(wèn)題請(qǐng)閱讀?代碼之謎 - 浮點(diǎn)數(shù),「為什么沒(méi)有鏈接呢,呵呵,因?yàn)槲疫€沒(méi)有寫,正在整理中」。)
console.log(0.2 + 0.4);
第四段代碼就相對(duì)來(lái)說(shuō)簡(jiǎn)單多了: 參考我一些發(fā)布的這篇 為什么 ++[[]][+[]]+[+[]] = 10? 。
[4,[3,2]][1][0]; // 3
2012年9月25日 22時(shí)25分 更新
還是忍不住,睡前想嘮叨幾句。
也許很多人第一次接觸編程時(shí),對(duì)?i = i + 1
?都感到百撕不得騎姐(咳,我就說(shuō)了嘛,必須得換一個(gè)輸入法了,更正「百思不得其解」)。
“i加上1怎么可能和i相等呢?”
后來(lái)慢慢知道了,不,確切的說(shuō),是慢慢地接受了,接受了=是賦值(前提是你學(xué)的不是pascal,我的入門語(yǔ)言就是它),因?yàn)?strong>你可能根本沒(méi)有思考,只是被動(dòng)接受。
再后來(lái),我們學(xué)了 if, 開(kāi)始寫分支代碼:
if (a >3) {
// do something
}
if (a < 5) {
// do something
}
但是當(dāng)我們寫出?if (3 < a < 5)
?時(shí),居然報(bào)錯(cuò)了,又是百撕不… 后來(lái)被教導(dǎo)了,這么寫是錯(cuò)的,應(yīng)該?if (a>3 && a<5)
。 于是我們又開(kāi)始接受了,認(rèn)為這么寫是理所當(dāng)然的,而且以后的代碼都是這么寫的。
直到有一天,你看了 python 的入門手冊(cè),尼瑪,居然逆天的出現(xiàn)了 'if 3 < a < 5:',當(dāng)時(shí)絕對(duì)又震驚了,“怎么可以這么寫?”。 難道你忘了,N年前你就是這么寫的,而且當(dāng)時(shí)你不也認(rèn)為?3 < a < 5
?是理所當(dāng)然的嗎(任何一個(gè)高中生都會(huì)同意這種寫法), 為什么你現(xiàn)在又開(kāi)始覺(jué)得?3 < a < 5
?是種逆天寫法呢,因?yàn)槟阍谶@幾年的編程生涯中,已經(jīng)被動(dòng)接受了太多太多的東西,而且使你根本就不曾思考過(guò), 這也是我寫「代碼之謎」系列的初衷。
當(dāng)你被告知了,在編程中=是賦值的意思(其實(shí)他們沒(méi)有告訴你,只是大部分語(yǔ)言這樣,還有很多語(yǔ)言不是這樣,比如pascal中:=是賦值,比如basic/VB中=即是賦值也是判斷), 但是=如果不是相等的話,那肯定有表示相等的,對(duì),就是==,或者===。
不管是==還是=,「相等」到底是什么意思呢?=或者==或者===,即使以后會(huì)出現(xiàn)====,到底和數(shù)學(xué)的「相等」有多少出入呢?
知道我們遇到了傳說(shuō)中的NaN(很多人認(rèn)為NaN既然表示Not A Number,那么他就是語(yǔ)言定義的一個(gè)東東,根本不存在,這是錯(cuò)誤的,NaN是在IEEE浮點(diǎn)數(shù)規(guī)范中明確定義的,包括本系列后面 后提到的+0和-0問(wèn)題),它不等于任何值,而且,它居然不等于它自己。
一個(gè)數(shù)居然不等于它自己,其實(shí)確切的說(shuō),是 NaN == NaN 居然返回 false, 甚至 NaN === NaN 也返回 false。是 NaN 的問(wèn)題,還是==或者===的問(wèn)題,抑或這根本就是相等這個(gè)概念的問(wèn)題。
在集合論中,相等的三要素,不管是==還是===,都無(wú)法滿足,所以說(shuō),===根本就不是相等(如果你讀過(guò)數(shù)學(xué)的「群倫」就更明白了)。
相等(等價(jià))的三要素
當(dāng)我們看到這幾條定理時(shí),我們從來(lái)沒(méi)有懷疑過(guò)。 脫離了數(shù)學(xué),我們進(jìn)入了編程領(lǐng)域,當(dāng)我們遇到了NaN, 我們知道了,在IEEE的數(shù)字表示規(guī)范里面,「自反省」是不被滿足的,那么傳遞性和對(duì)稱性呢? 如果你找到了反例,可以留言。
也許你說(shuō),相等/等于/全等/等價(jià)這些比較特殊,其它的應(yīng)該都會(huì)滿足吧。 我只能告訴你(說(shuō)通俗一點(diǎn)),以前的所有定理、公理都只適用于一個(gè)領(lǐng)域,當(dāng)它進(jìn)入另一個(gè)領(lǐng)域我們就不能把它當(dāng)作理所當(dāng)然的,也許它沒(méi)有問(wèn)題,比如 1+2=3,但也許這只是一個(gè)巧合, 上面我就提到了 0.2+0.4 就不等于 0.6。
計(jì)算機(jī)和現(xiàn)實(shí)最大的不同(也是問(wèn)題的根源)就是,世界是連續(xù)的,而計(jì)算機(jī)是非連續(xù)的,是離散的。 以前我們學(xué)校圖書館有很多「計(jì)算機(jī)數(shù)學(xué)」或者「離散數(shù)學(xué)」之類的書,我現(xiàn)在都不明白,里面寫的那些數(shù)學(xué),是設(shè)計(jì)計(jì)算機(jī)的工程師讀呢,還是使用計(jì)算機(jī)的程序員讀呢?里面的內(nèi)容簡(jiǎn)直就是大雜燴嘛。 什么是離散數(shù)學(xué)呢?我的理解,不連續(xù)的數(shù)學(xué)都是離散數(shù)學(xué)。比如量子論里面用到的數(shù)學(xué),就是離散數(shù)學(xué)。
其它算數(shù)定律或者定義有不滿足的嗎?
再舉一例,上小學(xué)剛學(xué)乘法運(yùn)算的時(shí)候老師就告訴我們,3x4就是4個(gè)3相加,下面這個(gè)例子再次顛覆你的想法。
console.log(0.1 * 10);
console.log(0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1);
寫完睡覺(jué),如果大家有什么更好的例子,歡迎補(bǔ)充。
更多建議: