在Ruby中模拟int64溢出
我是一个很长时间的程序员,但对Ruby还不熟悉。我正在尝试移植一个名为CheckRevision的算法,用于在登录到Battle.net的在线游戏服务之前检查游戏文件的完整性 该算法使用给定的公式对文件进行“散列”。在没有枯燥细节的情况下,它不断地修改值在Ruby中模拟int64溢出,ruby,integer,type-conversion,Ruby,Integer,Type Conversion,我是一个很长时间的程序员,但对Ruby还不熟悉。我正在尝试移植一个名为CheckRevision的算法,用于在登录到Battle.net的在线游戏服务之前检查游戏文件的完整性 该算法使用给定的公式对文件进行“散列”。在没有枯燥细节的情况下,它不断地修改值a、b和c,这些值都是64位整数,或者在我移植的参考实现中,修改一个Java长的。我的实现在最初的几次迭代中是正确的,但是当int64应该环绕它时,它就变成了BigNum 将FixNum限制为64位的正确方法是什么?或者我应该使用其他类型吗?只要
a
、b
和c
,这些值都是64位整数,或者在我移植的参考实现中,修改一个Java长的
。我的实现在最初的几次迭代中是正确的,但是当int64应该环绕它时,它就变成了BigNum
将FixNum限制为64位的正确方法是什么?或者我应该使用其他类型吗?只要我们讨论的是无符号整数,就可以使用模运算符计算溢出
irb(main):001:0> a = 2**128 + 1256231
=> 340282366920938463463374607431769467687
irb(main):002:0> a % 2**64
=> 1256231
只要我们讨论的是无符号整数,就可以用模运算符计算溢出
irb(main):001:0> a = 2**128 + 1256231
=> 340282366920938463463374607431769467687
irb(main):002:0> a % 2**64
=> 1256231
在某些情况下,即使在64位平台上,64位整数在Ruby MRI内部也表示为bignum(由于实现细节,在64位平台上fixnum的长度仅为63位,在32位平台上为31位)。因此,使用“二进制”和“运算符
&
”会快得多:
ruby-1.9.2-p290 :001 > a = 2**128 + 1256231
=> 340282366920938463463374607431769467687
ruby-1.9.2-p290 :002 > a & (2 ** 64 - 1)
=> 1256231
ruby-1.9.2-p290 :003 > a & 0xffffffffffffffff
=> 1256231
最后一个变体有点难看,但也更快,因为Ruby MRI缺少固定的文件夹。如果您在循环中执行002
子句,它将每次计算2**64-1
)
Ruby MRI是Ruby的官方(“Matz Ruby实现”)变体,即我们大多数人使用的“普通”Ruby。我在这里列出的细节可能适用于也可能不适用于其他实现,但在任何平台或语言上,二进制“and”通常比模运算符快或快。64位整数在Ruby MRI中表示为bignum,在某些情况下甚至在64位平台上也是如此(由于实施细节,64位平台上的fixnum只有63位长,32位平台上的fixnum只有31位长)。因此,使用“二进制”和“运算符
&
”会快得多:
ruby-1.9.2-p290 :001 > a = 2**128 + 1256231
=> 340282366920938463463374607431769467687
ruby-1.9.2-p290 :002 > a & (2 ** 64 - 1)
=> 1256231
ruby-1.9.2-p290 :003 > a & 0xffffffffffffffff
=> 1256231
最后一个变体有点难看,但也更快,因为Ruby MRI缺少固定的文件夹。如果在循环中执行002
子句,每次都会计算2**64-1
)
Ruby MRI是Ruby的官方(“Matz Ruby实现”)变体,即我们大多数人使用的“普通”Ruby。我在这里列出的细节可能适用于也可能不适用于其他实现,但二进制“and”通常比任何平台或语言上的模运算符更快或一样快。我喜欢它。如果必要的话,位推送应该会使处理签名整数变得更容易。我喜欢它。此外,如果需要,位推送应该使处理有符号整数更容易。