為什麼 Windows 10 計算器應用中含開方計算結果不準確?

在 Windows 10 中,UWP 應用「計算器」標準模式下計算sqrt{4} - 2 的結果為-1.068281969439142 	imes 10^{-19}

這是否是產品質量問題?

如下圖所示:


我記得這問題在知乎上出現過。

我當時的看法是,微軟從一開始就不該實現高精度運算功能(或者即使實現了,也放到「高級選項里」,默認別開)。要教育用戶,我們的計算器就是能力有限。而不是給用戶以「我們的計算器特別牛逼」的假象,但是實際上又沒法consistent地牛逼。


其實題主的這個問題應該分開回答。

1. 這個值合不合理?

考慮實現原理和精度,這個答案是合理的。

2. 能不能做的更好?

僅僅針對題主這個個案,能。不過總會出現其他的狀況下有類似的問題,比如 1/3*3 之類的。前面也有人舉過坑爹的0.1和0.3的加減法。更加先進的符號計算某種程度上能解決這一類問題,但也只是"某種程度"。

最後作為計算器來說這不是質量問題。因為能更好的解決問題的工具一般賣的都不便宜。


這不是bug是局限,基本每個學過計算機專業的人都知道會有這樣的問題。因為不可能把所有數都用有限的內存表示(比如無理數的值無法用有限位的0和1表示),複雜運算通常有誤差。計算的精度不是不可以提高,只要每個中間運算結果用更多的內存存儲就行。但是這樣提高精度的代價,是內存、磁碟空間佔用和耗電量的上升,以及運算速度的降低。任何計算軟體都需要在這兩個方面做均衡。作為入門級軟體,不可能做得又慢又笨重(參見記事本和Word的差別)。

微軟在計算器里已經沒有在用IEEE754這個工業標準了,加減乘除和整數乘方用的是高精度計算庫(1除以3再乘以3不再是0.99999999……)。但是這個庫不支持開方。實際上計算器算開方的時候,就是用0.5的乘方。用對數來算乘方的話,ln4這一步開始就有誤差了。微軟對於計算結果是有做矯正的,顯示的時候有效位數比實際存儲的少,所以在計算4的開方的時候你會看到2,但是像題主這樣一減去2就知道了,內部存儲的結果並不是2,只是顯示的時候舍入了而已。由於運算誤差的大小隨著運算的類型和次數增加,不可能說四捨五入到最近幾個小數點甚至整數就能搞定(而且你不預知結果,沒法決定是向上還是向下取整),所以複雜運算不再在顯示時舍入是正常的。

要獲得題主想要的精確結果,需要一個能夠檢測根號下是可以正好被開方的數的庫。而對於絕大多數的用戶場景(比如買菜,比如付小費,比如算利息),這個庫並沒有用。判斷一個表達式的中間運算結果到底需要多少精度,仍舊是計算數學家們的研究課題。


看到問題又改了,雖然去掉了題主自己的傾向,但是把問題改錯了。

科學記數法 AeB 的意思不是 A e^B 而是 A	imes{10}^B

——————

看到問題改了。題主(之乎者也)如果只是想發表自己的觀點甚至只是想聽到批判 Microsoft 的聲音的話大可不必提個問題然後在題目描述裡面給出自己的答案,你可以提問 + 自問自答,或者發篇專欄。

——————

log、ln、lg。

根據語境,log 是以 2 為底或者以 e 為底或者以任何一個大於 1 的數為底。

ln 永遠是自然對數,就是 f" = 1/x, f(1) = 0 的解;lg 永遠是以 10 為底。

Log、Ln、Lg 都是復變多值函數,log、ln、lg 是一個分支,通常選一個作為主值。

關於 log,如果你在計算機語境下,通常是 2 或者 e;如果是數學語境下,則通常是 e。這是一個常見的約定。

之乎者也 評論說:

程序員的世界和我們的世界是平行世界,在程序員的世界觀裡面log就是ln,另,具體如下:Log[z] 給出 z 的自然對數(對數的底數是 e). Log[b,z] 給出底數為 b 的對數。程序員通常以他們那些知識為榮,並且不屑向小白解釋~

我不理解為什麼這個人如此揣測,我使用 log 作為自然對數的習慣來源於數學學習,而且 Log 和 log 是不一樣的。我猜這個人說的那個語法是 Mathematica 的。

