來源:為什麼printf不能用%lf輸出double型,而用%f?
printf("%lf",a);
今天看到一篇好文章,mark一下。
出去旅遊了一下,是以有些天沒敲代碼,于是又弱爆了~忘掉了題目中的東西,結果出現了問題,好難找哈~
死記硬背是很難記住一些東西的,隻有了解原理才記得深入!
注意scanf函數和printf函數是不同尋常的函數,因為它們都沒有将函數的參數限制為固定數量。scanf函數和printf函數又可變長度的參數清單。當調用帶可變長度參數清單的函數時,編譯器會安排float參數自動轉換成為double類型,其結果是printf函數無法區分float型和double型的參數。是以在printf函數調用中%f既可以表示float型又表示double型的參數。
另一方面,scanf函數是通過指針指向變量的。%f告訴scanf函數在所傳位址位置上存儲一個float型值,而%lf告訴scanf函數在所傳位址位置上存儲一個double型值。這裡float和double的差別是非常重用的。如果給出了錯誤的轉換說明,那麼scanf函數将可能存儲錯誤的位元組數量(沒有提到的是,float型的為模式可能不同于double型的位模式)。
另外曆史原因C語言中浮點計算一直采用雙精度的形式。
附錄說明:IEEE浮點标準的兩種主要的浮點數格式:單精度(32位)和雙精度(64位)。數值以科學計數法的形式存儲,每一個數都是由3部分組成:符号、指數和小數。
EEE754浮點标準
EEE754标準在表示浮點數時,每個浮點數均由三部分組成:符号位S,指數部分E和尾數部分M。
我們知道10進制數的科學計數法如A= -3.5×105
這裡最前面有一個負号,3.5是尾數,兩個有效數字,後面以10為基數的指數為5。
我們可以将它表示為 -3.5E5
同樣,二進制數也可以用科學計數法規格化表示,比如5這個數,如果用二進制表示的話,整型為101,如果用科學計數法則可以表示為 1.25×24 ,這裡用的是十進制,将尾數換成二進制就是1.01(就是101向前移兩位小數點,和十進制完全相同),後面的指數4換成二進制則是10,那我們将其用二進制的科學計數法就可以寫成1.01E10。
當我們依照這種計數法給一個數字确定其精度(有效位)後,就可以用一定長度的1和0的位串來表示一個實數了。
浮點數一般采用以下四種基本格式:
(1)單精度格式(32位):除去符号位1位後,E占8位,M占23位。
(2)擴充單精度格式:E>=11位,M31位。
(3)雙精度格式:(64位);E=11位,M=52位。
(4)擴充雙精度格式:E>=15位,M>63位。
我們最重要的是掌握單精度格式的表示法。在IEEE754标準中,約定小數點左邊隐含有一位,通常這位數就是1,這樣實際上使尾數的有效位數為24位,即尾數為1.M。指數的值在這裡稱為階碼,為了表示指數的正負,是以階碼部分采用移碼表示,移碼值為127,階碼值即從1到254變為-126至+127,在 IEEE754中所有的數字位都得到了使用,明确地表示了無窮大和0,并且還引進了"非規格化數",使得絕對值較小的數得到更準确表示。請看下表:
S(1位) E(8位) M(23位) N(32位)
符 0 0 (-1)S·2E-127·(1.M) 為規格化數
0 不等于0 (-1)S·2-126·(0.M) 為非規格化數
号 1到254之間 不等于0 (-1)S·2E-127·(1.M) 為規格化數
255 不等于0 NaN(非數值)
位 255 0 無窮大
其中紅色字0、1表示隐含位,注意當數字N為非規格化數或是0時,隐含位是0。
記住了上面的表格就能算出所有IEEE标準的單精度二進制浮點數了,我們重點要會計算規格化數字的雙向轉換,并且了解二進制浮點數表示法的思想。