C++ C++;:double vs unsigned int.为什么它会这样运行?

C++ C++;:double vs unsigned int.为什么它会这样运行?,c++,int,double,unsigned,C++,Int,Double,Unsigned,我试图把三个数相乘,但得到了一个奇怪的结果。为什么我会得到如此不同的结果 unsigned int a = 7; unsigned int b = 8; double d1 = -2 * a * b; double d2 = -2 * (double) a * (double) b; double d3 = -2 * ( a * b ); // outputs: // d1 = 4294967184.000000 // d2 = -112.000000 // d3 = 4294967184.0

我试图把三个数相乘,但得到了一个奇怪的结果。为什么我会得到如此不同的结果

unsigned int a = 7;
unsigned int b = 8;
double d1 = -2 * a * b;
double d2 = -2 * (double) a * (double) b;
double d3 = -2 * ( a * b );

// outputs:
// d1 = 4294967184.000000
// d2 = -112.000000
// d3 = 4294967184.000000

在第一个示例中,数字
-2
被转换为无符号整数。乘法结果为-112,表示为无符号时为2^32-112=4294967184。然后,该结果最终转换为分配的
double

在第二个例子中,所有的数学都是在双精度上进行的,从而得到正确的结果。如果您这样做,您将得到相同的结果:

double d3 = -2.0 * a * b
as
-2.0
是一个
文本

double d1=-2*a*b

右侧的所有内容都是整数类型,因此右侧将作为整数类型进行计算
a
b
是无符号的,因此指示结果的特定类型。那
-2
呢?它被转换为一个
无符号int
。使用2s补码运算将负整数转换为无符号整数。
-2
变成一个非常大的正无符号整数

double d2=-2*(double)a*(double)b


现在,右边是混合整数和浮点数,因此右边将作为浮点类型计算。那
-2
呢?它被转换成了双人房。现在转换很简单:
-2
转换为
双精度
成为
-2.0
双精度签名。这意味着第一位(最高有效位又称符号位)确定该数字是正还是负

unsigned int无法处理负值,因为它使用第一位(最高有效位)来扩展它可以表示的“正数”的范围。所以在

double d1 = -2 * a * b;
执行时,您的机器将整个(-2*a*b)放入无符号int结构(如a和b),并生成以下二进制11111111111111111111111111111000000(因为这是二者的112的补码,即0000 0000 0000 0111 0000)。但这里的问题是它是无符号int,所以它被视为一个非常大的正整数(4294967184),因为它没有将第一个1视为符号位

然后你把它放进一个双格,这就是为什么你要打印.00000

另一个例子之所以有效,是因为您将a键入double,将b键入double,因此当将-2与double相乘时,您的计算机会将其置于双精度结构中,因此将考虑符号位

double d3 = -2 * (double) (a * b)
这也行


<>为了获得一个关于符号和无符号的感觉,C++和C++中的检查

,内置运算符总是应用在同一类型的两个变量上。如果两个变量的初始值不同(或太小),则一组非常精确的规则将指导提升其中一个(或两个)

在这种情况下,
-2
默认为类型
有符号int
(同义词为
int
),而
a
b
为类型
无符号int
。在这种情况下,规则规定应将
-2
提升为
无符号int
,并且因为在您的系统上可能有32位
int
和2位补码表示,这最终是
2**32-2
(4294967294)。然后将该数字乘以a,取模为2**32(4294967282),然后再乘以b,模为2**32(4294967184)


这真是一个奇怪的系统,导致了无数的错误。例如,溢出本身导致了今年6月30日的Linux错误,导致世界各地的许多计算机被挂断。我听说它还使几个Java系统崩溃。

谢谢你的解释!但是为什么:“-122”我们这里有:“2^32-122”?什么是“122”?不是这样的。数字
-2
转换为
无符号整数
。在具有32位整数的机器上,
-2
变为4294967294。乘以56(7*8)不会得到-112。怎么可能呢?它产生了一个相当大的数字,240518168464。这对于
无符号int
来说太大了。这将变为4294967184,因为对于无符号整数,无法由结果无符号整数类型表示的结果将以大于结果无符号整数类型可以表示的最大值(换句话说,模2^n)的一个数的模减少。