為什麼一定要慎用C語言標準庫中的pow函數,你知道嗎?

pow函數是C語言標準庫中自帶的一個計算函數,其接口存在於math.h文件中,所以使用前要先包含math.h文件。該函數用途是計算x的y次方,並將結果返回給用戶,直接調用非常方便。在TC2.0中其原型為extern float pow(float x, float y); ,而在VC6.0中原型為double pow( double x, double y )。

VC6.0中的代碼實現:


為什麼一定要慎用C語言標準庫中的pow函數,你知道嗎?

pow函數使用範例

可以看到計算結果符合預期,但是最近在用MSP430做遠程升級時遇到了這樣一個問題:

升級前平臺會發送一幀升級包的描述信息,其中包含總幀數,用可顯字符來表示,例如要傳輸的總幀數是167幀,那麼表示就是''167'',我需要將其轉換成167並存儲,根據其規律我先想到了用pow函數來解決,也就是a * 100 + b * 10 + c的思路,但是計算出來的結果總為166,從而導致升級一直不成功,真是百思不得其解。

為什麼一定要慎用C語言標準庫中的pow函數,你知道嗎?

後來仔細研究了一下pow函數的實現,終於發現問題所在,pow函數由於參數和返回值都是double類型,其在計算機內存中表示方式本身就是一種近似,存在一定表達誤差,比如100.0在內存中可能用99.999999來表示,而其轉換為unsigned int類型時會導致精度丟失,造成轉換結果為99。

找到問題的原因所在就好解決了,針對這個特點我們可以採取四捨五入的辦法,比如可以在結果的基礎上加一個很小的常量值 const double eps = 1e-6; 還可以用round函數直接進行四捨五入。

為什麼一定要慎用C語言標準庫中的pow函數,你知道嗎?

另外這還和編譯器有很大的關係,有的編譯器能保證計算結果正確,而像我使用的IAR自帶的編譯器就不行了。類似的標準庫中很多函數如三角函數也會存在這個問題,所以大家在使用pow函數時要十分慎重,尤其是將結果往整數轉換時。


分享到:


相關文章: