Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/453.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 为什么按位“;不是1“;等于-2?_Javascript_Numbers_Bitwise Operators - Fatal编程技术网

Javascript 为什么按位“;不是1“;等于-2?

Javascript 为什么按位“;不是1“;等于-2?,javascript,numbers,bitwise-operators,Javascript,Numbers,Bitwise Operators,假设我们有1,基数2中的这个数字是: 00000000000000000000000000000001 现在我想翻转所有位以得到以下结果: 11111111111111111111111111111110 据我所知,解决方案是使用~(按位非运算符)翻转所有位,但~1的结果是-2: console.log(~1); //-2 console.log((~1).toString(2)); //-10 (binary representation) 为什么我会得到这个奇怪的结果?在1和-2之间有

假设我们有
1
,基数2中的这个数字是:

00000000000000000000000000000001
现在我想翻转所有位以得到以下结果:

11111111111111111111111111111110
据我所知,解决方案是使用
~
(按位非运算符)翻转所有位,但
~1
的结果是
-2

console.log(~1); //-2
console.log((~1).toString(2)); //-10 (binary representation)

为什么我会得到这个奇怪的结果?

1
-2
之间有两个整数:
0
-1

二进制的
1
00000000000000000000000000000001

二进制的
0
00000000000000000000


二进制中的
-1
11111111111111111


二进制中的
-2
1111111111111111111 0

(“二进制”是2的补码,在按位非
~
的情况下)

正如您所看到的,这并不奇怪
~1
等于
-2
,因为
~0
等于
-1

它们将操作数视为32位序列<另一方面,code>parseInt。这就是为什么你会得到一些不同的结果


下面是一个更完整的演示:

用于(变量i=5;i>=-5;i--){
log('Decimal:'+pad(i,3,')+'| Binary:'+bin(i));
如果(i==0)
console.log('Decimal:-0 | Binary:'+bin(-0));//没有`-0`
}
功能板(数字、长度、字符){
var out=num.toString();
while(out.length>>0).toString(2),32,'0');
}

.as控制台包装{max height:100%!important;top:0;}
2的补码32位带符号整数(Javascript坚持使用32位带符号整数的格式)将-2存储为
1111111111 0


所以一切都如预期的那样。

这是预期的行为。根据

你可能不明白的是
[1111111111111111111111 0]₂ = [10]₂1。前导的
1
s可以是您想要的任意数量,并且它仍然是相同的数字,类似于无符号整数/十进制中的前导的
0
s

\<代码>[10]₂指定应将
10
解释为基数2(二进制)

记住2的补码表示法工作原理的一个简单方法是想象它只是一个普通的二进制,除了它的最后一位对应于相同的被求反的值。在我设计的三位二的补码中,第一位是
1
,第二位是
2
,第三位是
-4
(注意减号)

如您所见,按位不在2的补码中是
-(n+1)
。令人惊讶的是,将其应用于一个数字两次会得到相同的数字:

-(-(n + 1) + 1) = (n + 1) - 1 = n
按位说话时,这一点很明显,但在算术效果方面就不那么明显了

还有几项观察结果让我们更容易记住它的工作原理:

注意负值是如何上升的。完全相同的规则,只交换了0和1。按位NOTted,如果您愿意的话

100 -4  011 - I bitwise NOTted this half
101 -3  010
110 -2  001
111 -1  000
----------- - Note the symmetry of the last column
000  0  000
001  1  001
010  2  010
011  3  011 - This one's left as-is
通过将二进制文件列表按其中总数字的一半循环,可以得到从零开始的典型升序二进制数序列

-  100 -4  \
-  101 -3  |
-  110 -2  |-\  - these are in effect in signed types
-  111 -1  / |
*************|
   000  0    |
   001  1    |
   010  2    |
   011  3    |
*************|
+  100  4  \ |
+  101  5  |-/  - these are in effect in unsigned types
+  110  6  |
+  111  7  /

在计算机科学中,一切都是关于解释的。对于计算机来说,一切都是一个可以用多种方式解释的位序列。例如,
0100001
可以是数字33或
(这就是映射此位序列的方式)

对于计算机来说,任何东西都是一个位序列,无论您将其视为数字、数字、字母、文本、Word文档、屏幕上的像素、显示的图像或硬盘上的JPG文件。如果您知道如何解释该位序列,它可能会变成对人类有意义的东西,但在RAM和CPU中只有位

所以,当你想在计算机中存储一个数字时,你必须对它进行编码。对于非负数,它非常简单,只需使用二进制表示。但是负数呢

您可以使用一种称为二的补码的编码。在这种编码中,您必须决定每个数字将有多少位(例如8位)。将保留为符号位。如果是
0
,则该数字应解释为非负数,否则为负数。其他7位包含实际数字

00000000
表示零,就像无符号数字一样
00000001
是一,
00000010
是二,依此类推。在2的补码的8位上可以存储的最大正数是127(
01111111

下一个二进制数(
10000000
)是-128。这可能看起来很奇怪,但我马上会解释为什么它有意义<代码>10000001
为-127,
1000010
为-126,依此类推<代码>11111
为-1

为什么我们要使用这种奇怪的编码?因为它有趣的特性。具体地说,当执行加减运算时,CPU不必知道它是一个作为2的补码存储的有符号数。它可以将两个数字解释为无符号,将它们相加,结果将是正确的

让我们试试这个:-5+5-5是
11111011
5
00000101

  11111011
+ 00000101
----------
 000000000
  00010111
+ 11111001
----------
 100010000
结果是9位长。最高有效位溢出,剩下的
00000000
为0。它似乎起作用了

另一个例子:23+-7。23是
00010111
,-7是
11111001

  11111011
+ 00000101
----------
 000000000
  00010111
+ 11111001
----------
 100010000
同样,MSB丢失,我们得到
00010000
==16。它起作用了

这就是二的补码的工作原理。计算机在内部使用它来存储有符号整数

您可能已经注意到,在2的补码中,当您对数字的位进行求反时,它会变成
-N-1
。示例:

  • 0被否定==
    ~00000000
    =
    11111111
    =-1
  • 1否定==
    ~00000001
    =