2013-10-04 55 views
0

爲什麼當我的溢出計算是printf()函數的參數時,float不會溢出,但是當編碼計算被分配給單獨的變量float_overflowed並且不是printf函數的參數I得到'inf'的預期結果? 這是爲什麼發生?是什麼造成這種差異?浮點溢出但不是當C中的printf參數?

導致我出現這個問題的代碼和結果如下。

這裏是我的代碼按預期計算是一種論點,即未執行:當計算不是一個參數

This demonstrates floating data type overflow. We should get an 'inf' value. 
3.400000e+38*10=3.400000e+39. 

而且,:

float float_overflow; 
float_overflow=3.4e38; 
printf("This demonstrates floating data type overflow. We should get an \'inf\' value.\n%e*10=%e.\n\n",float_overflow, float_overflow*10);  //No overflow? 

結果

float float_upperlimit; 
float float_overflowed; 
float_upperlimit=3.4e38; 
float_overflowed=float_upperlimit*10; 
printf("This demonstrates floating data type overflow. We should get an \'inf\' value.\n%e*10=%e.\n\n",float_upperlimit, float_overflowed);  //for float overflow 

及其結果:

This demonstrates floating data type overflow. We should get an 'inf' value. 
3.400000e+38*10=inf. 
+0

根據我的理解,當將信息存儲在一個變量中時,「溢出」是opccurs。因爲,否則,它只是指數中的另一點。 – cyphar

回答

6

實際上,編譯器並不侷限於在float中進行算術運算,但它可能會使用double。當前的C標準的5.2.4.2.1具有:

除了分配和流延(其去除所有多餘的範圍和精度 ),是由操作者受到通常的算術浮動操作數和 值,得到的值轉換和漂浮 常數被評估爲一個格式,其範圍和精度可能是 大於該類型所要求的格式。使用的評價形式的特點是通過 FLT_EVAL_METHOD

的實現定義的值,所以你只知道逼值爲float當你將它。因爲在printf調用(它是一個va_arg函數)的上下文中,無論如何都需要double,所以在FLT_EVAL_METHOD的值爲1的情況下不存在轉換髮生,即全部float算術在double中完成。

+0

謝謝你的幫助!我可以更改FLT_EVAL_METHOD嗎?如果是這樣,怎麼樣? –

+0

@JonPlotner,不,不是以便攜的方式。該常量的值由編譯器實現者選擇。我想允許更改會很困難,因爲這可能會導致與'math.h'函數不一致。 –

+0

@JonPlotner如果您使用的是GCC,那麼使用命令行選項'-mfpmath = sse -msse2'應該配置GCC,使其將FLT_EVAL_METHOD定義爲0。 –

1

請記住,對於"%e"格式(以及所有其他浮點格式化代碼),參數實際上是double。見例如表in this reference

這意味着當您將「in-line」作爲參數進行計算時,您現在實際上會溢出。但是當你爲變量做這件事的時候,它確實溢出了,當在printf調用中使用時,它就會被攜帶。

+0

因此,如果我正確理解你的話,我相信你是說當計算的內聯「float_overflow * 10」沒有被聲明爲浮點數,而是作爲double存儲在計算機內存中,因爲說明符「%e」指向/使雙倍的空間,而不是更小的浮動?我只是想確保我明白。我曾經迷失,但現在我找到了。謝謝程序員Sheppard :) –

+2

這個答案只包含了一半的故事。乘法「float_overflow * 10」的類型在被提升爲「double」之前是「float」的。 FLT_EVAL_METHOD = 0時,printf(「%e」,float_overflow * 10)'**不會** printf'inf'。延斯古斯特的答案包含了後半部分的解釋。 –

+3

「爲'%e'格式[[]]參數實際上是一個'雙'」也是誤導。由於'%e'預計它不會發生到'double'的提升,而是因爲「C99的6.5.2.2:7」中的「默認參數提升在追蹤參數上執行」。如果格式爲'%Le',那麼參數實際上會是'長雙',但這並不意味着該表達式會自動被提升爲'long double'。 –