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