為什麼好多 Android 手機的計算器都有這樣的問題呢?
計算2÷3x3
說明:分步計算,先輸入2÷3=得出結果後再用結果x3
魅族Flyme 4的結果=1.9999999998
聯想的結果=2.0000001我覺得很簡單的Bug(在技術上來說未必稱得上是Bug),怎麼很多手機都有類似的問題呢? 手機廠家的工程師們是怎麼看待這樣的問題? 或者說這個問題是Bug嗎?
這個問題的討論,我想就到這裡吧,由於本人的文字表達能力的欠缺,可能引起了別人的反感及誤會,其實我的本意就是想知道在技術和用戶體驗上哪個重要,到底該做怎樣的取捨。
一個小小的計算器看起來很簡單,可是為什麼像windows,蘋果這些公司的處理和其他的就是不同呢?
這真不是技術的問題,你就說一個普通同人你給他說一個計算器2÷3x3最後的結果它不等於2,你再問他是什麼感受?肯定不是正面的評價吧? 不要給他說技術上什麼的所以什麼的,那些東西用戶看不到,他們關心那些幹什麼,他用你的計算器,你能給他們一個信服的結果比什麼都重要,是吧? 其實像這類的問題還有很多,都是一些細節上的,但是絕對能多讓人對某個應用某個系統改變印象的地方。 在接觸了很多手機後感覺很不明白為什麼這樣無關技術的細節像在國內很多比較有實力公司都不是那麼重視呢,他們的考慮的重點是什麼呢?
這個問題其實挺好解決的。
首先,進行分步驟運算的時候,解決這個問題是不可能的。因為已經損失的精度是無法補全的。
舉個栗子:
首先寫出一段漢字:比如
日本歌鴝是一種體型小巧的歌鴝,體長15厘米。上體褐色,臉及胸橘黃,兩脅近灰。日本歌鴝(學名:Luscinia akahige)為鶲科歌鴝屬的鳥類。
然後轉換成拼音:
ribengequshiyiyzhongtixingxiaoqiaodegequ, tichang15limi。shangtihese,lianjixiongjuhuang,liangxiejinhui。ribengequ(xueming:Luscinia akahige)weiwengkegequshuniaolei。
然後完全不經過處理的讓計算機自己轉換成中文,我採用的方案是直接使用搜狗如輸入啊的第一個選項。
日本歌曲是一種提醒小瞧的歌曲,提倡15厘米。上體褐色,練級胸橘黃,兩類錦輝。日本歌曲(學名:Luscinia akahige)為翁可歌曲熟的鳥類。
看出來了吧,精度一旦損失了,轉換回來幾乎不可能。不過這個損失的精度比計算器損失的幾個浮點位的精度可是高多了。
那麼來分析一下為什麼有一部分計算器能夠正確的計算出來2 / 3 * 3
其實解決方案很簡單,buffer算式,或者計算器盡頭補位或者舍位,然後進行四捨五入。
那麼首先使用windows 8.1 自帶的計算器來進行一個簡單的測試。
測試內容是0.6666666~667 * 3在有幾個6的時候會變成2
第一次測試 0.666666667 答案 2.000000001
第二次測試 0.6666666666667 答案 2.0000000000001
第三次測試 0.66666666666666667 答案 2.00000000000000001
ect ,最終測出的結果是0.66666666666666666666666666666667 的時候答案為2,因為計算器的精度到頭了,實際上,這個運算形成了精度損失。
那麼可以認為微軟的計算器是進行了四捨五入的。
當然有的計算器沒經過這個處理,出現2.00000000000000000001的結果,完全正常。
那麼如何杜絕呢?
可以使用buffer 算式來避免精度損失。
比如
2 * 3 / 3 和 2 / 3 * 3 完全是一個概念
那麼使用演算法1 就能正確的保證精度,演算法2 就不能。
計算機和人是不一樣的,計算機只會順序的執行人類的指令。
那麼讓乘法的優先順序高於除法就行了。但是這個需要把連續運算的結果和算式都進行buffer。
比如 123/6 *2 *5 /45
經過調整得出
123*2*5/6/45 = 4.5555555555555555555555555555556 (41/9)
如果這個直接乘9就有了精度損失
結果應該為 41但是會出現41.0000~001(儘管計算器會幫你四捨五入)
那麼調整乘9的策略為
123*2*5*9/6/45,結果就沒有精度損失了。
乘法優先順序比除法高一點,這個不能靠不靠譜的編譯器幫你調整。
想辦法自己弄出來唄。
不過。。。費勁不???能理解就好,夠用就行,還是四捨五入吧。
P.S. 實名反對所有賽個圖,我計算器算出來是2的答案。提主不是問這個,主意審題。提主提到魅族,可能提主就是單純的魅族用戶而已。因為他們沒用 BigDecimal。
有人說這個這問題沒有意義,我不這麼認為。
精度問題其實就是態度問題。
而且解決這個問題不要太簡單——隨手就改了。
有段時間要用到進位轉換,Windows自帶的長度不夠,搜了全網沒一個能用的,沒辦法花了半個小時寫了個62進位([0-9a-zA-Z])內任意進位任意長度的進位轉換。
很簡單的事情,他們卻選擇了敷衍和忽視。常識問題,計算器是不能用系統的floatdouble來做浮點運算的
計算器內部的小數應該按定點數儲存na?ve!
你用過1%的計算器沒?
題主自己都說了這是簡單計算器。
不支持分數的呀。當然會有精度問題。
區別就在於採取四捨五入,無條件進位,還是無條件捨去。
同理,損失了精度,就回不來了。
2 / 3 ≈ 0.6666666666
0.6666666666 * 3 = 1.9999999998
我覺得沒啥問題呀。
如果分步算,結果還是2的話,才說明計算器有問題。
---------------------------------------------------------------------------------------------------------------------------------------
我理解的所謂分步,就是默認前一步的結果作為本次運算的運算數,
既然第一步的結果因為精度原因進行了處理,那將處理之後的結果作為第二步運算的乘數肯定是可以的,事實上所有計算器都是這樣做的。
win7計算器基本型採用四捨五入,計算2/3=0.6666666666666667
而魅族是直接捨棄多餘位,計算2/3=0.6666666666
只是在第二步的時候,win7再進行了一次處理,計算0.6666666666666667*3=2
而魅族因為沒有溢出,所以直接得0.6666666666*3=1.9999999998
不過是處理方法上的差別而已,要是連這點兒精度處理都接受不了,按照你們的邏輯非要說這是錯。那也不過是魅族錯了一次,Windows錯了兩次罷了。
有能力解釋這個問題的人,都覺得這不是問題
蘋果用戶請跟我操作:
把手機橫著拿,變成科學計算器,然後輸入:
1 除以 3 乘以 10 x的y次方 20 - 0.333333333333333333(按到按著沒反應) * 10 x的y次方 20 =
你會發現結果是
嗯,蘋果萬歲,我還以為結果會是一堆的3呢...感謝蘋果糾正我多年的錯誤認知
以上只是個玩笑~
只是我用蘋果的時,許多很重要的地方,感覺自己總是「用法不對」,結果發現一堆題主這種見微知著的人卻總是看不到那些重要的地方,而是抓著這麼微小的東西大發議論
一加,cyanogen OS,算出來也是2。
嚴重支持張雲聰回答隱含的一個邏輯:這種「簡單」情況下通過各種手段去掩蓋,也還會有更複雜的情況下浮點計算精度的問題會浮現出來。只要用戶不懂浮點計算精度的限制在哪裡,用戶就永遠有把工具用錯的可能。
我覺得這又是一個Leaky abstraction的問題。通過技術手段去解決是不可能解決完美的,用戶必須搞清楚背後的計算方式是什麼。而如果你用了技術手段去掩蓋這個問題,用戶需要學習的東西反而可能更多。
說完了,現在回答題主的問題這真不是技術的問題,……在接觸了很多手機後感覺很不明白為什麼這樣無關技術的細節像在國內很多比較有實力公司都不是那麼重視呢
我覺得題主如果你不懂技術,是無法判斷一個問題是不是技術問題的……如果具體到「計算2/3*3的結果是不是2」這個問題上,當然可以解決。但是如果你的問題是「計算任意表達式以後得到的結果的精度任意高」,這顯然是根本無法解決的問題,如果能解決的話,呃,就可以把你的16G手機當1T手機用了。(證明留給讀者作為作業,hint:參考張雲聰給的那個例子)
所以現在回頭看題主的問題
我覺得很簡單的Bug(在技術上來說未必稱得上是Bug),怎麼很多手機都有類似的問題呢? 手機廠家的工程師們是怎麼看待這樣的問題? 或者說這個問題是Bug嗎?
狹義的問題是bug,需要修復。廣義的這個問題(我乘除乘除乘除乘方根號乘除乘除乘除乘除乘除乘除乘除乘方根號乘除乘除乘除乘除乘除乘方根號乘除乘除最後結果不能偏差)是bug,但是修復是不可能的,在bug管理系統里大概會被acknowledge然後infeasible, won"t fix。
他們的考慮的重點是什麼呢?
好問題,我覺得他們沒什麼考慮重點,就是沒考慮到唄。不會有人考慮到這種問題卻故意不處理的……人家的設計師的精力也是有限的,不可能去考慮到一個app的所有方面;測試人員花在測試上的也是有限的,就是沒測試到這個問題;程序員倒是很容易注意到這個問題,但是他很可能立刻想到這個問題是不可解決的,就根本不認為這是一個問題了……
微軟當年寫計算器的程序員據說水平了得,不過我知道得不多,就不八卦了。撇開程序員水平不談,這種程序,經過這麼多年,肯定會有人像廠家反饋。只要反饋了,廠家肯定會去解決的。只是事先未必想得到。要拿蘋果和微軟來比,也要拿他們成立之後寫的前幾個版本的計算器來比,對吧。
試了下魅族,結果等於2,後來再系統更新說明裡發現更改了計算機四則運算演算法
這個才能回答原問題嘛:這個問題設計的時候未必能想得到,測試的時候未必能測得出來,但是用戶抱怨了歸根到底是會解決的。
求黑的有水平點~補充:上午看到問題直接就回答了…導致木有看清楚問題,造成了誤解,還請提主見諒。對不起~原諒我急躁的心情。
其實很多人都說錯了。
2/3*3 確實是2 的,但如果分開計算,2/3,然後再乘 3 ,就算在標準的算術課上,它也不應該等於 2 的。
因為算術的角度必然要四捨五入,得到了 0.6666667 之後再乘 3 ,最後肯定會比 2 大。
所以,如果分開計算的話,0.6666667 * 3 = 2.0000001 是數學上正確的答案。
這個問題,題主不妨回去問自己的數學老師。表示Google公司實現了你說的2/3*3=2了,原生安卓5.1系統計算器是這樣,先是計算出小數,當你*3後立馬變為2,我覺得Google做的很好。
題主要知道二進位的運算方法
2/3=0.666666666666666......
那麼0.666666666666666......在二進位中如何表達?
首先將0.666666666666666......拆分為0.5+0.125+0.03125+......
準確的來說是
但是0.666666666666666......這個數拆不完阿,所以只能拆到幾十位的時候不拆了,取一個近似值,比如說0.666666666666666666666666666666666666666666666666234125,那麼這個數乘3的時候就不等於2了。
當然,不同的編程語言和不同的運行環境下運算結果都不一定,所以近似的位數也不一定,計算機也不會這麼腦殘顯示出1.9999999999999999999999999999998725這樣的數字,所以說一般都會約等於2.
詳情請百度浮點數。我覺得可能是題主買的是假的魅族建議去退貨。
我初三的時候花了一下午寫了個簡單計算器,WP的,雖然bug一大堆但是我剛剛試了一下沒有這個問題。數字是存成float的。。
實際上只是精度問題而已
表示安卓原生的計算器沒有此方面問題
Google細節做得很好
有兩點。你這例子可能不太好,這裡用0.5/3*3。
1、windows計算器下,0.166...67*3結果0.5000...01,相比0.666...67*3結果為2。這裡不一樣的原因顯示精度的處理,後者捨去了一位。
所以第一點,精度處理的方法。(windows計算器根據有效數字位數,測試的三星手機是根據小數點後位數)
2、windows計算器下,0.166...67*3結果0.5000...01,相比0.5/3*3分步計算結果為0.5。這裡不一樣的原因,猜想windows計算器把用結果繼續計算看作是連續計算,在計算過程中保留了精度。
所以第二點,是否在計算過程中保留精度。(沒保留的原因我猜是內存里沒保留上次計算結果所以直接取結果框的文本?怎麼想我都不信是故意去丟失精度)(測試的三星手機沒這個問題,另外一個雜牌安卓有)
寫完才發現偏題了,忽略1吧,2是回答。
另外反對所有說浮點數精度的。加減法怎麼不出問題?
因為每一個手機的計算器都有精確到幾位數的設定啊,所以後面的數值會被約等於,所以當然就有誤差了。這理解可以吧?第一次作答。。
基本數據類型 問題出在變數類型上 ( ????? )
推薦閱讀:
※像三星 (Samsung) 這樣在硬體性能測試 Benchmark 跑分中作弊的現象普遍嗎?
※手機安全軟體作用到底有多大?
※現在的安卓還會越用越卡嗎?能達到 iOS 的流暢度嗎?
※日劇《逃げ恥》里星野源用的手機是什麼型號?