简体   繁体   English

如何在JavaScript中添加位

[英]How to add bits in JavaScript

Say you have two integers 10 and 20. That is 00001010 and 00010100 . 假设您有两个整数10和20。即0000101000010100 I would then like to just basically concat these as strings, but have the result be a new integer. 然后,我想将它们基本连接为字符串,但结果是一个新的整数。

00001010 + 00010100 == 0000101000010100

That final number is 2580 . 最后的数字是2580

However, I am looking for a way to do this without actually converting them to string. 但是,我正在寻找一种无需实际将其转换为字符串的方法。 Looking for something more efficient that just does some bit twiddling on the integers themselves. 寻找更有效的方法来对整数本身进行一些调整。 I'm not too familiar with that, but I imagine it would be along the lines of: 我对此不太熟悉,但我想它会遵循以下原则:

var a = 00001010 // == 10
var b = 00010100 // == 20
var c = a << b //   == 2580

Note, I would like for this to work with any sequences of bits. 注意,我希望它可以处理任何位序列。 So even: 因此,即使:

var a = 010101
var b = 01110
var c = a + b == 01010101110

You basic equation is: 您的基本公式是:

c = b + (a << 8).

The trick here is that you need to always shift by 8. But since a and b do not always use all 8 bits in the byte, JavaScript will automatically omit any leading zeros. 这里的窍门是您需要始终移位8。但是由于ab并不总是使用字节中的所有8位,因此JavaScript会自动忽略任何前导零。 We need to recover the number of leading zeros (of b ), or trailing zeros of a , and prepend them back before adding. 我们需要恢复前导零(的数量b ),或尾随零a ,并添加之前在前面加上他们回来。 This way, all the bits stay in their proper position. 这样,所有位都保持在正确的位置。 This requires an equation like this: 这需要一个这样的方程式:

c = b + (a << s + r)

Where s is the highest set bit (going from right to left) in b , and r is the remaining number of bits such that s + r = 8 . 其中s是最高设置位在(从右到左去) b ,和r是比特的剩余数,使得s + r = 8

Essentially, all you are doing is shifting the first operand a over by 8 bits, to effectively add trailing zeros to a or equally speaking, padding leading zeros to the second operand b . 本质上,您要做的就是将第一个操作数a移8位,以有效地将尾随零添加到a或相等地说,将前导零填充到第二个操作数b Then you add normally. 然后,您正常添加。 This can be accomplishing using logarithms, and shifting, and bitwise OR operation to provide an O(1) solution for some arbitrary positive integers a and b where the number of bits in a and b do not exceed some positive integer n . 这可以使用对数来完成,并移位和逐位OR操作以提供O(1)对于某个任意的正整数ab ,其中位的数目ab不超过一些正整数n In the case of a byte, n = 8 . 在字节的情况下, n = 8

// Bitwise log base 2 in O(1) time
function log2(n) {

  // Check if n > 0

  let bits = 0;

  if (n > 0xffff) {
      n >>= 16;
      bits = 0x10;
  }

  if (n > 0xff) {
      n >>= 8;
      bits |= 0x8;
  }

  if (n > 0xf) {
      n >>= 4;
      bits |= 0x4;
  }

  if (n > 0x3) {
      n >>= 2;
      bits |= 0x2;
  }

  if (n > 0x1) {
      bits |= 0x1;
  }

  return bits;
}

// Computes the max set bit
// counting from the right to left starting
// at 0. For 20 (10100) we get bit # 4.
function msb(n) {

  n |= n >> 1;
  n |= n >> 2;
  n |= n >> 4;
  n |= n >> 8;
  n |= n >> 16;

  n = n + 1;

  // We take the log here because
  // n would otherwise be the largest
  // magnitude of base 2. So, for 20,
  // n+1 would be 16. Which, to 
  // find the number of bits to shift, we must 
  // take the log base 2
  return log2(n >> 1);
}

