Tra*_*vis 5 javascript ruby bit-manipulation
我发现在Ruby中使用整数会导致它们的二进制表示形式大于32位时,它们的行为不同于JS。
a = 144419633058839139324
b = 3903086624
Run Code Online (Sandbox Code Playgroud)
JS:
a >> 0; => 1482555392
b >> 0; => -391880672
Run Code Online (Sandbox Code Playgroud)
红宝石:
a >> 0 => 144419633058839139324
[a].pack('V').unpack('V').first => 1482560508
[b].pack('V').unpack('V').first => 3903086624
Run Code Online (Sandbox Code Playgroud)
我的问题是如何转换我的Ruby代码以提供相同的返回值JS?
这是一个很好的问题。我做了一些实验,试图弄清楚JavaScript到底在做什么,但后来我想:“我敢打赌,规范说。” 果然做到了!
首先,我检查了“ 按位移位运算符”部分,然后从中学到的知识是您已经知道的:在进行按位运算之前,JavaScript将其操作数转换为32位整数。为此,它链接到名为ToInt32的“抽象操作”(即由JavaScript引擎实现的算法)的定义。令人高兴的是,这很容易理解:
ToInt32 :(带符号的32位整数)
抽象运算ToInt32将其自变量转换为-2 31到2 31?1(含)范围内的2 32个整数值之一。此抽象操作的功能如下:
- 令number为在输入参数上调用ToNumber的结果。[这只是将非数字值(例如布尔值和字符串)转换为数字。]
- 如果number为NaN,则+0,?0,+?或?? ,返回+0。
- 令posInt为
sign(
数字) * floor(abs(
number))
。[sign
如果 number 为负,则返回-1;如果为负,则返回1。]- 设int32bit为posInt模2 32 ; 也就是说,一个Number类型的有限整数值k具有正号,其大小小于2 32,因此posInt和k 的数学差为2 32的整数倍。
- 如果int32bit大于或等于2 31,则返回int32bit?2 32,否则返回int32bit。
我们可以将其直接转换为Ruby(我将步骤1-5标记为注释):
def to_int32(number)
# (1)(2)
begin
sign = number < 0 ? -1 : 1
abs = number.abs
return 0 if abs == 0 || abs == Float::INFINITY
rescue
return 0
end
pos_int = sign * abs.floor # (3)
int_32bit = pos_int % 2**32 # (4)
# (5)
return int_32bit - 2**32 if int_32bit >= 2**31
int_32bit
end
Run Code Online (Sandbox Code Playgroud)
那么,行得通吗?
a = 144419633058839130000
puts to_int32(a)
# => 1482551184
b = 3903086624
puts to_int32(b)
# => -391880672
Run Code Online (Sandbox Code Playgroud)
似乎是合法的!
现在,我敢肯定有更多简洁明了且可能更快的方法,但这应该可以帮助您入门。