Javascript 中的无符号整数

IT技术 javascript bit-manipulation unsigned
2021-01-29 17:46:30

我正在处理一个处理 IP 地址信息的页面,但它对整数有符号这一事实感到窒息。我正在使用按位运算符来加速它,但第 64 位(有符号/无符号标志)将它搞砸了。

有没有办法强制一个数字在 Javascript 中不签名?它似乎工作正常,直到子网大于 30 或小于 2。

试试这个:

<html>
    <body>
    
    <script type='text/javascript'>
    document.write( (1 << 30) +"<br/>");
    document.write( (1 << 31) +"<br/>");
    document.write( (1 << 32) +"<br/>");
    </script>
    
    </body>
</html>

结果:

1073741824 -2147483648 1

6个回答
document.write( (1 << 31) +"<br/>");

<<操作者被定义为符号的32位整数(从双精度浮点的天然数存储转换)工作。所以1<<31必然导致负数。

唯一使用无符号 32 位整数的 JavaScript 运算符是>>>. 您可以利用它将您一直在使用其他位运算符处理的有符号整数转换为无符号整数:

document.write(( (1<<31)>>>0 )+'<br />');

同时:

document.write( (1 << 32) +"<br/>");

将不起作用,因为所有移位操作仅使用最低的 5 位移位(在 JavaScript 和其他类似 C 的语言中也是如此)。<<32等于<<0,即。没变化。

Niggle:1<<310x80000000哪个是INT_MIN,或者 -2147483648。-1 是0xFFFFFFFF
2021-03-15 17:46:30
为什么它会返回 1?您将 2^31 乘以 2,结果为 2^32,然后将其转换为 32 位数字,结果为 0。
2021-03-18 17:46:30
这有什么关系?(((1<<31)>>>0) * 2)>>>0返回0而不是1
2021-03-22 17:46:30
好资料。太糟糕了 Javascript 如此有限,我用 HTML 设计界面要容易得多。他们应该在 Firefox 中添加 PyScript 作为一种语言:)。
2021-03-24 17:46:30
+1:信息量很大。我想知道为什么1 << 32结果是 1 而不是 0。
2021-03-29 17:46:30

Douglas Crockford 认为按位运算符是 javascript 的缺点之一:

在 Java 中,按位运算符处理整数。JavaScript 没有整数。它只有双精度浮点数。因此,按位运算符将它们的数字操作数转换为整数,做他们的工作,然后将它们转换回来。在大多数语言中,这些运算符非常接近硬件并且速度非常快。在 JavaScript 中,它们离硬件很远,而且很慢。JavaScript 很少用于进行位操作。

-- Douglas Crockford 在“JavaScript: The Good Parts”中,附录 B,位运算符(强调)

你确定按位运算符真的能加速你的逻辑吗?

与所有其他方法相比,Firefox 中的按位运算速度非常快。在 chrome 中几乎与正常操作相同。(FF4 与 Chrome 12)
2021-03-22 17:46:30
是的,因为这是 emscripten 和其他 JS 编译器一直在使用的内容,并且作为响应,JS 引擎一直在为此进行优化。
2021-03-31 17:46:30
这是真的。老实说,我没有做过很多高级语言之外的编程。我只是假设这样做1 << 24会比Math.pow(2,24)处理速度更快我已将所有代码更改为使用pow,而且它似乎也一样快。
2021-04-06 17:46:30
也许现代浏览器可以按位优化(以及 Math.pow)以更接近硬件。如果不是今天,那么在未来。
2021-04-14 17:46:30

使用 >>> 而不是 >> 来获得无符号右移而不是符号扩展。无论整数是否有符号,所有其他按位运算符的行为方式都相同。

您的代码破坏“当子网...小于 2 时”令人担忧。听起来您可能有一些与整数的符号无关的错误。

那有什么问题呢?1<<31 为您提供正确的值 - 即它设置了第 31 位。按位逻辑 - 掩码、移位等 - 将如您所愿。现在,如果您真的想以2147483647..4294967296 范围内的整数形式显示大于 ((1<<31)-1) 的值,您将不得不做一些令人讨厌的事情或其他事情,例如 alert(x<0?4294967296+x:x) 它通过在内部将 x 强制返回到双重表示来工作。
2021-03-20 17:46:30
问题不在于子网,而是我计算了网络数和主机数。如果 n = 1,一个将是 2^31(即 1 << 31)。
2021-04-08 17:46:30

Javascript 没有整数,所有数字实际上都是双精度数。

MozillaJavascript 1.5 参考建议只能对 32 位数字安全地使用按位运算。

我在某处读到,当您进行按位运算时,它会转换为整数,然后返回给定类型(我认为是双精度)。
2021-03-28 17:46:30
@moonshadow,那是因为,你放了一个 | 在等式中。我将它们全部更改为使用 Math.pow,并且效果很好。
2021-03-29 17:46:30
@bradlis7 如果您从该页面查看给定的按位运算符,例如 & ,它将提到 32 位整数。
2021-03-29 17:46:30
你知道,我已经看了那页 100 次,但没有看到“32 位”。也许我会回去使用 Math.pow(2,n),而不是 (1 << n)。理论上它需要更多的处理循环,但至少它会起作用。
2021-04-06 17:46:30
如果对结果使用移位或按位布尔运算符,Math.pow 将无济于事,因为它会被强制转换为 32 位有符号整数;例如 alert(Math.pow(2,31)|1) 产生 -2147483647
2021-04-07 17:46:30

这里有两个函数可以在 javascript 中将 ipv4 地址与无符号整数相互转换:

function ip2long(ip) {
    var ipl=0;
    ip.split('.').forEach(function( octet ) {
        ipl<<=8;
        ipl+=parseInt(octet);
    });
    return(ipl >>>0);
}

function long2ip (ipl) {
    return ( (ipl>>>24) +'.' +
        (ipl>>16 & 255) +'.' +
        (ipl>>8 & 255) +'.' +
        (ipl & 255) );
}
我建议,ipl+=parseInt(octet, 10);因为八位字节可以包含前导 0。
2021-03-22 17:46:30