1.
浮點數為啥會有精度問題:
浮點數(以
c/c++為準)
,一般用的較多的是
float,double。
佔位元組數
數值範圍
十進位制精度位數
float
4-3.4e-38
~3.4e38
6~7double
8-1.7e-308
~1.7e308
14~15
如果記憶體不是很緊張或者精度要求不是很低,一般選用
double。14
位的精度
(是有效數字位,不是小數點後的位數
)通常夠用了。注意,問題來了,資料精度位數達到了
14位,但有些浮點運算的結果精度並達不到這麼高,可能準確的結果只有
10~12
位左右。那低幾位呢?自然就是不可預料的數字了。這給我們帶來這樣的問題:即使是理論上相同的值,由於是經過不同的運算過程得到的,他們在低幾位有可能
(一般來說都是
)是不同的。
這種現象看似沒太大的影響,卻會一種運算產生致命的影響
: ==
。恩,就是判斷相等。注意,
c/c++
中浮點數的
==需要完全一樣才能返回
true
。來看下面這個例子:
#include
#include
int main()
輸出:
a = 3.14159265358979360000
b = 3.14159265358979310000
a - b = 0.00000000000000044409
a == b = 0
我們解決的辦法是引進
eps,來輔助判斷浮點數的相等。
2.eps
eps縮寫自epsilon
,表示乙個小量,但這個小量又要確保遠大於浮點運算結果的不確定量。
eps最常見的取值是
1e-8
左右。引入
eps後,我們判斷兩浮點數a、
b相等的方式如下:
定義三出口函式如下
: intsgn(double a)
則各種判斷大小的運算都應做如下修正:
傳統意義
修正寫法
a == b
fabs(a – b) < eps
a != b
fabs(a – b) > eps
a < b
a – b < -eps
a <= b
a – b < eps
a > b
a – b > eps
a >= b
a – b > -eps
這樣,我們才能把相差非常近的浮點數判為相等
;同時把確實相差較大
(差值大於
eps)
的數判為不相等。
ps:養成好習慣,盡量不要再對浮點數做
==判斷。例如,我的修正寫法裡就沒有出現==。
3.eps
帶來的函式越界如果
sqrt(a),asin(a), acos(a)中的a
是你自己算出來並傳進來的,那就得小心了。 如果
a本來應該是
0的,由於浮點誤差,可能實際是乙個絕對值很小的負數(比如
1e-12),
這樣sqrt(a)應得0
的,直接因
a不在定義域而出錯。
類似地,如果
a本來應該是
±1,則
asin(a)
、acos(a)
也有可能出錯。
因此,對於此種函式,必需事先對
a進行校正。
4.
輸出陷阱
i
這一節和下一節一樣,都是因為題目要求輸出浮點數,導致的問題。而且都和四捨五入有關。 ,
據我所知有三種常見的方法:
1. printf(「%.3lf」, a); //保留a
的三位小數,按照第四位四捨五入。
2. (int)a; //將a
靠進0取整
3. ceil(a); floor(a); //
顧名思義,向上取證、向下取整。
需要注意的是,這兩個函式都返回
double
,而非int
其中第一種很常見於輸出
(nonsense…)。
現在考慮一種情況
,題目要求輸出保留兩位小數。有個
case
的正確答案的精確值是
0.005,
按理應該輸出
0.01,
但你的結果可能是
0.005000000001(恭喜)
,也有可能是
0.004999999999(
悲劇),
如果按照
printf(「%.2lf」,a)
輸出,那你的遭遇將和括號裡的字相同。
解決辦法是,如果
a為正,則輸出
a+eps,
否則輸出
a-eps
典型案例
: poj2826
5.
輸出陷阱
ii
icpc
題目輸出有個不成文的規定
(有時也成文
),不要輸出
: -0.000
那我們首先要弄清,什麼時候按
printf(「%.3lf\n」,a)
輸出會出現這個結果。
直接給出結果好了:a∈
(-0.000499999……,-0.000……1)
所以,如果你發現
a落在這個範圍內,請直接輸出
0.000
。更保險的做法是用
sprintf
直接判斷輸出結果是不是
-0.000
再予處理。
典型案例
:uva746
6.
範圍越界
這個嚴格來說不屬於精度範疇了,不過湊數還是可以的。請注意,雖然
double
可以表示的數的範圍很大,卻不是不窮大,上面說過最大是
1e308
。所以有些時候你得小心了,比如做連乘的時候,必要的時候要換成對數的和。
典型案例
:hdu3558
7.
關於set
有時候我們可能會有這種需求,對浮點數進行
插入、查詢是否插入過
的操作。手寫
hash
表是乙個方法
(hash
函式一樣要小心設計),但
set不是更方便嗎。但
set好像是按
==來判重的呀?貌似行不通呢。經觀察
,set
不是通過
==來判斷相等的,是通過
<
來進行的,具體說來,只要將小於定義成
: bool operator < (const dat dat)const
就可以解決問題了。
(基本型別不能過載運算子,所以封裝了下)
8.
輸入值波動過大
這種情況不常見,不過可以幫助你更熟悉
eps。假如一道題輸入說,給乙個浮點數
a, 1e-20 < a < 1e20
。那你還敢用
1e-8
做eps
麼?合理的做法是把
eps按照輸入規模縮放到合適大小。
典型案例
: hustoj1361
9.
一些建議
容易產生較大浮點誤差的函式有
asin
、acos
。歡迎盡量使用
atan2。
另外,如果資料明確說明是整數,而且範圍不大的話,使用
int或者
long long
代替double
都是極佳選擇,因為就不存在浮點誤差了。
注:atan2函式
atan2
(y,x)
是表示x-y
平面上所對應的
(x,y)
座標的角度,它的值域範圍是
(-pi,pi)
用數學表示就是:
atan2
(y,x)=arg(y/x)-pi
當y<0
時,其值為負,
當y>0
時,其值為正
.
js處理精度問題( )
加法函式 function accadd arg1,arg2 catch e try catch e m math.pow 10,math.max r1,r2 return arg1 m arg2 m m 給number型別增加乙個add方法,呼叫起來更加方便。number.prototype.ad...
php計算 處理丟失精度問題 保留小數
解決方法 使用php的內庫libbcmath 自 php 4.0.4,libbcmath 隨同 php 一起發布。該擴充套件不需要任何外部的庫 a bcdiv 100,100,2 除法 那麼 a 1.00 bcadd 2個任意精度數字的加法計算 bccomp 比較兩個任意精度的數字 bcdiv 2個...
PHP處理數學精度
用程式語言做計算,很多時候浮點數精度都是困擾過我的問題,即便是剛學php的新手也會在群裡問為什麼我的計算結果明顯不對,而我們總是老態龍鍾的丟出一句浮點數計算都存在精度問題,並沒有提出過什麼實質性的改善。比如下面的計算0.57 100 zhgxun pro zhgxun php a interacti...