電腦何中常用的函數及一些精度的簡單處理__函數

來源:互聯網
上載者:User
double hypot(double x,double y)//返回直角三角形斜邊的長度(z)double fabs(double x)//返回雙精確度參數x的絕對值double log(double x)//返回logex的值  double log10(double x)//返回log10x的值double pow(double x,double y)//返回x^y的值double pow10(int p)//返回10p的值double sqrt(double x)//返回x的開方double acos(double x)//返回x的反餘弦值,x為弧度double asin(double x)//返回x的反正弦值,x為弧度double atan(double x)//返回x的反正切值,x為弧度double atan2(double y,double x)//返回y/x的反正切值,y的x為弧度   double cos(double x)//返回x的餘弦cos(x)值,x為弧度double sin(double x)//返回x的正弦sin(x)值,x為弧度   double tan(double   x)//返回x的正切tan(x)值,x為弧度

以上主要是math標頭檔中的一些函數


//一下精度處理部分為轉載部分

1.浮點數為啥會有精度問題:

浮點數(以C/C++為準),一般用的較多的是float, double。

 

占位元組數

數值範圍

十進位精度位元

float

4

-3.4e-38~3.4e38

6~7

double

8

-1.7e-308~1.7e308

14~15

如果記憶體不是很緊張或者精度要求不是很低,一般選用double。14位的精度(是有效數字位,不是小數點後的位元)通常夠用了。注意,問題來了,資料精度位元達到了14位,但有些浮點運算的結果精度並達不到這麼高,可能準確的結果只有10~12位左右。那低幾位呢。自然就是不可預料的數字了。這給我們帶來這樣的問題:即使是理論上相同的值,由於是經過不同的運算過程得到的,他們在低幾位有可能(一般來說都是)是不同的。這種現象看似沒太大的影響,卻會一種運算產生致命的影響: ==。恩,就是判斷相等。注意,C/C++中浮點數的==需要完全一樣才能返回true。來看下面這個例子:

#include<stdio.h>

#include<math.h>

int main()

{

   double a = asin(sqrt(2.0) / 2) * 4.0;

   double b = acos(-1.0);

   printf("      a = %.20lf\n", a);

   printf("      b = %.20lf\n", b);

   printf(" a - b = %.20lf\n", a - b);

   printf("a == b = %d\n", a == b);

   return 0;

}

輸出:

      a = 3.14159265358979360000

      b = 3.14159265358979310000

 a - b = 0.00000000000000044409

a == b = 0

我們解決的辦法是引進eps,來輔助判斷浮點數的相等。

 

2. eps

       eps縮寫自epsilon,表示一個小量,但這個小量又要確保遠大於浮點運算結果的不確定量。eps最常見的取值是1e-8左右。引入eps後,我們判斷兩浮點數a、b相等的方式如下:

定義三出口函數如下: int sgn(double a){return a < -eps ? -1 : a < eps ? 0 : 1;}

則各種判斷大小的運算都應做如下修正:

傳統意義

修正寫法1

修正寫法2

a == b

sgn(a - b) == 0

fabs(a – b) < eps

a != b

sgn(a - b) != 0

fabs(a – b) > eps

a < b

sgn(a - b) < 0

a – b < -eps

a <= b

sgn(a - b) <= 0

a – b < eps

a > b

sgn(a - b) > 0

a – b > eps

a >= b

sgn(a - b) >= 0

a – b > -eps

這樣,我們才能把相差非常近的浮點數判為相等;同時把確實相差較大(差值大於eps)的數判為不相等。

PS: 養成好習慣,盡量不要再對浮點數做==判斷。例如,我的修正寫法2裡就沒有出現==。

 

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<T>

有時候我們可能會有這種需求,對浮點數進行 插入、查詢是否插入過 的操作。手寫hash表是一個方法(hash函數一樣要小心設計),但set不是更方便嗎。但set好像是按==來判重的呀。貌似行不通呢。經觀察,set不是通過==來判斷相等的,是通過<來進行的,具體說來,只要a<b 和 b<a 都不成立,就認為a和b相等,可以發現,

如果將小於定義成:      bool operator < (const Dat dat)const{return val < dat.val - eps;}就可以解決問題了。 (基本類型不能重載運算子,所以封裝了下)

 

8. 輸入值波動過大

這種情況不常見,不過可以協助你更熟悉eps。假如一道題輸入說,給一個浮點數a, 1e-20 < a < 1e20。那你還敢用1e-8做eps麼。合理的做法是把eps按照輸入規模縮放到合適大小。

典型案例: HUSTOJ 1361

 

9. 一些建議

容易產生較大浮點誤差的函數有asin、 acos。盡量使用atan2。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.