這是一個歷史遺留問題,屬於語法糖,叫做百分計算器。
按人類語義的理解,你去買東西,100元錢減去10%,那就是90元。早期的計算器就可以直接這樣寫100-10%。再比如,一隻股票股價10元,增長了50%,可以直接寫10+50%。這麼設計更深層次的原因可能與早期計算器的按鍵數量有限,以及單步運算的性質有關。具體有答主已經作了回答。
手機計算器保留了這種特性。
10%+10%就是0.11。
至於部分國內計算器結果是0.2,是因為國內手機廠商自己做了修改,符合華人打幾折的說法。上述的100-10% 其實是外華人的邏輯,在國外商品打9折叫10% off。
魅族的工程師已經在微博說明他們在國內使用了0.2的方案,在國外使用0.11的方案。
9.7更新:經調查各廠商的百分計算邏輯存在標準不統一的問題,複雜算式中對百分號的處理存在較大差異,具體差異已經合併寫入識別條件中。
下面有早期計算器百分鍵功能的具體說明。
雖然早期百分運算的用法很簡單,但是如今的手機計算器可以輸入連續的表示式,最後輸出結果(部分手機計算器還有即時回顯功能)。表示式計算滿足優先順序。但是計算器中的百分號非常特殊,它的功能實際與前後的環境與演算法的選擇有關。
比如:
5+5*10+10%+5=?
5+(10%)=?
5+10%*10=?
(如果你堅信你自己的想法,你可以用你的理論去算這些式子,然後用手機計算器驗證。)
要知道這些結果,我們需要了解百分運算的識別條件。
百分計算識別條件:
exp1 [+-] exp2 % [+-*/] exp3
要知道計算器如此工作的原因,我們可以直接從原始碼入手。
原始碼分析:
我找了一份Github上計算器的原始碼。
和大多數計算器的處理方法一致,先將原表示式轉化為字尾表示式,利用數字棧和運算子棧,配合指標,從左到右掃描一次就可以得出答案。
我已去除和百分運算無關的部分。
下面對該程式碼運算過程舉個例子:
可以明顯看出,加減法中多了一步判斷:
本質就是檢視字尾表示式+-之前的符號是否為%來執行該+-的操作。
如果不需要該特性,只需將這一句改為:
另外有網友提出括號的問題,部分計算器的字尾表示式生成時,遇到左括號“(”會將其作為一個標記插入佇列。於是,a+(b%)字尾表示式會變成 a b % mark +,加號之前的符號不再是%,不再執行特殊百分比加法。也有計算器加了括號也沒有用,這也很好推斷,該計算器在生成字尾表示式時沒有對括號作插入標記。
計算器的處理過程就是這麼簡單粗暴,也不涉及什麼高深的演算法。對於百分運算的特殊處理也只需多一個指標就能做到。所以你能想到了,要適應國內的習慣,只需要加一個地區判斷替換語句就可以了。
個人建議在使用手機計算器時,在複雜連續表示式中避免使用+10%這種寫法,因為不同的廠商演算法不同,計算邏輯也不同。儘量轉化為小數或者在百分數前加基數,比如+1x10%。
這是一個歷史遺留問題,屬於語法糖,叫做百分計算器。
按人類語義的理解,你去買東西,100元錢減去10%,那就是90元。早期的計算器就可以直接這樣寫100-10%。再比如,一隻股票股價10元,增長了50%,可以直接寫10+50%。這麼設計更深層次的原因可能與早期計算器的按鍵數量有限,以及單步運算的性質有關。具體有答主已經作了回答。
手機計算器保留了這種特性。
10%+10%就是0.11。
至於部分國內計算器結果是0.2,是因為國內手機廠商自己做了修改,符合華人打幾折的說法。上述的100-10% 其實是外華人的邏輯,在國外商品打9折叫10% off。
魅族的工程師已經在微博說明他們在國內使用了0.2的方案,在國外使用0.11的方案。
9.7更新:經調查各廠商的百分計算邏輯存在標準不統一的問題,複雜算式中對百分號的處理存在較大差異,具體差異已經合併寫入識別條件中。
下面有早期計算器百分鍵功能的具體說明。
How does the calculator percent key work? | The Old New Thing雖然早期百分運算的用法很簡單,但是如今的手機計算器可以輸入連續的表示式,最後輸出結果(部分手機計算器還有即時回顯功能)。表示式計算滿足優先順序。但是計算器中的百分號非常特殊,它的功能實際與前後的環境與演算法的選擇有關。
比如:
5+5*10+10%+5=?
5+(10%)=?
5+10%*10=?
(如果你堅信你自己的想法,你可以用你的理論去算這些式子,然後用手機計算器驗證。)
要知道這些結果,我們需要了解百分運算的識別條件。
百分計算識別條件:
exp1 [+-] exp2 % [+-*/] exp3
exp1可以是表示式也可以是單獨的數字,比如5,5+5,5+5x5,(5+5)。exp1 的值會被優先計算,比如 5+5-10%=(5+5)x(1-10%)=9exp2可以是單獨的數字或者帶括號的表示式,比如5,(5+5)。如exp2與exp3之間為 [ * / ],不同廠商有不同的處理方式。第一種會將exp2 % [* /] exp3 作為整體計算成數值,比如5+10%*10=6。第二種會將exp2 % [* /] exp3 作為增長率,比如5+10%*10=5+100%=10。有關在exp2%前後加括號的問題,即 exp1[+-](exp2%)這種情況,不同計算器會有不同的處理方式,括號不一定會影響結果,比如10+(10%)可能等於11,也可能等於10.1。這涉及程式碼處理,已在最後更新。實際含義:在滿足識別條件的情況下,對之前的累計結果增長或減少一個百分比。要知道計算器如此工作的原因,我們可以直接從原始碼入手。
原始碼分析:
我找了一份Github上計算器的原始碼。
和大多數計算器的處理方法一致,先將原表示式轉化為字尾表示式,利用數字棧和運算子棧,配合指標,從左到右掃描一次就可以得出答案。
hoijui/arity我已去除和百分運算無關的部分。
下面對該程式碼運算過程舉個例子:
可以明顯看出,加減法中多了一步判斷:
本質就是檢視字尾表示式+-之前的符號是否為%來執行該+-的操作。
如果不需要該特性,只需將這一句改為:
另外有網友提出括號的問題,部分計算器的字尾表示式生成時,遇到左括號“(”會將其作為一個標記插入佇列。於是,a+(b%)字尾表示式會變成 a b % mark +,加號之前的符號不再是%,不再執行特殊百分比加法。也有計算器加了括號也沒有用,這也很好推斷,該計算器在生成字尾表示式時沒有對括號作插入標記。
計算器的處理過程就是這麼簡單粗暴,也不涉及什麼高深的演算法。對於百分運算的特殊處理也只需多一個指標就能做到。所以你能想到了,要適應國內的習慣,只需要加一個地區判斷替換語句就可以了。
個人建議在使用手機計算器時,在複雜連續表示式中避免使用+10%這種寫法,因為不同的廠商演算法不同,計算邏輯也不同。儘量轉化為小數或者在百分數前加基數,比如+1x10%。