如果你不喜歡這個記號也沒什麼關係,反正它們之間差得不多,而且你只要在遇到我書寫的文字中把符號對應到你喜歡的版本就可以了。

這是不是一個 bug?

不是,計算器不是一個符號計算工具,它是數值計算工具,算出來的數期待是帶有誤差的。

如果你認為程序應該特殊處理一些情況,那麼我的 argument 是:無論你怎麼處理,只要還是一個數值計算工具,總會有和數學上不一致的式子出現;如果你要處理到完美,那麼你可以尋求任何一個符號計算工具。

為什麼 sqrt(4) - 2 不是 0?

答:因為浮點數運算有誤差。

為了簡化場景,我們假設 sqrt(4)-2 算出來的近似值是 1e-30。

情況 1:計算器不知道精度。此時計算器應該輸出 1e-30。

情況 2:計算器知道精度,例如內部存儲了誤差限是 2e-30。

此時計算器最好的是輸出「1e-30(可能有正負 2e-30 的誤差)」。然而這對於普通用戶來說 overwhelming 了,直接輸出 1e-30 也是很好的選擇。

繼續上面的場景,為什麼 sqrt(4) 不輸出 2.000...01(中間有 29 個 0)?(同樣可以解釋為什麼 sqrt(9) - 1 是 2 但是 sqrt(9) - 3 是一個絕對值很小的數)

答:要解釋這個問題,我首先介紹什麼是浮點數的返程表示。所謂浮點數 x 的返程表示,是指一個串 s,它滿足 s 被解析為 x 後,和 x 的內存表示完全相同。

接下來我們以 double 為例,顯然 0.1 的返程表示是 0.1,因為該數值就是用 0.1 解析得來的。而 1.0 + 0.1 - 1.0 的返程表示是 0.10000000000000009。

我們可以看到,雖然返程表示是精確的(在忠實還原這個浮點數的意義下),但是通常是不 desirable 的。

因此 Windows 的計算器選擇不用返程表示,用普通的轉換為字元串表示。

再用 double 的情況舉例,3.0 + 0.1 - 3.0 的通常字元串表示是 0.1,返程表示是 0.10000000000000009。

而 3.0 + 0.1 - 3.0 - 0.1 的通常字元串表示是 8.32667268468867E-17,返程表示是 8.3266726846886741E-17。

同樣地,在 Windows 計算器裡面,sqrt(4) 的通常表示是 2,返程表示不是 2,而 sqrt(4) - 2 就會暴露出 sqrt(4) 和 2 的差別。

為什麼 Windows 計算器不選擇在結果非常小的時候輸出 0?

這個問題本身就不對。為什麼 0 就應該是特殊的?計算器算出的近似值是 1e-39,那麼就輸出 1e-39。如果你覺得此時應該輸出 0,請思考:為什麼此時不可以輸出 2e-39?它和 0 距離 1e-39 相等(都是 1e-39)。

所以到底怎麼辦?

答:對於多數日常使用來說,算出來的數通常不會如此接近 0,比如算一算平均 1mL 香水多少錢,或者算一算某個信用卡活動的回報率。因此這一點點的精度問題不會造成影響。計算器目前的實現已經 cover 住了很多日常場景。對於更多場景,可以自己寫程序來計算,或者使用符號計算軟體。

Windows 的計算器如何計算平方根?4 的算術平方根明明是可表示的浮點數啊?

答:設輸入是 x,若 x &< 0,輸出錯誤,若 x = 0,輸出 0,否則輸出 exp(0.5 * log(x))。而 log(4) 不是有理數,因此不可能是可表示的浮點數。

特別注意:這裡的 log 是自然對數,這個寫法是符合數學和 C 語言的庫函數的。我在這裡更偏向於數學的表示,因為如果你把 log(4) 理解為一個 C 語言庫函數調用,那麼結果總是有理數,而我這裡想要表達的是因為 log(4)(一個數學記號)是無理數,所以這一步運算已經帶來了誤差。

——————

更新之前:

低級黑的姿勢太難看。

Why does the Windows calculator generate tiny errors when calculating the square root of a perfect square?

如果你只做四則運算,則你將獲得完美精度。但是開根號不是四則運算。

——————

更新:上面那篇文章中使用無限精度的條件是錯誤的,並不是所有四則運算都會使用無限精度。