// Operands
let a = 0b00001010  // 10
let b = 0b00010100  // 20

// Max number of bits in
// in binary number
let n = 8

// Max set bit is the 16 bit, which is in position
// 4. We will need to pad 4 more zeros
let s = msb(b) 

// How many zeros to pad on the left
// 8 - 4 = 4
let r = Math.abs(n - s)

// Shift a over by the computed 
// number of bits including padded zeros
let c = b + (a << s + r)

console.log(c)

Output: 输出:

2580

Notes: 笔记:

  • This is NOT commutative. 这不是可交换的。
  • Add error checking to log2() for negative numbers, and other edge cases. 将错误检查添加到log2()中是否存在负数和其他边缘情况。

References: 参考文献:

so the problem: 所以问题是:
a is 10 (in binary 0000 1010) a是10(二进制0000 1010)
b is 20 (in binary 0100 0100) b为20(二进制0100 0100)
you want to get 2580 using bit shift somehow. 您想以某种方式获得2580的位移。

if you right shift a by 8 using a<<=8 (this is the same as multiplying a by 2^8) you get 如果您使用a << = 8将a右移8(这与将a乘2 ^ 8相同),则会得到
1010 0000 0000 which is the same as 10*2^8 = 2560. 1010 0000 0000与10 * 2 ^ 8 = 2560相同。
since the lower bits of a are all 0's (when you use << it fills the new bits with 0) you can just add b on top of it 1010 0000 0000 + 0100 0100 gives you 1010 0001 0100. 由于a的低位全为0(当您使用<<时,它用0填充新位),您可以在其顶部加上b 1010 0000 0000 + 0100 0100,得到1010 0001 0100。

so in 1 line of code, it's var result = a<<8 + b . 所以在1行代码中,它是var result = a<<8 + b

Remember in programming languages, most of them have no explicit built-in types for "binary". 请记住,在编程语言中,大多数语言都没有针对“二进制”的显式内置类型。 But everything is binary in its nature. 但是一切本质都是二进制的。 so int is a "binary", an object is "binary" ....etc. 所以int是一个“二进制”,一个对象是“二进制” ..etc。 When you want to do some binary operations on some data you can just use the datatype you have as operands for binary operations. 当您要对某些数据执行一些二进制操作时,可以仅使用具有二进制操作数的数据类型。

this is a more general version of how to concatenate two numbers' binary representations using no string operations and data 这是一个更通用的版本,说明如何在不使用字符串操作和数据的情况下连接两个数字的二进制表示形式

 /* This function concate b to the end of a and put 0's in between them. b will be treated starting with it's first 1 as its most significant bit b needs to be bigger than 0, otherwise, Math.log2 will give -Infinity for 0 and NaN for negative b padding is the number of 0's to add at the end of a */ function concate_bits(a, b, padding) { //add the padding 0's to a a <<= padding; //this gets the largest power of 2 var power_of_2 = Math.floor(Math.log2(b)); var power_of_2_value; while (power_of_2 >= 0) { power_of_2_value = 2 ** power_of_2; a <<= 1; if (b >= power_of_2_value) { a += 1; b -= power_of_2_value; } power_of_2--; } return a; } //this will print 2580 as the result let result = concate_bits(10, 20, 3); console.log(result); 

Note, I would like for this to work with any sequences of bits. 注意,我希望它可以处理任何位序列。 So even: 因此,即使:

var a = 010101
var b = 01110
var c = a + b == 01010101110

This isn't going to be possible unless you convert to a string or otherwise store the number of bits in each number. 除非您转换为字符串或以其他方式在每个数字中存储位数,否则这是不可能的。 10101 010101 0010101 etc are all the same number (21), and once this is converted to a number, there is no way to tell how many leading zeroes the number originally had. 10101 010101 0010101等都是相同的数字(21),一旦将其转换为数字,就无法判断该数字最初有多少个前导零。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM