本文摘於 ccos(Cheng Cosine) ccos.bbs@bbs.iie.ncku.edu.tw yhliu(劉應興) yhliu.bbs@bbs.iie.ncku.edu.tw Devil(璉璉) Devil.bbs@bbs.iie.ncku.edu.tw --------------------------------------------------------------------------- 發信人: ccos@bar (Cheng Cosine), 信區: fortran 標 題: Help!也是浮點數的問題... 我的問題是: 步驟:1.宣告a為倍精的實數 2.經過一些計算之後,a有了值,比如說 a=0.123451234512345d-015 3.我用write(11,*)把a值寫到一個檔案out1 4.再次由檔案out1讀入a值,read(10,*) aa 5.開啟另一個檔案,將a-aa用write(12,*)寫入out2 6.檢視檔案out2裡面所記載的值不為0!!! 我的猜測: 因為a真正的值可能是a=0.123451234512345123...d-015 因而在輸出到out1的時候, fortran當它是a=0.123451234512345d-015 以致於重新讀入時,aa-a~=0!!! 我的想法對嗎?是否有辦法證明我的猜測呢? 更清儲的說,給定一個已知a值,經過步驟1~5之後,能否預先知道在步驟6 所必然會出現的值呢? 開始感到頭昏的Cheng Cosine Dec./11/1995 ---------------------------------------------------------------------------- 發信人: yhliu@bar (劉應興), 信區: fortran 標 題: Re: Help!也是浮點數的問題... Fortran 中, 數值的儲存是二進位的, 輸出轉成十進位, 輸入再把十進位轉成二進位。在有小數的情形, 兩種進位 系統之間的轉換一般都會有誤差。 ---------------------------------------------------------------------------- 發信人: Devil@bar (璉璉), 信區: fortran 標 題: Re: Help!也是浮點數的問題... 在 computer 中無法避免小數點的極小錯誤, 這不算 bug, 是系統限制. 他的 問題不一定發生計算錯誤在何處, 由於發問者並沒有提供不等於 0, 而等於多 少的值, 所以我目前假設計算錯誤發生在下面兩點之一, 若倍精度變數小數點以下16位, 指數為d-15, 1.並沒有將完整的變數內容寫入檔案之中. 則不等於 0的值應大於 1.xxxx d(-15-16+1) , 也就是說大於 1. d-30 2.相減錯誤. 則不等於 0的部份應小於 1.xxxx d(-15-16) , 而你指出不對的 地方就是這, 但是這不是不會發生, 而是不一定發生. 所以劉同學並沒有說 錯. 尤其常作數值計算的人, 最頭痛的就是系統的限制造成的加減乘除的位 元誤差. ps. 由於原發者所提供的資訊不足, 所以回答都是各人的猜測, 很難說是對是 錯. 補充記載: 倍精度變數為 8 bytes=64 bits 其中保留 1 bit 為正負, 10 bit 為指數, 指數中又保留 1 bit 為指數的正負 剩下的 bit 才為有效位數使用. 其數值內容計算原則為 sum (i=1, 53) bit(i)*(1/2**i) 上述是原則, 有可能因各家編譯器為求速度的反應而略有不同. 另外, 387 是一次進行 60 bit 的計算, 所以資料傳輸後會有可能發生 1 bit 的誤差. (保留給指數 10 bit , 及 387 的 60 bit 中所提及的數值 10 及 60 是記憶 中的數值, 可能有誤, 正確數據需翻一下資料. 但是 6? <> 64, 不然就不會不 確定了) ---------------------------------------------------------------------------- 發信人: ccos@bar (Cheng Cosine), 信區: fortran 標 題: Re: Help!也是浮點數的問題... program test real*8 a, aa a=.12345123451234512345d-15 open(21,file='1.out') write(21,*) a close(21) open(20,file='1.out') open(22,file='2.out') read(20,*) aa write(22,*) aa-a close(20) close(22) stop end 執行結果: case I. 1.out : 0.123451234512345d-015 2.out :-0.986076131526265d-031 = -9.86076...d-032 assume aa = 1.out then exact = -0.12345d-030 = -1.2345d-031 Not the same as 2.out !? case II. if I change a=.12345123451234554321d-015 then 1.out : 0.123451234512346d-015 2.out : 0.443734259186819d-030 = 4.43734...d-031 assume aa = 1.out then exact = 0.45679d-030 = 4.5679d-031 Not the same as 2.out !