如果你認為 Microsoft 做不好 Apple 能做好的話,試試 sqrt2 - 2 / sqrt2。如果你不同意我說題主是低級黑,可以仔細品味一下下面這句上綱上線的氣味:

如果是一種錯誤的話,可以說是對產品質量不負責的表現吧!其實也是擔心這麼簡單的都能算錯,複雜的計算會不會也出錯,信任基礎破滅了!

恕我直言,恐怕題主對 Microsoft 本來也沒什麼信任基礎,而且對「簡單」的理解是樸素的。

同時,認為 sqrt(4)-2 輸出一個非常小的數是一個 錯誤 和認為下面的行為是一個錯誤一樣:

在 standard 模式下輸入 1+2*2,按 =,得到 6。

Basically, 根本沒明白計算器能幹什麼、怎麼用。


浮點精度基本上是個計算器都會出問題,而且我敢保證除了 Mathematica 之類基於符號計算的,其他的百分之百可以找到算式讓他出翔。

或許 Haskell 裡面某些使用惰性求職的動態精度算數庫可以處理好

Feedback 我已經報了,你可以去支持 feedback-hub:?contextid=130feedbackid=799631ec-f6bf-4fb1-9732-fff7fb336b66form=1src=2

————————————————————————————————————————————

另外請給這個 bug 狠狠點贊 → feedback-hub:?contextid=117feedbackid=b7624675-883a-4c93-a206-5561bbbffc11form=1src=2


其實MATLAB 在某些數值計算(題主的例子沒問題)的時候一樣會出問題:

&>&> 0.1+0.1+0.1-0.3
ans =
5.55111512312578e-17

不過對於類似這種情況 MATLAB 在文檔中給出了比較詳細的說明和解釋

Floating-Point Numbers

所以相比起來要說微軟不負責也算吧,嚴格上來說,微軟需要把這種現象在比較明顯的地方提前告知用戶(或許有但是我沒找到,有誰找到了麻煩說下),畢竟懂計算機科學不是用戶的義務。

不過像 Windows 自帶計算器這種類型的小工具好像還真沒見到有幾個能把這種問題說清楚的

另外,說句題主可能不關心的話,這種兩相近的數減法在數值計算上經常處理成:

(sqrt(4)^2-2^2)/(sqrt(4)+2) = (4-2^2)/(sqrt(4)+2)

這樣的話即使用 windows 計算器算等號右邊這個表達式應該也不會出錯吧


別拖 macOS 墊背了。當然你總能找到算不對的例子,這種我能理解,事實上 Mathematica 都會莫名其妙地在有些情況下炸掉。但常見的解決起來真沒那麼難,我很多年前買的卡西歐計算器都能算對這些東西,現在都 2016 年了……


這當然是個 bug,然而很多計算器都並沒有解決這個 bug 。

解決這種 bug 並非不可能,比如你用 Matlab 或者 Mathmatica 之類的專業性數學軟體計算你所說的式子一定能獲得數學正確的答案。某些內置十進位運算庫的語言也可以很方便的做到這一點。甚至更粗暴的縮小顯示精度也行(當然這可能會導致其它一些問題)。

Windows 計算器作為一個簡易計算器,沒能解決這個bug,顯然是認為它不需要解決(或者說不解決這個bug是更優的選擇),因為這是一個程序員眾所周知,已經成為潛規則的bug,在知乎這個碼農輩出的地方你可以找到一萬個理由來說明這個bug存在的合理性。然而,這並不是把這種bug原樣呈現給用戶的理由。

從某種程度上來說,我個人認為,Windows 計算器作為一個白送的軟體,本身不具有高品質,這是完全可以理解的。----如果微軟把系統自帶軟體做到專業級,那其它軟體開發商還怎麼活呢?


FYI:Why Windows Calculator sqrt(4)-2=-8.1648465955514287168521180122928e-39,另外這個只對win7有效應該。

實際上這個不在於精度不夠,而在於計算器的輸出沒有統一性。

不信大家試一下sqrt(4)-3 sqrt(4)-2.1 sqrt(4)-2.01 等計算結果是多少,相信不會出現問題中的那一串尾數。

win10中計算器科學型的顯示有效數字經手工測試是32位(十進位下),後面部分就會被保留,比如計算1+10^(-32),就顯示1。這本身無可厚非,如果題主對此表示質疑,我相信ls的答案都可以做出有力反擊。

