负与有符号整数如何按位与或和异或运算?

时间:2018-12-27 19:41:35

标签: javascript bit-manipulation bitwise-operators bitwise-and

我只是解决bitwise operators上的随机问题,并尝试各种其他组合来制作个人笔记。而且以某种方式我无法找出解决方案。

说我想检查两个整数之间或在〜number和-negative number(〜num1&-num2)和其他各种组合上的按位与运算。然后我可以看到答案,但是我无法确定这是怎么发生的?

控制台:

  

console.log(25&3);输出1(我可以轻松解决此问题)。

     

console.log(-25和-3);输出27。

类似地

  

console.log(〜25&〜3);输出-28。

     

console.log(25&〜3);输出-24。

     

console.log(〜25&3);输出-2。

     

console.log(〜25&-3);输出--28。

     

console.log(-25&〜3);输出--28。

我知道“ console.log(25&-3)” 背后的逻辑。

  

25是11001
  -3是11101(3 = 00011负号像2s恭维+1)
  AND-11001 =25。

但是当两个数字均为负数或与上述其他情况一起使用时,我无法以相同的方式工作。我也尝试过各种数字组合,而不仅仅是这两个。但是我不能解决问题。有人可以解释我无法解决的问题中使用的二进制逻辑。

(我在SO上花了大约2个小时在这里找到答案,而在Google上又花了1个小时以上,但我仍然没有找到答案)。

感谢和问候。

4 个答案:

答案 0 :(得分:1)

-27中有6个二进制数字,因此您应该使用至少具有这么多数字的数字。使用8位数字,我们可以:

  • 00011001 = 25
  • 00000011 = 3
  • 00011011 = 27

和:

  • 11100111 = -25
  • 11111101 = -3
  • 11100101 = -27

现在-25&-3 = -27,因为11100111&11111101 = 11100101

答案 1 :(得分:1)

JavaScript指定对整数执行按位运算,就像它们存储在二进制补码中一样。幸运的是,如今大多数计算机硬件仍然会自然使用此表示法。

为简便起见,我将以下数字显示为8位二进制数。它们实际上是JavaScript中的32位,但是对于原始问题中的数字,这不会改变结果。但是,它的确让我们丢了很多领先的东西。

console.log(-25 & -3); //outputs -27. How?

如果我们用二进制写整数,则分别得到(11100111&11111101)。与这些加在一起,您将得到11100101,即-27。

在后面的示例中,您似乎交替使用了NOT运算符(〜)和否定符(-)。您不能用二进制补码来做到这一点:〜和-不是同一件事。 〜25是11100110,它是-26,而不是-25。同样,〜3是11111100,它是-4,而不是-3。

但是,当我们将它们放在一起时,我们可以得出您给出的示例。

console.log(~25 & ~3); //outputs-28. How?

11100110&11111100 = 11100100,它是-28(而不是您所写的28)

console.log(25 & ~3);//outputs-24. How?

00011001&11111100 = 00011000,即24

console.log(~25 & 3);//outputs-2. How?

11100110&00000011 = 00000001,即2

console.log(~25 & -3);//outputs--28. How?

11100110&11111101 = 11100100,即-28

console.log(-25 & ~3);//outputs--28. How?

11100111&11111100 = 11100100,即-28

了解这一点的真正关键是您实际上并未对整数使用按位运算。您将它们用在一定大小的钻头袋上,这些钻头袋恰好可以方便地表示为整数。这是了解此处发生情况的关键,因为您偶然发现了差异很重要的情况。

在计算机科学中,有一些特殊的情况,您可以通过巧合的方式来处理比特袋,结果与您对数字进行特定的数学运算一样。但这仅在特定情况下有效,并且它们要求您对正在处理的数字进行某些假设,并且如果您的数字 不符合这些假设,则情况会崩溃。

这是唐纳德·克努斯(Donald Knuth)说“过早的优化是万恶之源”的原因之一。如果要使用位运算代替实际的整数数学,则必须绝对确定输入将实际遵循该技巧所需的假设。否则,当您开始使用这些假设之外的输入时,结果将看起来很奇怪。

答案 2 :(得分:1)

25 = 16+8+1 = 0b011001,我添加了另一个0数字作为符号数字。实际上,您将至少有8位二进制数字 但两者的补码数学是相同的。要在6位二进制补码中获得-25,请执行-25 = ~25 + 1=0b100111 3=2+1=0b000011; -3 = ~3+1 = 0b111101

&两者同时出现,您得到:

-25 = ~25 + 1=0b100111
&
-3 = ~3 + 1 = 0b111101
              0b100101

最左边的位(符号位)被设置为负数。要找出负面结果,您可以颠倒该过程,先减去1,然后执行~

~(0b100101-1) = 0b011011

那是1+2+0*4+8+16 = 27,所以-25&-3=-27

对于25&〜3,是:

25 = 16+8+1 = 0b011001
&        ~3 = 0b111100
______________________
              0b011000 = 24

对于25和3,它是:

~25 =         0b100110
&        ~3 = 0b000011
______________________
              0b000010 = 2

对于〜25&-3,是:

~25 =         0b100110
&      ~3+1 = 0b111101
______________________
               0b100100 #negative

#find what it's a negative of:
~(0b100100-1) =~0b100011 = 0b011100 = 4+8+16 = 28
               0b100100 = -28

答案 3 :(得分:1)

32位整数的二进制字符串表示形式可以找到:

(i >>> 0).toString(2).padStart(32, '0')

两个二进制字符串的按位与运算很简单

带符号的32位二进制字符串的整数值是

parseInt(bitwiseAndString, 2)

如果字符串以“ 0”开头,或者

-~parseInt(bitwiseAndString, 2) - 1

如果以“ 1”开头

将所有内容放在一起:

const tests = [
  ['-25', '-3'],
  ['~25', '-3'],
  ['25', '~3'],
  ['~25', '3'],
  ['~25', '~3'],
  ['-25', '~3']
]

const output = (s,t) => { console.log(`${`${s}:`.padEnd(20, ' ')}${t}`); }

const bitwiseAnd = (i, j) => {
  console.log(`Calculating ${i} & ${j}`);
  const bitStringI = (eval(i) >>> 0).toString(2).padStart(32, '0');
  const bitStringJ = (eval(j) >>> 0).toString(2).padStart(32, '0');
  output(`bit string for ${i}`, bitStringI);
  output(`bit string for ${j}`, bitStringJ);
  const bitArrayI = bitStringI.split('');
  const bitArrayJ = bitStringJ.split('');
  const bitwiseAndString = bitArrayI.map((s, idx) => s === '1' && bitArrayJ[idx] === '1' ? '1' : '0').join('');
  output('bitwise and string', bitwiseAndString);
  const intValue = bitwiseAndString[0] === '1' ? -~parseInt(bitwiseAndString, 2) - 1 : parseInt(bitwiseAndString, 2);
  if (intValue === (eval(i) & eval(j))) {
    console.log(`integer value: ${intValue} ✓`);
  } else {
    console.error(`calculation failed: ${intValue} !== ${i & j}`);
  }
}

tests.forEach(([i, j]) => { bitwiseAnd(i, j); })