为何将int除以2会产生正确的值?


110

以下代码段中的结果如何

int a = 7;
int b = 3;
double c = 0;
c = a / b;

c最终得到的值为2,而不是人们所期望的2.3333。如果ab是双打,答案的确变为2.333。但是可以肯定的是,因为c 已经是双精度数,它应该与整数一起使用吗?

那么怎么int/int=double不起作用呢?


Answers:


161

这是因为您使用的是的整数除法版本operator/,需要2 ints并返回int。为了使用double返回a 的版本,必须将s double中的至少一个int显式转换为a double

c = a/(double)b;

9
我宁愿明确地都转换abdouble仅出于清楚,但它其实并不重要。
John Dibling 2011年

31
由于该问题被标记为C ++,所以我希望看到static_cast <>而不是C强制转换。
马丁·约克

16
就我个人而言,我认为C样式的转换更加清晰(大多数其他通用语言的广播都是以C样式的方式进行的)。 static_cast<>对我来说似乎总是很长。在原语的情况下,确实没有得到任何危险static_cast<>reinterpret_cast<>混合起来。
乍得拉瓜迪亚

6
@ Tux-D:用于算术强制转换?static_cast在这种情况下,我宁愿避免使用C样式的强制转换。在这里使用C ++样式的强制类型转换没有任何好处,并且它们比C样式的强制转换更加混乱。算术强制转换恰好是C样式强制转换非常适合并且实际上比其他强制转换更合适的上下文。
2011年

19
有时,您可以通过写作胜过“没有C风格的人” double(b)。他们并不总是意识到这是一次转换,因为它看起来与显式构造函数调用相同。
史蒂夫·杰索普

12

这里是:

a)除以2 int总是执行整数除法。因此,a/b根据您的情况,结果只能是int

如果你想保持abintS,尚未完全分化他们,你必须投其中至少有一个加倍:(double)a/ba/(double)b(double)a/(double)b

b)中c是一个double,因此它可以接受int上assignement值:所述int被自动转换为double并分配给c

c)请记住,在赋值时,将首先=计算右边的表达式(根据上面的规则(a),并且不考虑左边的变量),然后将其赋值到左边的变量(根据( b)以上。我相信这完成了整个过程。==


11

除了少数例外(我只能想到一个例外),C ++会根据表达式本身确定表达式(或子表达式)的全部含义。表达式结果的处理无关紧要。在您的情况下,表达式中a / b没有出现double;一切都是int。因此,编译器使用整数除法。只有获得结果后,它才会考虑如何处理并将其转换为double


3
我可以想到的一个例外是在获取指针时选择函数重载-值&funcname取决于您将其强制转换为哪种类型。
史蒂夫·杰索普

2
@Steve Jessop这也是我能想到的唯一例外。(但是考虑到标准的规模和复杂性,我不想发誓我从未错过任何内容。)
James Kanze 2011年

6

c是一个double变量,但是分配给它的int值是一个值,因为它是由两个ints 的除法产生的,这为您提供了“整数除法”(除去余数)。因此,发生在生产线上的c=a/b

  1. a/b 被评估,创建一个临时类型 int
  2. c转换为type后,将临时值分配给double

a/b确定的值时不参考其上下文(分配给double)。


6

当您将两个整数相除时,结果将是一个整数,而与将其存储在双精度数中无关。


5

在C ++语言中,子表达式的结果永远不会受到周围环境的影响(有一些罕见的例外)。这是该语言认真遵循的原则之一。该表达式c = a / b包含一个独立的子表达式a / b,该子表达式独立于该子表达式之外的任何事物进行解释。该语言并不关心您以后将结果分配给doublea / b是整数除法。其他没有关系。您将在语言规范的许多角落看到遵循这一原则的方法。这说明了C ++(和C)的工作方式。

我上面提到的异常的一个示例是函数重载情况下的函数指针分配/初始化

void foo(int);
void foo(double);

void (*p)(double) = &foo; // automatically selects `foo(fouble)`

在这种情况下,赋值/初始化的左侧会影响右侧的行为。(此外,对数组的引用初始化可防止数组类型衰减,这是类似行为的另一个示例。)在所有其他情况下,右侧完全忽略左侧。


4

/运算符可用于整数除法或浮点除法。您给它两个整数操作数,所以它在进行整数除法,然后结果存储在double中。


2

从技术上讲,这是依赖于语言的,但是几乎所有语言都对该主题进行相同的处理。当表达式中两个数据类型之间的类型不匹配时,大多数语言会尝试=根据一组预定义的规则将数据强制转换到的一侧,以匹配另一侧的数据。

将两个相同类型的数字(整数,双精度数等)相除时,结果将始终为同一类型(因此,“ int / int”将始终为int)。

在这种情况下,您需要 在计算之后double var = integer result 将整数结果转换为双精度数,在这种情况下,小数数据已经丢失。(大多数语言都会进行这种转换,以防止类型不正确,而不会引发异常或错误)。

如果您想将结果保持为两倍,则需要创建一种情况 double var = double result

最简单的方法是强制将方程式右侧的表达式强制转换为双精度:

c = a/(double)b

整数与双精度数之间的除法将导致将整数强制转换为双精度数(请注意,在进行数学运算时,编译器通常会“转换”为最特定的数据类型,以防止数据丢失)。

翻身之后,a将结束为双打,现在您可以在两个双打之间进行划分。这将创建所需的划分和分配。

同样,请注意,这是特定于语言的(甚至可能是特定于编译器的),但是几乎所有语言(肯定是我能想到的所有语言)都以相同的方式对待此示例。


这个问题被标记为[C ++],C ++标准明确规定了它的工作方式。假设没有使用任何编译器扩展,则不确定“语言特定”的含义,当然也不是编译器特定的。
John Dibling 2011年

同样,说“ double var =将double变量转换为int的整数结果”也是不正确的。不能将double转换为int。将int结果转换为双精度型。
John Dibling 2011年

我允许使用编译器扩展(实际上,我的环境在“错误地投射”结果并且我不知道为什么的情况下,实际上就遇到了这个问题)。结果是特定于语言的,因为某些语言不遵循相同的转换规则。我不认为这是C ++特定的标记。您对“ double var =整数结果”的评论是正确的。编辑以反映这一点。谢谢!
matthewdunnam 2011年

0

重要的是计算的要素之一是浮点双精度型。然后,要获得双重结果,您需要像下面所示那样投射此元素:

c = static_cast<double>(a) / b;

或c = a / static_cast(b);

或者您可以直接创建它:

c = 7.0 / 3;

请注意,计算元素之一必须具有“ .0”,以表示浮点双精度类型被整数除。否则,尽管c变量为双精度型,结果也将为零。


您的答案带来了其他9个答案中没有一个的答案?
bolov
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.