然而現在的問題是唯獨sqrt(4)-2輸出會有一大串尾數,這實際是因為計算器內部代碼在判斷如何輸出這個數字時,只判斷了結果的有效數字位數,而忽略了計算過程對結果精度的影響。

在計算sqrt(4)時,實際計算結果是2-8.1648465955....e-39,假設這個結果是通過牛頓法等迭代方法求出的,那麼計算器肯定知道這個結果的精度是不到40位的,因此計算完-2這個結果後,其結果-8.1648465955....e-39,必然達不到小數點後40位的精度,因此此時有效數字應該從被減數2-8.1648465955....e-39的第一位不是0的位數,即個位開始算起,而不是從-8.1648465955....e-39第一位不是零的數開始算起。

一個佐證是,

我們計算1+10^(-40),得到1,再將這個結果減去1,得到10^(-40)。

我們計算1+10^(-60),得到1,再將這個結果減去1,得到0。

說明計算器內部存儲精度是在40到60位十進位之間的。

1+10^(-60)-1=0,這個錯誤可以說是精度問題導致的,無可厚非。但sqrt(4)-2的錯誤就是計算器沒有分清楚數字本身的有效位數和顯示的有效位數之間的區別帶來的。

這在實現上確實是一個bug。

================================================================

我覺得很多討論偏掉了。

首先一個東西是不是bug取決於其結果是不是我們預計其得出的。

計算器當然並不一定給出數學上正確的結果,不管這個計算器是實體的還是軟體,是免費的還是收費,如果認為計算器不能給出數學上的結果就是錯誤,那麼只能說是想當然。

比如說著名的卡西歐計算器fx991,他的計算也會有誤差。http://support.casio.com/storage/cn/manual/pdf/CN/004/fx-570_991ES_PLUS_CN.pdf,在這個說明書里最後就列出了各個運算的範圍和誤差。而且實際上還有不少不在說明書列表上的bug,這個很容易搜到。不過微軟的Calculator的app似乎我沒找到類似說明書的東西,Windows Calculator。

從這個角度來說,題目中計算器的計算結果是可以接受的,至少絕對達不到「其實也是擔心這麼簡單的都能算錯,複雜的計算會不會也出錯,信任基礎破滅了!」的程度。

其次,我們之所以認為這個結果不能接受,主要取決於sqrt(4)會顯示2,而-2之後顯示-8e-39(科學型),這兩個結果差距過於大。

產生這個結果的原因我在上面分析了,簡而言之是因為計算精度問題,實際上sqrt(4)存儲的是2-8e-39,而在輸出時由於位數過多,四捨五入到了2,而-2之後變成-8e-39,按照從左起第一位非零位是第一個有效數字的演算法,此時能夠輸出這個尾數,因此輸出了,從而產生了不一致性。

第三,我在之前的分析中認為這個結果可以通過對於計算結果添加有效位數這個meta-data並在計算中推導結果的有效位數來規避。

下面評論中有人提出了幾點質疑。

1:現有方案只需要將內部儲存的decimal直接轉為科學計數法形式的string輸出即可,作為簡單工具不需要複雜判斷。

這個觀點有道理,但是既然已經對於循環小數進行了判斷(應該是對於循環小數內部維護了其分數形式),那我認為這種處理要比維護分數類簡單。

2:複製過程會丟失這一meta-data。

我認為計算器不需要對於用戶複製出去再粘貼進來的數據負責,其一是計算器本身有存儲功能M。其二是對於目前已有的循環小數,複製出去再粘貼進來也會出錯。


我覺得不是bug

1.00000000000000000001程序可以認為是1,好多個0後面是誤差

0.00000000000000000001憑什麼要被認為是誤差?我要是計算結果正好是這麼多,你憑什麼要顯示為0

計算電容的時候如果得到1pf這種結果,等於1e-12f,你要是給我舍成0了我電路出錯怎麼辦?

報道出了偏差是要負責的

計算出了偏差也是要負責的


答案大部分重寫。

由於題主問題描述中曾經存在的「其實也是擔心這麼簡單的都能算錯,複雜的計算會不會也出錯,信任基礎破滅了!」。這樣一句話,讓我覺得題主預設立場,小題大做準備搞一個大新聞,以致用一些不佳的語氣反駁了這一句話。很多答主(包括我)的答案也主要是針對這一句話。現答主去掉了這句話,那麼我也重新答題。

