Javascript 具有IP地址的节点位计算

Javascript 具有IP地址的节点位计算,javascript,node.js,bit-manipulation,Javascript,Node.js,Bit Manipulation,我在Node中制作了一个DNS工具,我想知道如何使用按位优化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

我在Node中制作了一个DNS工具,我想知道如何使用按位优化
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;
};
var\u解析器=函数(ip){
返回ip.split('.').map(函数(i){
返回i | 0;
});
},
_isIPv4=功能(ip){
变量i,isValid=true,八位字节=_解析器(ip);
如果(八位字节长度!==4){
isValid=false;
}
八位字节。forEach(函数(八位字节){
如果(八位组<0 | |八位组>255){
isValid=false;
}
});
返回有效;
};
托龙:功能(ip){
变量i,已转换,八位字节=_解析器(ip);
如果(!\u isIPv4(ip)){
抛出“无效IPv4地址!”;
}
换算为0;
对于(i=0;i
给你:

编辑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;
};
 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];
    };
var p256=[Math.pow(256,3),Math.pow(256,2),256,1];
var cache={};
var newToLongCache=函数(ip){
变量八位字节=_解析器(ip);
var=0;
对于(变量i=0;i
这是更新的展开解决方案,没有按位运算符(相同的5x性能):

var unrolled multiplicationLongNobitWise=函数(ip){
var八位字节=ip.split('.');
如果(octets.length!==4)抛出“无效IPv4地址!”;
八位位组[0]=八位位组[0]| 0;
八位位组[1]=八位位组[1]| 0;
八位位组[2]=八位位组[2]| 0;
八位位组[3]=八位位组[3]| 0;
if((八位字节[0]<0 | |八位字节[0]>255)||
(八位字节[1]<0 | |八位字节[1]>255)||
(八位字节[2]<0 | |八位字节[2]>255)||
(八位字节[3]<0 | |八位字节[3]>255)){
抛出“无效IPv4地址!”;
}
返回(八位字节[0]*16777216)+(八位字节[1]*65536)+
(八位组[2]*256)+八位组[3];
};

我真的建议展开这些循环并放弃函数调用。我在@imsky:创建的jsPerf中添加了一个修订版,看起来比原来快了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 unrolled long=函数(ip){
var八位字节=ip.split('.');
如果(octets.length!==4)抛出“无效IPv4地址!”;
八位位组[0]=八位位组[0]| 0;
八位位组[1]=八位位组[1]| 0;
八位位组[2]=八位位组[2]| 0;
八位位组[3]=八位位组[3]| 0;
if((八位字节[0]<0 | |八位字节[0]>255)||
(八位字节[1]<0 | |八位字节[1]>255)||
(八位字节[2]<0 | |八位字节[2]>255)||
(八位字节[3]<0 | |八位字节[3]>255)){
抛出“无效IPv4地址!”;
}
//>>>0调用将强制将数字恢复为无符号值。
返回八位字节[3]+
((八位组[2]>>0)+
((八位组[1]>>0)+
((八位组[0]>>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);
};
var unrolled long=函数(ip){
var八位字节=ip.split('.');
如果(octets.length!==4)抛出“无效IPv4地址!”;
八位位组[0]=八位位组[0]| 0;
八位位组[1]=八位位组[1]| 0;
八位位组[2]=八位位组[2]| 0;
八位位组[3]=八位位组[3]| 0;
if((八位字节[0]<0 | |八位字节[0]>255)||
(八位字节[1]<0 | |八位字节[1]>255)||
(八位字节[2]<0 | |八位字节[2]>255)||
(八位字节[3]<0 | |八位字节[3]>255)){
抛出“无效IPv4地址!”;
}
//>>>0调用将强制将数字恢复为无符号值。
返回八位字节[3]+
(八位字节[2]*0x100)+
(八位字节[1]*0x10000)+
(八位字节[0]*0x1000000);
};

只是在玩弄优化:

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 );
}
功能(ip){
var八位字节=ip.split('.');
if((八位字节长度!==4)||
((八位组[0]|=0)和~0xFF)||
((八位组[1]|=0)和~0xFF)||
((八位组[2]|=0)和~0xFF)||
((八位组[3]|=0)和~0xFF)){
抛出新错误(“无效IPv4地址!”);
}
返回(八位字节[3])|

(八位位组[2]+1用于基准测试。我会看看你做了什么,然后想出一些办法。谢谢!我有很多关于位的阅读。我很感谢你的反馈!我认为数学是错的。当给出
unrolled long('172.2.6.139'))
它返回
-1409153397
。这是我在尝试按位使用时遇到的问题。我想我可能必须先转换为二进制。@GrayFox检查我的修订答案,我想它会像你预期的那样工作。@GrayFox也修复了我的问题。我花了一些时间来理解为什么展开会更快。我想,因为作为一名学生,我在软件开发中,你学到的第一件事是不要重复自己,编写预期会失败的测试,然后重新迭代。我从这些基准测试中学到了很多东西,并找到了这个伟大的来源: