节点 - 使用IP地址的按位计算

时间:2014-06-18 23:33:45

标签: javascript node.js bit-manipulation

我在Node中创建了一个DNS工具,我想知道如何使用bitwise优化toLong()的性能?我已经包含了一些伪代码供参考。

var _parser = function (ip) {
  return ip.split('.').map(function (i) {
    return i | 0;
  });
},

_isIPv4 = function (ip) {
  var i, isValid = true, octets = _parser(ip);

  if (octets.length !== 4) {
    isValid = false;
  }
  octets.forEach(function (octet) {
    if (octet < 0 || octet > 255) {
      isValid = false;
    }
  });
  return isValid;
};

toLong: function (ip) {
  var i, converted, octets = _parser(ip);

  if (!_isIPv4(ip)) {
    throw 'Invalid IPv4 address!';
  }
  converted = 0;
  for (i = 0; i < octets.length; i++) {
    converted += octets[i] * Math.pow(256, (3 - i));
  }
  return converted;
};

3 个答案:

答案 0 :(得分:1)

在这里:http://jsperf.com/node-bitwise-calculations-with-ip-addresses

编辑2:这是最初的解决方案,大约是2倍的性能:

var p256 = [Math.pow(256, 3), Math.pow(256, 2), 256, 1];
var cache = {};

var newToLongCache = function(ip) {
  var octets = _parser(ip);
  var converted = 0;
  for (var i = 0; i < octets.length; i++) {
    var val = octets[i];
    if (cache[val] == null) {
      cache[val] = {};
    }
    if (cache[val][i] == null) {
      cache[val][i] = val * p256[i];
    }
    converted += cache[val][i];
  }
  return converted;
};

这是更新的展开解决方案,没有按位运算符(相同的5倍性能):

 var unrolledMultiplicationLongNoBitwise = function(ip) {
      var octets = ip.split('.');
      if (octets.length !== 4) throw "Invalid IPv4 address!";

      octets[0] = octets[0] | 0;
      octets[1] = octets[1] | 0;
      octets[2] = octets[2] | 0;
      octets[3] = octets[3] | 0;

      if ((octets[0] < 0 || octets[0] > 255) ||
        (octets[1] < 0 || octets[1] > 255) ||
        (octets[2] < 0 || octets[2] > 255) ||
        (octets[3] < 0 || octets[3] > 255)) {
        throw 'Invalid IPv4 address!';
      }

      return (octets[0] * 16777216) + (octets[1] * 65536) +
      (octets[2] * 256) + octets[3];
    };

答案 1 :(得分:1)

我真的建议展开这些循环并放弃函数调用。我在@imsky创建的jsPerf中添加了一个修订版:http://jsperf.com/node-bitwise-calculations-with-ip-addresses/6看起来这比原版快〜5倍。

var unrolledLong = function(ip) {
  var octets = ip.split('.');
  if (octets.length !== 4) throw "Invalid IPv4 address!";

  octets[0] = octets[0] | 0;
  octets[1] = octets[1] | 0;
  octets[2] = octets[2] | 0;
  octets[3] = octets[3] | 0;

  if ((octets[0] < 0 || octets[0] > 255) ||
      (octets[1] < 0 || octets[1] > 255) ||
      (octets[2] < 0 || octets[2] > 255) ||
      (octets[3] < 0 || octets[3] > 255)) {
    throw 'Invalid IPv4 address!';
  }
  // The >>> 0 calls will force the number back to an unsigned value.
  return octets[3] +
    ((octets[2] << 8) >>> 0) +
    ((octets[1] << 16) >>> 0) +
    ((octets[0] << 24) >>> 0);
};

如果按位数学有点奇怪,你也可以使用乘法:

var unrolledLong = function(ip) {
  var octets = ip.split('.');
  if (octets.length !== 4) throw "Invalid IPv4 address!";

  octets[0] = octets[0] | 0;
  octets[1] = octets[1] | 0;
  octets[2] = octets[2] | 0;
  octets[3] = octets[3] | 0;

  if ((octets[0] < 0 || octets[0] > 255) ||
      (octets[1] < 0 || octets[1] > 255) ||
      (octets[2] < 0 || octets[2] > 255) ||
      (octets[3] < 0 || octets[3] > 255)) {
    throw 'Invalid IPv4 address!';
  }
  // The >>> 0 calls will force the number back to an unsigned value.
  return octets[3] +
    (octets[2] * 0x100) +
    (octets[1] * 0x10000) +
    (octets[0] * 0x1000000);
};

答案 2 :(得分:1)

只是玩弄优化:

function( ip ){
  var octets = ip.split( '.' );

  if( ( octets.length !== 4 )        ||
      ( ( octets[0] |= 0 ) & ~0xFF ) ||
      ( ( octets[1] |= 0 ) & ~0xFF ) ||
      ( ( octets[2] |= 0 ) & ~0xFF ) ||
      ( ( octets[3] |= 0 ) & ~0xFF ) ){
    throw new Error( 'Invalid IPv4 address!' );
  }

  return ( octets[3]       ) |
         ( octets[2] << 8  ) |
         ( octets[1] << 16 ) |
         ( octets[0] * 0x1000000 );
}