這樣的計算結果直接呈現給客戶,沒有提供相關的文檔說明,確實反映了微軟工作的不足。在這一的場景下加一些特殊的判斷條件可以一定程度上緩解這一問題。比如一個簡單的方案對整數開方進行判定:

如果某浮點數a十分接近一個整數b,且開方的結果浮點數c也十分接近一個整數d,且驗證d*d=b,則把開方的結果c使用d替換(十分接近指差絕對值小於1x10^-17)。如此一來,sqrt(4)=2, sqrt(4)-2=0,沒有任何問題。這樣的判斷在windows計算器日常生活中應用場景下,不會造成什麼其它額外影響。這樣的判定會對一些人造成影響,但他們主要使用Matlab等專業軟體,不做過多考慮。

最後這樣的特殊判定解決不了計算器計算sqrt{2} -frac{2}{sqrt{2}} 
e 0的問題,解決這一問題不是加一點判定就可以,得引入符號計算引擎。但相信題主對於sqrt{2} -frac{2}{sqrt{2}} 
e 0這種情況已經可以接受了。


在設計容許誤差範圍內就不是bug。用戶期望值和設計目的不一致說明你用錯了產品。

汽車儀錶盤顯示100km/h的時候,用GPS實測只有90km/h,是不是bug?當然不是,因為這是為了符合國標而故意設計的。

電腦時鐘用了一年之後快了一秒是不是bug?實際上一天之後快一秒也是在容許範圍內的。想精確測量時間請購買原子鐘。


