首页 > 试题广场 >

以下说法正确的是

[单选题]
void swap_int(int *a, int *b){
  *a = *a + *b;
  *b = *a - *b;
  *a = *a - *b;
}

int m = 2112340000, n = 2100001234;
swap_int(&m, &n);
以下说法正确的是:
  • 结果不正确,因为会溢出,用位与的方式就没问题
  • 结果正确,即使会溢出
  • 结果正确,不会溢出
  • 其他选项都不对
设整形变量*a、*b的位表示为
*a = n31n30 ··· n0
*b = m31m30 ··· m0
只有当*a > 0 && *b > 0 或 *a < 0 && *b < 0时才会发生溢出。两者类似,只证明均大于0时的情况。必须扩展额外一位才能够容纳正确的结果,'|'左边为扩展位。
*a = 0|0n30 ··· n= n30*230 +  n29*229 + ··· + n0*20 = N
*b = 0|0m30 ··· m0 = m30*230 +  m29*229 + ··· + m0*20 = M
若和溢出,则33位表示必为
*a + *b = 0|1b30 ··· b= -231 + b30*230 +  b29*229 + ··· + b0*2=  2 31  + B  
计算机将得到的33位结果truncate回原来的32位,即丢弃第33位(0)变为:
*a + *b =    1b30 ··· b= -231 + b30*230 +  b29*229 + ··· + b0*20 = -2  31   + B ②
正确的真实值是①,溢出结果为②,可见溢出结果=真实值-2 32
则*b = *a - *b = ② - *b =  ① - 232 - *b = *a + *b - 232 - *b = -232 + *a
最后一步,来看 -232 + *a  == *a 成立否?
0 < *a < 231, 则 -232 < -232 + *a < -231,和仍需要扩展1位方能表示:
*a    = 0|0n30 ··· n= n30*230 +  n29*229 + ··· + n0*20 = N
-232 = 1|0000 ··· 00
 和的位表示为
-232 + *a = 1|0n30 ··· n= n30*230 +  n29*229 + ··· + n0*20
同样,计算机把33位结果truncate回32位(丢弃第33位)得到:
-232 + *a =  0n30 ··· n= n30*230 +  n29*229 + ··· + n0*20 = *a
可见-232 + *a  == *a 是成立的。因此尽管溢出了,但仍能正确交换。
---分隔线---
写的比较繁琐,见谅。

编辑于 2015-08-20 15:09:00 回复(17)
这道题首先得保证输入的两个参数不是指向同一个地址,否则,无论两个数如何,交换后的结果都将变为零,题目中没说明这一点。
发表于 2015-08-16 10:21:32 回复(9)
举个栗子
交换-5, -7。 以4bit为例。
-5 = 1011 (补码)    -7 = 1001 (补码)
(-5)+ (-7)= 10100=0100=4 (溢出后为4)
4-(-7)= 4 +7=0100 + 0111 = 1011 = -5的补码
4-(-5)= 4 + 5 = 0100 + 0101 = 1001 = -7的补码

发表于 2016-08-25 18:04:48 回复(0)
可能经验上的某种直觉告诉我们:加减法可能会溢出。其实不然,第一步的加运算可能会造成溢出,但它所造成的溢出会在后边的减运算中被溢出回来。
发表于 2015-08-13 16:11:17 回复(17)
此题可以参考《深入理解计算机》P58页习题2.30
大致思路:即使会产生溢出,但是运算法则仍然成立,举个例子,假设int只有4bit,那么-8 + (-5) = -13(溢出), 实际结果为3,而3-(-8) = 11(依然溢出),实际结果是-5,
所以,swap程序中的第二句: *b=*a-*b,相当于*b = *a+*b-*b;溢出并没有影响。

发表于 2015-08-18 10:49:20 回复(4)

以signed char为例 a=127 b=1为例

a=a+b时  溢出 此时 a=-128

b=a-b  -128-1溢出  b=127

a=a-b  -128-127 溢出 为1仍然能正确交换。

发表于 2018-06-11 20:40:53 回复(0)
*a=*a+*b;在*a和*b都比较大的时候,会出现越界的问题;
正确的做法是:
a=a^b;
b=a^b;
a=a^b;
发表于 2015-08-22 10:47:44 回复(2)
唉,费这劲干啥,多定义一个变量咋地了
发表于 2015-08-20 20:49:57 回复(0)
此题应当选"D". 当输入的指针指向同一个对象时必然是错误的.
发表于 2015-08-22 12:24:15 回复(0)
溢出会轮转。。 例如a+b—c和a—c+b结果是相同的,即使a+b会溢出。
发表于 2016-08-04 21:57:49 回复(0)
运算溢出时,将上述运算看作无符号整数的加法运算, -b用b的补码形式表示。 

c = a+b
c - b = c + b(补码)
        = c+(2^32-b)    
        = a+b+2^32-b 
        = a+2^32 ;在32位整数中 a+2^32 = a,
所以c-b = a


 
编辑于 2015-08-27 16:07:04 回复(2)

各个数据类型的表示范围可以看成是一个首尾相接的环,在进行某次运算后超出范围时,可按数据类型所能表示的最大数据范围的长度(char、unsigned char是2^8,int、unsigned int是2^32 )作为步长将溢出数据平移至范围内,就是最后结果

发表于 2017-06-15 16:50:56 回复(0)
求解答,a溢出变成负数后再减b的得到的不应该也是个负数吗,如何会还原呢
发表于 2015-08-14 13:11:36 回复(1)
sp头像 sp
如果输入的是同一个地址,不就错了吗
发表于 2015-08-15 19:52:54 回复(1)
结果应该是D吧 都超出int整数的取值范围了 在标准里应该是属于未定义吧
发表于 2024-11-17 14:46:42 回复(0)
荣荣:溢出存低八位

以signed char为例 a=127 b=1为例a=a+b时  溢出 此时 a=-128b=a-b  -128-1溢出  b=127a=a-b  -128-127 溢出 为1仍然能正确交换。
-128~127,循环🔄
发表于 2024-05-12 16:02:04 回复(0)
忽略进位的异或
发表于 2023-08-04 16:09:36 回复(0)
都溢出了结果还正确???

发表于 2022-08-21 15:08:21 回复(0)
使用异或就行了,大数就会溢出了,假设int超过max后
发表于 2021-02-02 22:29:31 回复(0)
其实蛮简单,假设两个正数a+b溢出到符号位,那么这个结果在计算机中就是补码形式表达。
之后的b=b-a中的减法运算会把-a转化为补码
此时b+(-a)符号位都为1所以溢出,符号位又变为0此时,正好就是a。
可以拿几个简单的例子来进行理解。严格证明还是看高赞答案吧。
编辑于 2019-09-23 21:46:27 回复(0)