两个整数的异或运算是否会超出范围?

56

我一直在研究如何在一个数组中找到孤独的整数算法,并且这是实现:

int arr[] = {10, 20, 30, 5, 20, 10, 30};
int LonelyInteger = 0;
for(int i=0; i< 7; i++)
{
    LonelyInteger = LonelyInteger ^ arr[i];
}
结果是5
我的问题是 - 假设整数(由 XOR 操作生成)由于该操作过大
LonelyInteger ^ arr[i]

这可能导致一个非常大的整数,而在这种情况下常规 int 类型无法表示。我的问题是:

  1. 使用 XOR 运算是否有可能生成无法存储在 int 类型中的大整数?
  2. 如果不可能发生这种情况,是否有证明?

35
XOR是一种位运算。它不生成整数,而是生成位模式。结果逻辑上要么是一个陷阱表示,要么是一个值的非陷阱表示。无法获得“太大”的结果,因为“太大”的结果是不可表示的。 - davmac
11
x^y 可能比 max(x, y) 大,因此在这方面,你可以获得某个大数的定义。 - harold
2
@RasmiRanjanNayak:不,这个算法不会“找到”孤立的整数。它的命题只是 LonelyInteger != 0 → 存在一个孤立的值(注意它不是一个 ,就像例子 {1,2,3} 中所看到的那样)。 - Bergi
3
如果只有一个孤独的整数,结果将是该值。如果有多个整数,则您是正确的,唯一的信息是它是否!=0。 - Mooing Duck
5
@harold所说的是:x^y <= x+y < 2*max(x,y),这意味着你不能将任何一个操作数中已经设置的比特位设置得更高。例如:128^127 = 255,这仍然是一个8位的数值。 - smci
显示剩余5条评论
10个回答

121

XOR不会越界,因为它只是将位组合起来而不会在之前没有设置位的地方创建新位。

结果5是正确的。查看您的值和XOR结果的二进制表示。

10    00001010
20    00010100
30    00011110
 5    00000101
20    00010100
10    00001010
30    00011110
--------------
      00000101 => 5

计算多个XOR值的简单方法是:结果将在奇数数量的位组合时设置一个位,偶数位组合时不设置位。

如果这不可能发生,那么有证明吗?

XOR等价于对各个位进行无进位相加。当您无进位相加时,不会发生溢出,因此int值不会超出界限。


2
但是我们有足够的保证,int 类型是类似于二进制的吗?最大的整数是否发生在某个 n 的极限值为 2^n-1 的位置? - Yakk - Adam Nevraumont
这是关于按位异或的,所以当然它是二进制的。如果不是,我们就必须定义一个非按位异或(非二进制)。 - assembly_wizard
@JanDvorak:你在哪里看到三元计算机的?还是说你的问题只是理论上的? - Bhaskar
1
@JanDvorak :三进制系统的异或运算符定义(或真值表)是什么?我认为即使C和C++也不知道。如果设计了三进制计算机,那么就需要从头开始创建新的编程语言。 - Bhaskar
无符号数异或无符号数是否会得到负数? - Dee
显示剩余2条评论

38

操作的结果在其使用的位数上不会 "太大",因为该操作的定义是结合其操作数的位值,而不产生任何新位。也许一个更好的问题是,结果是否可能是除了有效的 int 值以外的其他值?

对于无符号整数,不可能。所有的位模式,因此所有按位操作的结果都是有效值表示。

对于有符号整数,这取决于负值的实现定义表示形式。你可能遇到的每一种实现都使用2的补码,其中每个位模式都是有效的;所以再次,任何按位操作的结果都将是有效的表示。

然而,标准还允许其他表示形式,其中可能存在一个或多个无效的位模式。在这种情况下,可能会使用两个有效操作数的按位操作生成该模式,从而产生一个无效的结果。


这个无效的结果会导致未定义的行为吗? - Ruslan
1
@Ruslan:对于C++,我会说是的;标准并没有明确说明哪些有符号值是有效的,以及在无效情况下会发生什么,因此行为似乎没有被定义。至于C语言,我就不好说了。 - Mike Seymour

28

(此帖适用于C语言,不适用于C++语言)

由于设置无效的填充位,按位运算符不会导致陷阱表示,参见C11 6.2.6.2/1注:

......对有效值进行的任何算术运算都不会生成陷阱表示......

(“算术运算”的含义不清楚,但索引链接到XOR的定义6.5.11)。

但是,在C语言中,它们可能会导致生成负零。在二进制补码中,没有负零。但是假设您使用的是一种补码方法,则可以通过^生成负零,这可能会导致陷阱表示。 6.2.6.2/3明确指出了这一点:

如果实现支持负零,则只能通过以下方式生成负零:

- &、|、^、~、<<和>>操作符与产生该值的操作数;

最后,6.2.6.2/2意味着(我非常确定)不可能有任何价值位组合,其表示超过INT_MAX


总之,两个int进行^运算的可能结果是:

  • 另一个有效的int值(可能具有与其他版本不同但不会陷入陷阱的填充位)
  • 负零,可能会导致陷阱

