似是而非的k sqrt n

2021-09-08 16:59:19 字數 2236 閱讀 9380

//題目:輸入乙個大於3的整數n,判定它是否為素數(prime,又稱質數)

#include

#include

int main()

————譚浩強.《c程式設計》(第四版).p137,清華大學出版社

這個程式的**首先輸入需要判斷的整數並存放在變數n中(其實這個變數定義為unsigned型別更理想,因為題目中已經明確是大於3的整數)。緊接著通過:

k=sqrt(n);

試圖求出n的平方根或其平方根的整數部分。然而這個寫法是有問題的,能否正確地按照希望求得n的平方根或其整數部分是得不到保證的。

這是因為sqrt()函式的函式原型是:

double sqrt (double);

也就是說,sqrt()函式的引數和返回值都是double資料型別。double型別屬於浮點資料型別的一種,浮點型別並非像整數型別那樣可以精確地表示整數,正相反,浮點資料型別用於近似地表示實數,儘管在個別情況下可以精確地表示,但就一般意義上而言,浮點資料型別只是對一定範圍內的實數的一種近似表示。

因此,在k=sqrt(n)這個表示式中,不可能指望這個n是準確的,因為按照sqrt()函式原型的要求,這個n實際上表示的是(double)n,即呼叫時會存在型別轉換,轉換後的值為double型別,它是否精確等於原來的int型別的n值,一般而言是不清楚的。

或許有些對ieee754標準很熟悉的人對此不能贊同——他們非常清楚在這個標準下浮點數的表示方法和內部結構。好吧,「不爭論」,繼續看下乙個不確定性。

由於sqrt()函式的返回值是double型別,這表明sqrt()函式只承諾為我們求得實參的平方根的近似值——而不是像數學那樣一定可以得到乙個精確值。換句話說,當呼叫sqrt(9.)的時候,函式未必會精確地得到3.0這個數學上的精確的平方根,sqrt(9.)的值無論為3.000000000000001還是2.999999999999999 都有可能。這雖然是出於理性的判斷,但也並非絕無經驗事實作為佐證。試看下面的**:

#include #include int main( void )

在某些編譯器上的輸出結果是:

9999

這清楚地表明pow()這樣的返回值為double型別的數學函式只是一種近似計算的函式。sqrt()這個數學函式也是如此,sqrt(9.)的值無論為3.0、3.000000000000001還是2.999999999999999都有可能。一旦sqrt(9.)的值為2.999999999999999,那麼

k=sqrt(n);

for(i=2;i<=k;i++)

的迴圈次數就會產生錯誤。這種錯誤在何時出現很難預料,但k=sqrt(n)是乙個似是而非的表達則是確切無疑的。

這種未必立刻發作的錯誤比那些立刻就產生症狀的bug更可怕,它就像一顆不定時炸彈一樣說不定什麼時候造成損失。古代有則守株待兔的寓言,說的是某一天出現了兔子,你不能指望天天出現兔子。但這裡的情形恰恰相反,儘管很多天都沒出現兔子,但你保不准哪天就會突然竄出乙隻兔子。而一旦出現兔子,其嚴重後果則是你假定不會出現兔子時所無法預料的。

那麼此時應該如何求n的平方根或其整數部分呢?實際上可以利用下面的數學常識輕易求得:

1=1^2

1+3=2^2

1+3+5=3^2

…1+3+5+…+(2k1)=k^2

後面正確的**應用了這個原理。

樣本**中的另乙個問題是根本沒有考慮輸入一旦不小於3時應該如何處理,這樣的乙個嚴重後果是一旦使用者誤輸入資料,比如輸入了負數,程式將會發生悲慘的崩潰。在乙個真正的軟體中,絕對不能假設使用者一定會正確地輸入,否則可能帶來非常嚴重且無法彌補的損失。

此外,**中的輸出部分過於囉唆繁複,後面的**對此也進行了修正。

#include int main( void )

for(i=2;i<=k;i++)

if(n%i==0)

break;

printf("%d%s是素數\n" , n , (i > k)?"":"不");

} return 0;

}

其中:

while( n_ >=  odd )

用於求出n的平方根的整數部分。由於只需進行√n次整數的加減法運算,其效率方面也必定高於浮點運算的k=sqrt(n)。

求職中七個似是而非的誤區

求職的艱難使得關於求職指導成為一種小小的熱門,而有些流行在求職場上的觀點卻是似是而非的,如果求職者輕易被這些觀點牽著鼻子走,那麼可能會在求職中碰壁。誤區一 找工作的人應避免那些正在解雇員工的公司,試想乙個減員的公司怎麼還會僱傭新人呢?而在現實生活中,這些公司可能恰好就是求職人的最佳去處。有許多這樣的...

似是而非的製造業 德魯克日誌之五月十二日

quote b 你如何讓更少的員工製造出更多的產品 b 在對2020年的眾多 中,人們認為最可能實現的莫過於以下論斷 屆時,發達國家的製造業總產量至少要翻一番,但是製造業的員工總人數將會比現在減少10 12 變革製造業並且推動其生產率迅速提高是一種全新的概念,例如精益生產等。製造業的新理念比資訊化和...

權利是人賦而非天賦的

課堂回顧 你好,今天我要給你介紹乙個既離經叛道又實事求是而且合情合理的觀念,那就是權利其實是人賦的,不是天賦的。上一講我跟你講了權利和能力之間的區別。我們說在動物世界裡面,動物有的只有能力,might 而在人類社會裡面,當然每個人有能力,而他們更重要的是有權利,right。能力取決於你自己能夠占有多...