Re: [問題] float (加減乘除) int 問題

作者: remizu (remizu)   2014-04-22 17:44:05
剛好這個問題小弟覺得小弟有辦法回答,
趁本板高手們還沒出沒之前回一下,
希望能夠拋磚引玉,
若觀念有誤還請前輩們多多指教。
※ 引述《SuperMaster (神手)》之銘言:
: 小弟我再進行C++測試時遇到一點小問題
: [問題1:Type checking概念]
: 測試1:
: int a 10 ;
: float b = 2.5 ;
: b = a + b ;
: printf( "%f", b ) ;
: 印出值為:12.5 << 因為會發生型別轉換
: 測試2:
: int a = 10 ;
: float b = 2.5 ;
: b = a / 3 ;
: printf( "%f", b ) ;
: 印出值為:3 << 沒有轉換 應該要是3.33333
: 需要改成b = (float)a / 3 才能印出正確的值
: 為什麼測試1的不需要就能印出正確的值??????
這是個arithmetic expression type conversion的問題,
用簡單的一句話回答就是:C++標準這樣規定。
對於built-in的arithmetic type來說,
當operator兩邊的operands型別不同時,
compiler會自動發生一些型別轉換。
原原PO的測試1中,a是int型別,b是float型別。
當執行a + b時,a會被轉換成float型別,
然後再進行float加法動作,最後將其結果賦值給b。
所以能得到原原PO預期中的正確結果。
在測試2中,由於變數a及字面常數3都是int型別。
因此a / 3實際上是int / int的操作。
執行的是所謂的整數除法,
根據標準,其結果的小數部分將被直接捨去。
10 / 3 = 3.333...捨去小數部分後得到3,
最後將這個int型別的3轉型成float並賦值給b。
若想獲得3.333...的結果,可以如前篇推文所說,
在算術表達式中進行顯式轉型:
b = static_cast<float>(a) / 3; // Cast variable 'a' to float type.

b = a / 3.0f; // Let literal constant be float type.
從而令算術表達式進行時,
另一個operand也能夠被隱式轉型為float。
關於int / int的整數除法行為,
與float / float的浮點數除法行為不同之處。(前者捨去小數部分)
則可以視為是一種built-in的operator overloading。
雖然,在算術表達式中,看起來總是由小型別轉換至大型別。
但實際上並非總是如此,
這些算術表達式型別轉換規則比想像的還要更複雜一些,
以C++11的標準來說,
大致上可以依循下列規則確定operand會被轉換成什麼型別:
1. 若operator兩邊有其中一邊的operand是long double型別,
則另一邊的operand也會被轉換成long double型別。
2. 否則,若其中一邊的operand是double型別,
則另一邊的operand也會被轉換成double型別。
3. 否則,若其中一邊的operand是float型別,
則另一邊的operand也會被轉換成float型別。 // 原原PO問題即適用這條
4. 否則,若兩邊的operand都是整數型別,
則會進行一個叫integral promotion(*1)的處理。
5. 在這種情況下,若兩邊的operand皆為signed或皆為unsigned,
則級別較低的型別會被轉型為級別較高的型別。
6. 若不符合上述規則,則表示一邊為signed、一邊為unsigned,
若unsigned的operand型別級別較高,
則另一邊的operand將被轉換為unsigned operand的型別。
7. 否則,當signed operand的型別可容納unsigned operand型別
所能表示的任意值時,unsigned operand將被轉型成signed operand的型別。
8. 當上述情況皆不符合時,兩邊的operands都會被轉換成
signed operand的型別的unsigned版本。
*1. 什麼是integral promotion?
當compiler在評估算術表達式時,會將bool、char、unsigned char、
signed char以及short自動轉換為int,並將bool值true轉換為1,
false轉換為0,這個過程就叫做integral promotion。舉例來說:
short power = 100;
short defense = 60;
short hp = power - defense; // here
此時,power及defense皆會被轉型成int,運算結果是
int型別的40,然後再轉型回short並賦值給hp。做這種轉換通常是為了
能夠更有效率地做運算,詳細就不再贅述。
下面舉一些例子:
long double llfResult;
double lfResult;
float fResult;
long long int llResult;
unsigned long ulResult;
int iResult;
short nResult;
long double llfValue = 789.12L;
double lfValue = 456.78;
float fValue = 123.45f;
long long llValue = 99999999LL;
unsigned long ulValue = 98765L;
int iValue = 100;
unsigned int uValue = 120u;
short nValue = 75;
char chValue = 13;
// According to rule 1, fValue will be converted to long double.
llfResult = llfValue + fValue;
// According to rule 2, fValue will be converted to double.
lfResult = lfValue + fValue;
// According to rule 3, iValue will be converted to float.
fResult = fValue + iValue;
// According to rule 4, nValue will be converted to int.
iResult = iValue + nValue;
// According to rule 4, both chValue and nValue will be converted
// to int and perform addition operation, and then convert back to
// short, assign to nResult.
nResult = chValue + nValue;
// According to rule 6, iValue will be converted to unsigned long.
ulResult = ulValue + iValue;
// According to rule 7, uValue will be converted to long long.
llResult = llValue + uValue;
要留心的是,上述規則為C++11的標準,與C++03以及ANSI C標準有些微差異,
詳細狀況還得看自己的編譯環境而定。
:
作者: ot32em (reverse(wasefo);)   2014-04-22 21:50:00
我記得在 function overloading,promotion會比標準轉換優先這是其中之一的差異

Links booklink

Contact Us: admin [ a t ] ucptt.com