在C++中,就我所见,它并没有明确说明当生成负零时会发生什么。 - M.M
1
注意:C标准允许除符号位以外的所有位都为零,用于陷阱2的补数(即,INT_MIN可以是-INT_MAX,而INT_MAX ^ -1未定义)。虽然我知道存在非2的补数机器的例子,但我不知道是否存在这样的2的补数实现,也许它只是出现在标准中,因为通常对程序员来说并不是一个负担。 - mafso
2
@mafso:我相信一些补码实现将INT_MIN定义为-32767,以避免处理一些角落案例,例如printf、除法等。例如,在仅具有带符号右移操作的计算机上,当n为负数时,对n/4求值可能会计算为-(-n)>>2。如果n=-32767,那么结果为-8191,但如果n=-32768,则结果为8192。如果INT_MIN为-32767,则计算(-32768)/4将是未定义行为,因此使其产生8192将是完全合法的。 - supercat
2
此外,虽然我不知道有哪些硬件将-INT_MAX-1视为陷阱或NaN,但在某些情况下,NaN肯定会很有用(能够在计算的任何阶段之后测试是否发生了溢出可能比必须让代码检查和捕获每个阶段的溢出更有效,特别是在支持乱序执行的系统上)。我不确定这样的硬件是否能够解决先有鸡还是先有蛋的问题,但我不介意有这样的东西可用。 - supercat
1
你引用后面的话是“除非出现异常情况,例如溢出,否则不会发生这种情况,而无符号类型也不会发生。” - 在定义了这个值为陷阱表示的系统上,生成一个带有符号位为1和所有其他位为0的值(即在二进制补码系统中为-INT_MAX-1),可以被视为溢出。 - Random832
@Random832,“溢出”通常意味着值超出范围,而位运算不适用于值,尽管也许“溢出”可以描述您所建议的情况。也许我们需要另一个关于“溢出”确切含义的问题。 - M.M

21

严格来说,您不能对两个整数执行异或操作。 您可以对两个整数大小的位袋执行异或操作,并且您可以在其他时间将这些位袋视为整数。 甚至可以在所有其他时间将它们视为整数。

但在进行异或操作时,您正在将它们视为与整数或数值本身非常不同的东西:它们只是两个位序列,其中相应的位进行比较。 这个概念不适用于溢出,并且如果您随后决定将结果视为整数,则它也不能发生溢出。


5
我不太能支持这个评论:C标准直接说明可以对两个整数进行异或运算。 - M.M
C语言允许你使用按位异或运算符(在第6.5.12节中指定)执行类似于两个整数的XOR操作,但该操作仍将操作数视为一组位。一些“逻辑运算符”确实存在,它们对整数值进行操作(具体来说是AND、OR和NOT;C将它们呈现为&&、||和!)。但是,没有逻辑运算符用于XOR。 - The Spooniest
我可以将整数视为无限大的位袋,对它们进行异或运算,并始终得到有效的整数... 实际上,我也可以对任何二进制小数执行相同的操作。然而,非终止小数会导致0.9999...等问题。 - John Dvorak
@JanDvorak:如果您使用某种可变长度编码的整数,则可以执行此操作。您还可以执行分数或实际上任何其他东西的操作,只要您有某种将它们映射到位包和相反的方式即可。但是XOR操作仍将其视为位包,而不是可变长度的数字、分数或任何其他初始结构。 - The Spooniest
@TheSpooniest 我没有使用可变长度编码。我正在使用无限长度编码,其中对于整数有一种自然的编码方式。至于不使用二进制的定义,有一个叫做mex操作=最小排除值:f(x,y)是与每个f(x',y)(其中x'<y)和每个f(x,y')(其中y'<y)都不同的最小非负整数。结果证明它同构于XOR操作。 - John Dvorak
@JanDvorak:我猜你说的是像我们在现实生活中写整数那样,但除非你用无限数量的前导零写出每个整数,否则它不是无限长度:在正常使用中它是可变长度的。无论哪种方式,XOR操作仍将两个整数视为位包。您提到的mex运算符很有趣,但它并不适用于整数:它只能正确地处理Grundy数字。 - The Spooniest

11

XOR是否会生成无法存储在int类型中的大整数值?

如果操作数是int类型,则不会。

如果不可能发生这种情况,那么是否有证明?

从定义上来看很显然是不可能的。虽然这并不是一个严谨的数学证明,但你可以考虑这样一个事实:只有当运算数中的某一位为1时,XOR输出中的相应位才会为1。由于超出范围的位不能在操作数中为1,因此不存在值为1且超出范围的输出位。


只有当操作数为负时。怎么做? - Expert Novice
@ExpertNovice 因为(假设使用二进制补码),负数的最高位是 1,而正数的最高位是 0。如果两个操作数都是负数,则它们的最高位都是 11 XOR 1 等于 0。因此,两个负数异或的最高位是 0,即该整数为正数。正数大于负数。 - eerorika
我撤回只有负操作数会产生更大结果的说法。正数的异或运算结果也可能比操作数大。但是不会超过操作数位数的范围。我误解了这个含义。如果两个操作数都是负数,结果总是更大,但它们不是唯一导致更大结果的情况。我的错。 - eerorika
正确的是,1 ^ 45,比任何一个都大——但是最高位设置不会增加。而表示4的能力意味着也能够表示567(C99 6.2.6.2)。 - hobbs

