为什么~2等于-3?~操作符是如何工作的?


当前回答

Tl;dr ~翻转比特。结果符号就改变了。~2是负数(0b..101)。要输出一个负数红宝石打印-,则2的~2的补:-(~~2 + 1)== -(2 + 1)== 3。正数按原样输出。

有一个内部值,和它的字符串表示。对于正整数,它们基本重合:

irb(main):001:0> '%i' % 2
=> "2"
irb(main):002:0> 2
=> 2

后者相当于:

irb(main):003:0> 2.to_s
"2"

~翻转内部值的位。2 = 0b010。~2是0b..101。两个点(..)代表无限个1。由于结果的最高有效位(MSB)为1,因此结果为负数((~2)。= = true)。要输出一个负数的红宝石印-,则是二的内部补值。2的补位是通过翻转位,然后加1来计算的。0b的2的补。101等于3。是这样的:

irb(main):005:0> '%b' % 2
=> "10"
irb(main):006:0> '%b' % ~2
=> "..101"
irb(main):007:0> ~2
=> -3

总的来说,它翻转了位,从而改变了符号。为了输出一个负数,它输出-,然后~~2 + 1(~~2 == 2)。

ruby像这样输出负数的原因是,它将存储的值视为绝对值的2的补。换句话说,存储的是0b..101。它是一个负数,因此它是x的2的补,为了找到x,它是2的补0b..101。它是2的x的补,也就是x(例如~(~2 + 1)+ 1 == 2)。

如果你将~应用于一个负数,它只是翻转位(尽管如此,这改变了符号):

irb(main):008:0> '%b' % -3
=> "..101"
irb(main):009:0> '%b' % ~-3
=> "10"
irb(main):010:0> ~-3
=> 2

更令人困惑的是~0xffffff00 != 0xff(或MSB等于1的任何其他值)。让我们稍微简化一下:~0xf0 != 0x0f。这是因为它将0xf0视为正数。这是有道理的。因此,~0xf0 == 0x..f0f。结果是一个负数。0x的2的补。F0f是0xf1。所以:

irb(main):011:0> '%x' % ~0xf0
=> "..f0f"
irb(main):012:0> (~0xf0).to_s(16)
=> "-f1"

如果你不打算对结果应用位操作符,你可以考虑~作为-x - 1操作符:

irb(main):018:0> -2 - 1
=> -3
irb(main):019:0> --3 - 1
=> 2

但可以说,这并没有多大用处。

举个例子,假设你有一个8位的网络掩码(为了简单起见),你想计算0的个数。您可以通过翻转位并调用bit_length (0x0f. bit_length)来计算它们。bit_length == 4). But ~0xf0 == 0x..F0f,所以我们要去掉不需要的部分

irb(main):014:0> '%x' % (~0xf0 & 0xff)
=> "f"
irb(main):015:0> (~0xf0 & 0xff).bit_length
=> 4

或者你可以使用XOR运算符(^):

irb(main):016:0> i = 0xf0
irb(main):017:0> '%x' % i ^ ((1 << i.bit_length) - 1)
=> "f"

其他回答

很简单:

Before starting please remember that 
 1  Positive numbers are represented directly into the memory.
 2. Whereas, negative numbers are stored in the form of 2's compliment.
 3. If MSB(Most Significant bit) is 1 then the number is negative otherwise number is 
    positive.

你会发现~2:

Step:1 Represent 2 in a binary format 
       We will get, 0000 0010
Step:2 Now we have to find ~2(means 1's compliment of 2)
                  1's compliment       
       0000 0010 =================> 1111 1101 

       So, ~2 === 1111 1101, Here MSB(Most significant Bit) is 1(means negative value). So, 
       In memory it will be represented as 2's compliment(To find 2's compliment first we 
       have to find 1's compliment and then add 1 to it.)
Step3:  Finding 2's compliment of ~2 i.e 1111 1101

                   1's compliment                   Adding 1 to it
        1111 1101 =====================> 0000 0010 =================> 0000 0010
                                                                      +       1
                                                                      ---------
                                                                      0000 0011 
        So, 2's compliment of 1111 1101, is 0000 0011 

Step4:  Converting back to decimal format.
                   binary format
        0000 0011 ==============> 3
        
       In step2: we have seen that the number is negative number so the final answer would  
       be -3
                                    
                                So, ~2 === -3

正如其他人所提到的~只是翻转位(将1变为0,将0变为1),由于使用了2的补码,您就得到了您所看到的结果。

需要补充的一点是为什么使用2的补数,这是为了对负数的运算和对正数的运算是一样的。把-3看成是要加3才能得到0的数字,你会看到这个数字是1101,记住二进制加法就像小学(十进制)加法,只是你得到2时进1,而不是10。

 1101 +
 0011 // 3
    =
10000
    =
 0000 // lose carry bit because integers have a constant number of bits.

因此1101是-3,翻转位就得到0010,也就是2。

位操作符是一个一元操作符,根据我的经验和知识,它的工作原理是符号和幅度方法。

例如~2的结果是-3。

这是因为逐位操作符将首先以符号和幅度表示数字,即0000 0010(8位操作符),其中MSB是符号位。

然后取2的负数,也就是-2。

-2用符号和幅度表示为1000 0010(8位运算符)。

之后,它将1添加到LSB(1000 0010 + 1),得到1000 0011。

也就是-3。

下面是一种解释:

让我们以~2 = -3为例(为了简单起见,使用8位系统进行解释)

1)我们有2——> 00000010

2)我们可以得到~2—> 11111101 #通过简单地交换位。

[但常见的错误是,有些人试图将~2的二进制值直接转换为十进制(以10为基数)数字,在这种情况下,它是253。这不是我们寻找互补的方式。

3)现在我们找到一个二进制数,将其与二进制值2~相加得到0(00000000)作为结果。 在这种情况下,它是00000011(即3),因为如果我们将00000011加到我们已有的11111101,我们得到100000000,但由于我们使用的是8位系统,1在第9位,它被完全忽略,所以我们最终得到00000000。

4)从点(3)我们可以说~2+3 = 0,因此我们可以说~2 = -3

注意:-3的值是简单的11111101,可以用同样的方式解释。

我知道这个问题的答案很久以前就贴出来了,但我想分享我的答案。

要找到一个数的一补,首先要找到它的二进制等价物。这里,十进制数字2用二进制形式表示为0000 0010。现在通过将其二进制表示的所有数字逆(将所有1都翻转为0,将所有0都翻转为1)来求其1的补数,这将得到:

0000 0010 → 1111 1101

这是十进制数2的1补。由于二进制数的第一个位,即符号位为1,这意味着它存储的数字的符号为负。(这里所指的数字不是2,而是2的1的补数)。

现在,由于数字存储为2的补数(取1的补数加1),所以要将这个二进制数1111 1101显示为十进制,首先我们需要找到它的2的补数,即:

1111 1101 → 0000 0010 + 1 → 0000 0011

这是2的补。二进制数0000 0011的十进制表示是3。并且,因为符号位是1,所以结果是-3。

提示:如果你仔细阅读这个过程,你会发现1的补码操作符的结果实际上是,数字(操作数-,这个操作符被应用)加1,带一个负号。你也可以用其他数字试试。