非常規(guī)入門之一:通用編程語言技術(shù)之?dāng)?shù)理邏輯基礎(chǔ)(二)

在前文的引入數(shù)據(jù)和數(shù)據(jù)類型的基礎(chǔ)上,本文將逐步說明編程語言的數(shù)理邏輯。
在傳統(tǒng)的計(jì)算機(jī)體系結(jié)構(gòu)中,數(shù)理邏輯建立在二值邏輯的基礎(chǔ)上。但在“通用編程語言技術(shù)”系列文章中,我并不打算講解傳統(tǒng)的二值邏輯體系下的數(shù)理邏輯。相反,我將通用編程語言技術(shù)建立在三值邏輯體系上。因?yàn)槿颠壿媽Χ颠壿嬤M(jìn)行了部分拓展。
本文的重點(diǎn)在于講解“通用編程語言技術(shù)”中由數(shù)學(xué)原理向上層過度,這一部分也是在所有編程語言學(xué)習(xí)過程中令所有學(xué)生感到最無奈的一部分,因?yàn)樵诖髮W(xué),根本不會講授數(shù)學(xué)與編程的關(guān)系,在軟件工程專業(yè)更不會講授哲學(xué)與數(shù)學(xué)的關(guān)系。
這一點(diǎn)我深有感受。記得大二在一次上機(jī)實(shí)踐課時,有一道經(jīng)典問題。按照我的做法,先列了一個二元一次方程組,然后編寫代碼,而老師在我身后提醒我這不是數(shù)學(xué)題。
故而在本文開始之前,有一個重要的說明:即“所有的計(jì)算機(jī)問題都是數(shù)學(xué)問題。”

