为什么除法结果为零而不是小数?
教我自己C,发现当我做一个温度转换的方程时,除非把分数改成小数,否则它将不起作用。 即
tempC=(.555*(tempF-32))
将工作,但tempC=((5/9)*(tempF-32))
将不起作用。
为什么?
根据C底漆加它应该工作,因为我为tempC和tempF使用浮动。
看起来你在第二种情况下有整数除法:
tempC=((5/9)*(tempF-32))
5 / 9
将被截断为零。
为了解决这个问题,你需要使其中一个浮点types:
tempC=((5./9.)*(tempF-32))
其他人已经告诉你,5和9都是整数,这就是为什么结果被截断的原因。
我将添加一个解释,以更深入地了解行之间真正发生的事情:
double tempC; double tempF; tempC = (5/9) * (tempF-32); // removed unnecessary parenthesis
根据您的特定编译器使用的从左到右或从右到左的评估顺序 ,它将开始评估子expression式(5/9)
或(tempF-32)
。
你无法知道这两个评估中的哪一个! 因为评估顺序在C中是未指定的行为,这意味着编译器可以做任何事情,而不需要logging如何。 因此,不应该依赖评估的顺序编写代码,否则将不可移植,可能不正确。
让我们假设一个特定的编译器使用从左到右的评估。
- C的运算符优先级规则决定开始评估的位置。 括号运算符在C中具有最高优先级,因此编译器将首先评估遇到的第一个括号内容。
- 因此,它将从expression式
(5/9)
。 - 编译器检查每个操作数的types。
- 在这种情况下,它们都是常量整数文字。 整数文字在C中总是
int
types - 由于两个操作数都是相同的types,所以不需要隐式types转换。
- 计算是在一个
int
types上执行的,结果是一个int
。
所以现在expression式被评估为:
tempC = (int)0 * (tempF-32);
- 编译器然后评估(tempF-32)。
- 操作数的types是
double
和int
。 它们不是同一types的。 - 隐式types转换发生。 在这种情况下称为平衡(正式称为通常的算术转换 )。
- 平衡规则说,如果一种types是双重的,另一种是别的,另一种types应该被转换成双倍。
- 在隐式types转换之后,expression式现在相当于
(double)tempF - (double)32.0
。 计算结果并将其存储在double
types的临时不可见variables中。 这个不可见variables存储在CPU寄存器或堆栈中。
现在的expression可以被描述为
tempC = (int)result1 * (double)result2;
其中“result1”为0,“result2”为tempF – 32.0的结果。
- 编译器然后评估这个新的expression式。 它find一个
int
和一个double
。 - 再次,平衡发生,int被转换为double。
- 乘法是在两个双打上执行的,结果是双倍的。
- 结果存储在另一个临时的不可见variables中。
tempC = (double)result3;
- 编译器评估这个新的expression式。 它发现一个双倍应该保存在一个双。 这不是问题,所以不需要隐式转换。 “result3”存储在tempC中。
当你做5/9,5和9都是整数和整数除法发生。 整数除法的结果是一个整数,它是两个操作数的商。 因此,5/9的情况下的商是0,并且由于您乘以0,所以tempC会出现为0.为了不具有整数除法,两个操作数中的至less一个必须是float
。
例如,如果您使用5.0 / 9或5 / 9.0或5.0 / 9.0,它将按预期工作。
5/9是一个整数除法,不是浮点除法。 这就是为什么你得到错误的结果。
使5或9浮点variables,你会得到正确的答案。
像5.0 / 9或5 / 9.0
5/9
是一个整数expression式,因此它被截断为0.您的编译器应该警告您这个,否则您应该查看启用警告。
如果将5/9放在括号中,则将首先计算这个值,因为这些是两个整数,所以将通过整数除法完成,结果将为0,然后评估其余的expression式。
您可以重新排列expression式,以便首先发生浮动转换:
tempC=((5/9)*(tempF-32));
→ tempC=(5*(tempF-32))/9;
或者当然,正如别人所说的,使用浮点常量。