在x86上测试一些整数乘法。
int32_t a = 2097152; int64_t b = a * a;
为什么上面的b的计算结果为零?
b
f87krz0w1#
x86上的int64_t范围限制是多少?C11标准7.20.2.1说[-2^63; 2^63-1]等效于[-9223372036854775808;9223372036854775807],你可以通过打印INT64_MAX和INT64_MIN来获得它。为什么上述b的值为零?因为只有在乘法运算完成后,提升才会发生。a*a的结果是int32_t类型,当溢出一个有符号整数时,就会调用未定义的行为。实际上,你所做的是:
[-2^63; 2^63-1]
[-9223372036854775808;9223372036854775807]
INT64_MAX
INT64_MIN
a*a
int32_t
int32_t a = 2097152; int32_t tmp = a * a; int64_t b = tmp;
您可以通过以下方式获得所需的结果:
int32_t a = 2097152; int64_t b = ((int64_t) a) * a;
外括号不是必需的,但重要的是要理解,我不是在谈论(int64_t)(a*a),因为它不会产生正确的结果。
(int64_t)(a*a)
ycggw6v22#
int64_t限制在您的示例中是无关紧要的,因为b类型仅在计算a * a表达式 * 之后 * 才起作用,并且损害已经造成。当执行算术时,执行“普通算术转换”,即值被转换为至少为int的公共类型;在本例中,int32_t很可能已经是int了,所以这两个值保持不变,执行32位乘法。这会溢出int32_t的范围,结果如图所示(请注意,有符号溢出实际上是未定义的行为)。要使其按预期运行,必须首先将至少一个操作数强制转换为int64_t,以便乘法以64位算术方式执行。
int64_t
a * a
int
int64_t b = ((int64_t)a) * a;
gpnt7bae3#
因为您将两个32位值相乘,得到的结果为32位。所以实际上你会得到(a * a) % 2^32因为2097152 * 2097152 = 4398046511104 = 0x40000000000个得到结果的0x00000000部分。如果你想做一个正确的64位乘法,你必须转换一个参数
(a * a) % 2^32
2097152 * 2097152 = 4398046511104 = 0x40000000000
0x00000000
int64_t b = (int64_t)a * a;
3条答案
按热度按时间f87krz0w1#
x86上的int64_t范围限制是多少?
C11标准7.20.2.1说
[-2^63; 2^63-1]
等效于[-9223372036854775808;9223372036854775807]
,你可以通过打印INT64_MAX
和INT64_MIN
来获得它。为什么上述b的值为零?
因为只有在乘法运算完成后,提升才会发生。
a*a
的结果是int32_t
类型,当溢出一个有符号整数时,就会调用未定义的行为。实际上,你所做的是:您可以通过以下方式获得所需的结果:
外括号不是必需的,但重要的是要理解,我不是在谈论
(int64_t)(a*a)
,因为它不会产生正确的结果。ycggw6v22#
int64_t
限制在您的示例中是无关紧要的,因为b
类型仅在计算a * a
表达式 * 之后 * 才起作用,并且损害已经造成。当执行算术时,执行“普通算术转换”,即值被转换为至少为
int
的公共类型;在本例中,int32_t
很可能已经是int
了,所以这两个值保持不变,执行32位乘法。这会溢出int32_t
的范围,结果如图所示(请注意,有符号溢出实际上是未定义的行为)。要使其按预期运行,必须首先将至少一个操作数强制转换为
int64_t
,以便乘法以64位算术方式执行。gpnt7bae3#
因为您将两个32位值相乘,得到的结果为32位。
所以实际上你会得到
(a * a) % 2^32
因为
2097152 * 2097152 = 4398046511104 = 0x40000000000
个得到结果的
0x00000000
部分。如果你想做一个正确的64位乘法,你必须转换一个参数