11

XOR、AND、OR、NOT和其他位运算符产生的结果是按位进行的,结果中的位来自输入的完全相同位置处的位组合。因此,n位输入产生n位输出,不会有任何高位,那么如何超出范围呢?


5
C和C++不要求n个比特位的所有可能序列都代表有效值。在现代计算机上,通常会这样做,但某些奇怪的架构可能不会这样做。 - cHao
@cHao 只会出现在陷阱表示法中。在1或2的补码或符号-幅度中,所有位模式都是有效的。 - phuclv
@LưuVĩnhPhúc:我认为一个二进制补码机器可以合理地将INT_MIN定义为-INT_MAX,从而摆脱确保涉及-INT_MIN-1的算术行为合理的任何义务。 - supercat

10

不可以。与其他答案不同,我的回答将是数学证明。

XOR 是“异或”的缩写,可以定义为 exclusive orexclusive disjunction ():

A ⊕ B = (A ∪ B)\(A ∩ B)

您的建议是

∃x: x ∉ A ∧ x ∉ B ∧ x ∈ (AB)

因此,从第一个等式开始

x ∈ (A ∪ B)\(A ∩ B)

可以表达为什么

x ∈ (A ∪ B) ∧ x ∉ (A ∩ B)

第二部分可以表示为:
x ∉ A ∧ x ∉ B

第一部分可以表述为:
x ∈ A ∨ x ∈ B

我们的假设是 x ∉ A ∧ x ∉ B,因此命题对于任何集合 AB 都是错误的。

证毕。


7
在一般情况下,所描述的算法无法真正在数组中找到一个孤立的整数。它实际上找到的是所有出现奇数次数的元素的XOR。
因此,如果只有一个“孤立”的元素存在于其中,比如一个元素'a',并且所有其他元素在数组中都出现偶数次,那么它可以“按要求”工作——>它会找到这个孤立的元素'a'。
为什么呢?
该算法执行了数组中所有元素的XOR (a ^ b ^ c ^ d ^ ...)。
XOR操作具有以下特性:
1) a ^ a = 0 (非等价)
2) a ^ 0 = a (零的中性)
3) a ^ b = b ^ a (交换律)
4) (a ^ b) ^ c = a ^ (b ^ c) (结合律)
例如,假设一个包含元素 {a,b,c,a,c,b,a,c} 的数组。
(元素'a'出现3次,元素'b'出现2次,元素'c'出现3次)
然后,根据上述XOR属性,算法结果
R = (((((((a ^ b) ^ c) ^ a) ^ c) ^ b) ^ a) ^ c)
可以重新排列如下:
R = (a ^ b) ^ (c ^ a) ^ (c ^ b) ^ (a ^ c) =
= (a ^ a) ^ (b ^ b) ^ (c ^ c) ^ (a ^ c) =
= 0 ^ 0 ^ 0 ^ (a ^ c) = (a ^ c)
即,
a) ...所有出现偶数次的元素都会得到零
b) ...所有出现奇数次的元素都会进行XOR并创建最终结果
XOR是一种按位操作,因此它永远不会溢出,当然。

3
假定:
int xor  = x^y;
Max value of int is x = 999999999;
Max value of Xor will come if y=0;
and Max Xor is 999999999;

这在技术上是有限制的。:)


使用反引号来表示内联代码。例如,**int的最大值为x = 999999999;** 变成 **int的最大值为x = 999999999;**。 - Pluto
5
这并不能证明什么。 - indiv
2
999,999,999 xor 73,741,824 等于 1,073,741,823。但是,int 的最大值不太可能是 999,999,999。 - Random832

2

XOR是否可能生成一个过大的整数值,无法存储在int类型中?

Data-Type3 = Data-Type1 operator Data-Type2

如果这不可能发生,那么是否有证明呢?

在整数的情况下,我们有 Data-Type3,它是 Data-Type1Data-Type2 中具有更大大小的一个,即使在加法或乘法的情况下也是如此。

SIZE(Data-Type3) = MAX(SIZE(Data-Type1), SIZE(Data-Type2))

因此,如果 Data-Type1 = Data-Type2,则返回类型也是这两种数据类型。

Short + Short   = Short
Short + Integer = Integer
Short + Long    = Long

Integer + Short   = Integer
Integer + Integer = Integer
Integer + Long    = Long

Long + Short   = Long
Long + Integer = Long
Long + Long    = Long

可能会发生的情况是溢出,当操作有进位时会发生。在二进制补码中,当高位列的进位不等于高位列的进位时,就会发生溢出。查看更多 但是XOR操作不会溢出,因为XOR操作不产生进位,因为XOR是按位操作,就像NOT一样。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接