一、三值布爾邏輯
布爾邏輯是計(jì)算機(jī)體系結(jié)構(gòu)的重要基礎(chǔ)。三值布爾邏輯是對二值邏輯的拓展。
在二值邏輯中,有真、假邏輯。在三值邏輯中允許存在一個非真非假邏輯,英文中可以使用“unknown”來表示,我們姑且稱為“空邏輯”(畢竟叫“不明”邏輯既冗長又難聽)。
真、假邏輯之間的邏輯運(yùn)算仍應(yīng)當(dāng)符合二值邏輯運(yùn)算。空邏輯在運(yùn)算過程中不影響邏輯結(jié)果。而在程序運(yùn)行過程中,空邏輯應(yīng)當(dāng)對應(yīng)異常、警告或者程序錯誤。注意此處的程序錯誤指的是數(shù)據(jù)運(yùn)算中允許存在的原始性錯誤,而不是致使程序崩潰、中斷的錯誤。
在軟件中,三值邏輯的運(yùn)算形式對于程序的運(yùn)行邏輯的影響并不是很大,最多是影響程序運(yùn)行時的精準(zhǔn)程度。反觀硬件中,三值邏輯的影響則更加具體。至此,可能知識面較廣的小伙伴會聯(lián)想到量子計(jì)算機(jī)。
然而,本系列文章中認(rèn)為,量子計(jì)算機(jī)可能仍然屬于二進(jìn)制計(jì)算機(jī)的范疇,即使運(yùn)算形式采用三進(jìn)制也仍未能突破其固有的局限性;更準(zhǔn)確的說法是量子計(jì)算機(jī)是由二進(jìn)制轉(zhuǎn)向三進(jìn)制的過度形態(tài)。(這里可能是個深淵,畢竟量子計(jì)算機(jī)現(xiàn)有的發(fā)展不容詆毀。)
作者個人認(rèn)為:在所有的計(jì)算模型中,所有數(shù)據(jù)單元的運(yùn)算必須是可監(jiān)測的;運(yùn)算方式或運(yùn)算形式的變化不能影響隨機(jī)監(jiān)測的結(jié)果,且隨機(jī)監(jiān)測的結(jié)果應(yīng)當(dāng)在監(jiān)測預(yù)算之內(nèi)。
二、表達(dá)式
在計(jì)算機(jī)程序中,表達(dá)式是有限數(shù)量運(yùn)算單位進(jìn)行有效的算術(shù)邏輯或比較邏輯的語句。表達(dá)式不能、也不應(yīng)該造成上下文環(huán)境的變化。
這里點(diǎn)名JavaScript,因?yàn)樽髡咴凇拔⑿判〕绦颉焙汀癡ue課程”中遇到很多同學(xué)在回調(diào)函數(shù)中使用this時程序報錯,而我給他們的建議時,遇到內(nèi)部需要使用this的,盡量使用箭頭函數(shù)而非匿名函數(shù)。箭頭函數(shù)屬于表達(dá)式,而匿名函數(shù)屬于函數(shù)定義。
計(jì)算機(jī)程序中的表達(dá)式一般都會產(chǎn)生一個可接收的返回值。無論是否接收這個返回值,它都會存在,只是用戶(程序員)無法直觀判斷這個返回值存儲的位置。
另外,表達(dá)式也是數(shù)據(jù)處理過程中最基本的語句。表達(dá)式在原則上可以書寫在程序的任何位置。但是為了方便簡明只管的體現(xiàn)程序流程,不同編程語言會有不同的約束。
1、算數(shù)表達(dá)式
算術(shù)表達(dá)式的書寫應(yīng)至少滿足基本的數(shù)學(xué)運(yùn)算規(guī)律,即算數(shù)運(yùn)算符應(yīng)當(dāng)匹配數(shù)學(xué)中的運(yùn)算符優(yōu)先級。同時算術(shù)表達(dá)式的計(jì)算精度應(yīng)當(dāng)在可接受的范圍內(nèi),不同的可接受范圍適用于不同的程序設(shè)計(jì)場景。特別注意,算數(shù)表達(dá)式的算術(shù)邏輯必須是無條件嚴(yán)格的。
2、邏輯表達(dá)式
計(jì)算機(jī)程序中邏輯表達(dá)式應(yīng)至少包含數(shù)學(xué)中二值邏輯。故而在C語言中,除邏輯與、邏輯或、邏輯非外,增加了符合機(jī)器特性的按位與、按位或、按位非、按位異或。
表達(dá)式是對底層邏輯(數(shù)學(xué)原理)進(jìn)行的最基本的封裝。
三、函數(shù)與接口
函數(shù)同樣可以在數(shù)學(xué)中找到原型。只是數(shù)學(xué)中的函數(shù)必然有一個返回值(或稱為結(jié)果),顯然這樣類比是不合適的。
我更愿意這樣理解:函數(shù)的思想是數(shù)學(xué)中代數(shù)表達(dá)式,而其來源無關(guān)緊要。
例如:
數(shù)學(xué)中比較常見的公式
這個公式可以理解成是函數(shù)設(shè)計(jì)的過程。以C語言為例(因?yàn)樯婕熬鹊膯栴})
代碼1:
代碼2:
各位小伙伴認(rèn)為上面那個版本的代碼更好呢?
倘若為了可讀性,應(yīng)當(dāng)首推第一個版本。但是如果涉及運(yùn)算精度和運(yùn)行效率,則首推第二個。
下面進(jìn)行分析:(首先要知道加減法的效率遠(yuǎn)高于乘除法和函數(shù)調(diào)用)。
函數(shù)的調(diào)用過程:
1、獲取上下文,即函數(shù)名
2、跳轉(zhuǎn)至函數(shù)所在地址
3、保護(hù)上下文環(huán)境,即將之前的調(diào)用位置保存在棧中
4、為局部數(shù)據(jù)開辟空間
5、執(zhí)行函數(shù)體
6、將返回值保存在RAX寄存器中(可能有、可能沒有)
7、釋放局部數(shù)據(jù)的空間(開辟多少就釋放多少)
8、預(yù)備恢復(fù)上下文環(huán)境,將保存在棧中的前一個調(diào)用位置取出。
9、恢復(fù)上下文環(huán)境,即跳轉(zhuǎn)至前一個調(diào)用位置
注意:在大學(xué)實(shí)踐課中,所言針對數(shù)據(jù)的“壓?!被颉皬棗!钡男袨榭赡懿⒉淮嬖?,根據(jù)gcc編譯器編譯所得的匯編代碼,只針對函數(shù)調(diào)用初保存環(huán)境變量時存在壓棧行為、針對預(yù)備恢復(fù)上下文環(huán)境時存在彈棧行為。故而在上述過程中,沒有使用“壓棧”、“彈棧”等詞匯。(可能在匯編語言中,push或pop指令的效率要低于mov指令。當(dāng)然,這就屬于編程語言的優(yōu)化細(xì)節(jié)了。函數(shù)的調(diào)用行為本來就是人為規(guī)定的。可能習(xí)慣上仍說“壓?!薄皬棗!敝惖?,我更喜歡“入?!薄俺鰲!钡慕蟹?。)
總之,無論上述一段文字的爭論如何,函數(shù)調(diào)用、傳遞參數(shù)及其局部數(shù)據(jù)都是在棧上進(jìn)行處理的。
下面給出函數(shù)的定義:函數(shù)是對程序中一段有效表達(dá)式的封裝,函數(shù)即是接口,函數(shù)的參數(shù)就是接口的輸入,函數(shù)的返回值就是接口的輸出。
注意:這里的接口不是面向?qū)ο笾薪涌?,更不是Java等某一具體編程語言中的接口。

在本文中,可爭議的地方較多,而理解時更需要各位小伙伴結(jié)合數(shù)學(xué)經(jīng)驗(yàn)。加之個人思維特點(diǎn),可能每個人的理解角度都不一樣,所以在探討相關(guān)問題時,希望能夠和大家進(jìn)行有效的交流,盡可能的求同存異。同時也希望我國量子計(jì)算工程能夠再獲突破。
至此,在通用編程語言技術(shù)中,機(jī)器特性以及相關(guān)底層細(xì)節(jié)已經(jīng)能夠完全被隱藏。核心基礎(chǔ)章節(jié)至此也就結(jié)束了。