所以大部分科學計算器都會做成內部精度大於外部精度,以及說明了 Windows 自帶的計算器沒有 CAS (逃


感覺題主是來這裡罵程序員的。沒錯,sqrt(4)-2=0可以說是用戶所期待的答案,而絕大多數人都不了解浮點計算的缺陷。但是咱們換個角度:400+RMB的Texas Instrument TI-84+做類似的運算時也不能避免浮點運算的缺陷。稍微有點常識/計算器使用經驗的人都知道,如果看到類似10E-30這種數量級的結果,可以默認為0。

計算器軟體/普通計算器的定位中不可能也不應該包含Mathematica這種高端數學運算軟體的符號運算能力。這是個經濟意義上的成本/資源分配問題,和是否注重產品根本就沒有關係。

考慮到題主的態度,我只想說:缺乏常識不是罪,但是不虛心受教真的很惹人厭。


算是個小BUG吧,但在數值計算里這也是很正常的現象,因此不應該算作「對產品不負責任」。

能解決完善當然更好,但那個就屬於錦上添花的部分了。

Why does the Windows calculator generate tiny errors when calculating the square root of a perfect square?

根據鏈接中的描述來看,windows自帶的計算器的開二次根號的功能是通過先取對數再取指數計算的,即exp(? ln x),用這個算式計算√4的話誤差大概是兩倍的eps(1),對於計算器來講就是不能抹除的了。我覺得如果能通過牛頓法或者二分查找法計算一個根號的話,可能誤差會小一些。


因為首先計算機是算不出根號的真實值的,只能用迭代趨近或者用公式近似,所以這個0.00...0001是必然存在的,那麼就是看怎麼處理它了,你可以為了好看而覺得這個1可以省略了,也可以為了精度保留,到底是選擇為了保證簡單運算的正確性重要,還是保證在普適性運算下的精度重要,win選擇了後者,不評價,但是我個人覺得後者好一點,因為我用計算器的時候都是需要一個值而不是去驗證什麼我已經知道的東西,所以精度越高越好

當然。。。可以通過內置乘方的表來解決這個問題。。。然而我覺得這除了好看並無卵用

然而!

我拿我手機(Android M)和手頭的CASIO fx-991ES 都試了一遍。。。確實都是0。。。

所以既然如此,我只好認為這確實是一個bug,但是要不是有題主這麼較真的人,我還真不會覺得這是多大點事。。。一方面是我不會這麼用,另一方面是我覺得這可以容忍,不要緊。

所以,對於電子產品越來越普及,而技術越來越深奧的今天,也許我們在設計軟體的時候必須考慮到使用者沒有任何關於計算機運行的知識?軟體往傳說中的「去設備化」前進?


這也要問如何看?

首先,我懷疑樓主對這個結果-1.068281969e-19都沒有一個清晰的認識,我幫你改寫一下吧

-0.000000000000000001068281969 (不確定有沒有多一個0,敲的手疼)

作為一個正常人,先心算出一個答案,再與這個結果作比較,居然會認為是"算錯",那我也真的是無話可說了,就這樣吧,題主可以不繼續往下看了,請反對我。

這其實就是對產品質量不負責的表現吧!其實也是擔心這麼簡單的都能算錯,複雜的計算會不會也出錯,信任基礎破滅了!

其次,這個浮點數問題由來已久,恕不贅述,至於這個算不算是「bug」,我覺得是有待商榷的,畢竟這個軟體是免費給你的,也不是什麼專業運算軟體,目標就是普通的日用or家用吧,完全沒必要精確到小數點後面這麼多位,一般人完全用不到————真的需要這麼高精確位數的,請去找專業軟體,matlab什麼的,如果有這個問題才能叫做bug吧。

多說一句,現在很多號稱「專業」、各種功能天花亂墜的計算器對於浮點數的支持非常不好呢,我覺得這才應該是大新聞應該鬧的方向吧,windows自帶的calc……最主要的功能難道不是黑白帽子演示漏洞時候用嗎…………(大霧)

------補充---

(1)感謝評論區中 @龍雀的提醒,之前把calc都敲錯了……

(2)另外我在評論區中補充了下,其實我強調的並不是「這個軟體是免費的-&>這個問題可以容忍」,而是「這個軟體是非專業的-&>這個問題可以容忍」,很多時候這種問題其實很常見,例如大家用的手錶,沒有一個考慮到閏秒的問題吧?大家覺得有影響嗎?大家用的米尺,想完全做到標準定義(真空光速的1/299792458),也沒什麼可能性吧不是依然繼續用嗎——這才精確到小數點後多少位了?難道大家對這種1e-2~1e-4數量級的誤差都不敏感,對這個1e-19大談特談,信任危機什麼的……你適合去天涯,真的

(3)我會力所能及地回復大家的疑問(如果我知道的話),但是對於連「精度」這個計算機專業術語都不了解,在這裡指手畫腳講「誤差」的,恕我直言,不再回復。如果你對我「精度」這個詞兒不滿,請去修改IEEE標準,只要你把它改了,我就跟著你改。


雖然在形式上有些不同,不過這個問題和另一個關於計算器的問題還是等價的:

「在蘋果手機的計算器中計算97-48.5,則界面會卡住,有時還會得出結果0。」

通常來說小白是這麼想的:

「哇這一定是個Bug客服我要退款」

大多數人的想法是:

「非得去試一下才知道果然自己的數學全還給老師了」

而大神的想法一般是:

「媽的智障」

不過這個計算器有沒有問題呢,肯定是有的……一個非常簡單的辦法是按等號後加一個閃爍時間,就像大多數計算器一樣。當然,加個屏幕滑動也不是不可以。

為什麼他們沒有這麼做呢?這就不是我們需要想的問題了,留給開發者去想吧。那麼多BUG反饋的方式,又不是人看著玩的。

當然,也許蘋果可以說這個鍋我不背,用戶自己應該會點數學。不過,當時這個問題被抖出來的時候,可真有人去專賣店退貨的。

好的說回來,開方這個功能有沒有解決方案?當然有,如果整數開方的結果很像另一個整數(中間有很長的循環部分,比如4開方變成2.0000000...,一堆0),就去掉最後的部分平方回去,如果完全一樣就當成結果好了。

嗯我知道,一定有人會說sqrt(1/9)-1/3不等於0的,不過,能想到這裡的人,基本上還是會數學的吧。


題主:

Windows 中的這個計算器,和我們平時用的各種計算機一樣,是用有限小數顯示結果的。只要是這樣的,那就無法避免精度誤差。

數學上,你的根號幾都可以直接用符號表示,比如根號 2,就直接寫根號 2,不需要寫 1.414...。根號 2 這個符號的值,只能約等於 1.414...,而不能完全等於。Windows 中的計算器不行,因為是有限小數的結果,所以這就造成了誤差缺陷。

你也可以使用諸如 MATLAB 這樣的專業計算軟體,其所有的中間量都是按照符號量進行保存的,根號 2 就是根號 2,不是有限小數的 1.414...,甚至根號 4 也是根號 4,不是 2。除非到了最終結果,否則不進行中間計算,最後使用各種數學規則可以算出精確的結果(無理數除外,這個就連世界上最牛逼的數學家也做不到)。但人家是 10 多個 G。

那為什麼根號 4 - 2 算出了等於 -8x10 的 -39 次方呢?那是因為計算器算出的根號 4 並不等於 2。而題主你認為的根號 4 等於 2,那是因為你已知了正負 2 的平方是 4,所以 4 的平方根是 2。那對於你未知的呢?你照樣要用迭代法算,而且平方根運算不是用標準的四則運算就能算出準確值的,它只能無限接近其準確值。而由於實數有無窮多個,所以註定了計算器不能已知哪個數的平方是幾,也就是說不能用查表的方式精確計算平方根,只能迭代逼近。其實計算器算出來的根號 4 是 2 - 8x10 的 -39 次方這個值,有效數字從個位的 2 開始,顯示上保留 20 位有效數字,內存中保留 40 位精度,所以你看到的是 2。而當它再減去 2 後,數字變成了 -8x10 的 -39 次方,有效數字反而從小數點後 39 位開始了,再加上浮點數運算過程中的誤差,就變成了你所看到的樣子。

這是計算器,不是數學。真要有數學上的要求,大可用一些專業的計算軟體,它們在計算時,對於複雜運算是用符號量而不是有誤差的有限小數表示,完美解決你的問題。簡潔和精確兩者不可兼得。


這是浮點誤差啊,和bug有什麼關係-.-

=================================

加點東西吧,既然題主都重新編輯了問題的描述了.

如果應用不能保證正確,最好的做法是不提供開方功能。

我們手上的實體計算器精度更差,但我猜大家都不希望它把開方這個按鈕去掉了.

既然提供了,就應該得出「用戶預期的正確結果」。

對於這個"用戶預期的答案",大概大家對1/3*3的結果是0.999999是不驚訝的,甚至有些人覺得輸出1才是奇怪的.這和程序員沒有關係,自從我使用計算器發現了這個事實之後,就這麼認為的.

因此,"用戶預期的答案"是什麼?可以說是因人而異.顯然,我和題主的預期有很大差別.

說的不好聽一點,之所以會有人覺得不是 bug,只是因為在他們的能力範圍內解決不了。

是的,寫這樣完全精確的計算器是很難的.但問題是,是否有必要寫這樣的計算器.這個問題有點像家裡需要一部普通的計算器,還是一部科學的計算器.

對於微軟來說,它要考慮這個計算器的使用人群.或者說,它要這個計算器能滿足大部分人的需求,以及,"用戶預期的答案".

顯然,在這裡-1e-19和0都可以是"用戶預期的答案".可能對初次使用的人來說,得到-1e-19這個答案會比較詫異.

對於要求精確計算的用戶來說,他肯定會有這樣的意識,普通的計算器不放心,他需要尋找特定的計算工具.這裡的不放心,不是指開發者寫的有問題,是指計算器的固有缺陷.

這樣分析,微軟完全沒有必要實現一個精確的計算器.

因為在他們的意識里,This is how it works,這就是他們世界的運行法則。

計算機科學和物理科學一樣,有它們的法則,這個法則不是人能輕易改變的,也不是人隨便造出來的.

顯然,無法實現完全精確計算,是當前計算機科學得出的無奈結論.

然而偏偏有些偉大的程序員,就解決了這個問題。

如果你是指實現某種程度上的精確計算,請谷歌一下,這樣的計算工具是有的.

如果你是指實現完全的精確計算,請告訴我一下這方面的研究方向,我也很好奇.

=================================

有一位提到了,1pF=1e-12如果變成了0,會很危險.

這或許是個好例子...

=================================

另外,如果微軟因為這個而產生信任危機的話,我一定要把python批判一番.


推薦閱讀:

聽說很多微軟員工自己不用 Windows,是真的嗎?
為什麼蘋果美國工廠的 iMac 上運行的是 Windows 系統?
有哪些關於 Windows 下 C++ 程序調試的書推薦?

TAG:MicrosoftWindows | 數學 | 程序 | 計算器 | 浮點數 |