I met this problem when I tried to compute 3**557 in irb. Ruby and MacRuby both are installed in my Mac (OS X 10.8). And the version of ruby is 1.8.7, of MacRuby 0.12 (ruby 1.9.2). rib and macirb gave me two different answers on computation of 3**557. (macirb's is right.)
我尝试在irb中计算3 ** 557时遇到了这个问题。 Ruby和MacRuby都安装在我的Mac(OS X 10.8)中。红宝石的版本是1.8.7,MacRuby 0.12(ruby 1.9.2)。 rib和macirb在计算3 ** 557时给了我两个不同的答案。 (macirb是对的。)
$ irb
>> 3**557
=> 54755702179342762063551440788945541007926808765326951193810107165429610423703291760740244724326099993131913104272587572918520442872536889724676586931200965615875242243330408150984753872526006744122187638040962508934109837755428764447134683114539218909666971979603
$ macirb
irb(main):001:0> 3**557
=> 57087217942658063217290581978966727348872586279944803346410228520919738045995056049600505293676159316424182057188730248707922985741467061108015301244570536546607487919981026877250949414156613856336341922395385463291076789878575326012378057561766997352898452974964563
And then I tried something bigger, e.g. 3**5337, and I got the same answer this time.
然后我尝试了更大的东西,例如3 ** 5337,这次我得到了同样的答案。
So, is this a bug in Ruby 1.8.7, or I should use another way to compute exponentiation?
那么,这是Ruby 1.8.7中的一个错误,还是我应该使用另一种方法来计算取幂?
5 个解决方案
#1
3
When calculating, Ruby is supposed to convert from Fixnum to Bignum when the numbers go beyond the bounds of Fixnum. For older versions of Ruby, this fails with the ** operator:
在计算时,当数字超出Fixnum的界限时,Ruby应该从Fixnum转换为Bignum。对于旧版本的Ruby,这失败了**运算符:
$ ruby --version
ruby 1.8.7 (2012-02-08 patchlevel 358) [universal-darwin12.0]
$ irb
>> 2 ** 62
=> 4611686018427387904
>> 2 ** 63
=> -9223372036854775808
>> 2 ** 64
=> 0
Where it fails depends on the word size of the architecture. 64-bit words on the iMac in this example. Internally, the Fixnum is cast to a long integer, and the operator is handled with longs. The longs overflow at word size, and Ruby is ungracefully handling this by returning 0.
它失败的地方取决于架构的字大小。本例中iMac上的64位字。在内部,Fixnum被强制转换为长整数,操作符用long来处理。字长大小溢出,而Ruby通过返回0来解决这个问题。
Note that the * operator works correctly (converting to Bignum), where the ** fails:
请注意,*运算符正常工作(转换为Bignum),其中**失败:
>> a = 2 ** 62
=> 4611686018427387904
>> 2 ** 63
=> -9223372036854775808
>> a * 2
=> 9223372036854775808
>> 2 ** 64
=> 0
>> a * 4
=> 18446744073709551616
Moving to a newer version of Ruby will fix this. If you can't move to a newer version, then avoid using Fixnum and ** with large powers.
迁移到更新版本的Ruby将解决这个问题。如果您无法移动到更新版本,请避免使用Fixnum和**具有大功率。
#2
2
Using 1.9.3 produces the correct result. Unless you have a really good reason, try to use 1.9.3 or better since 1.8.7 is being phased out.
使用1.9.3可以生成正确的结果。除非你有充分的理由,否则尝试使用1.9.3或更高版本,因为1.8.7正在逐步淘汰。
It's also worth noting that after testing with 1.8.7-p358 on Linux I get the correct answer as well. it could be a bug in the particular version of 1.8.7 you're using.
值得注意的是,在Linux上使用1.8.7-p358进行测试后,我也得到了正确的答案。它可能是您正在使用的1.8.7特定版本中的错误。
#3
1
This is definitely a bug. It is probably dependent on the processor and/or compilation options.
这绝对是个错误。它可能取决于处理器和/或编译选项。
I wouldn't be surprised if it was fixed by this commit.
如果通过此提交修复它,我不会感到惊讶。
As others have stated, only security fixes make it to 1.8.7 nowadays, so upgrade to 1.9.3.
正如其他人所说,现在只有安全修复程序达到1.8.7,所以升级到1.9.3。
#4
0
It's not related to exponentiation explicitly. I think it's in some way related to the transition from 63 to 64 bits required for representation, though this doesn't seem 100% consistent.
它与exponentiation明确无关。我认为它在某种程度上与表示所需的63到64位的转换有关,尽管这似乎并不是100%一致的。
>> 19**14
=> 799006685782884121
>> 19**15
=> -3265617043834753317
>> (19**14)*19
=> -3265617043834753317
and
>> 2**64-1
=> -1
>> 2**64
=> 0
>> 0x7fffffffffffffff
=> 9223372036854775807
yet
>> 0x8000000000000000
=> 9223372036854775808
Also: running irb in 32-bit mode (arch -i386 irb
), I don't see this at this point, but earlier:
另外:在32位模式下运行irb(arch -i386 irb),此时我没有看到这个,但是之前:
>> 19**15
=> 15181127029874798299
>> 2**31
=> -2147483648
#5
0
Writing your own exponentiation method seems to be another way to do it that doesn't produce errors:
编写自己的求幂方法似乎是另一种不会产生错误的方法:
def xpnt(base, exponent)
sum = base
while exponent >= 2
sum = sum * base
exponent -= 1
end
puts sum
end
'10' to any power should begin with a single '1' and be followed by nothing but zeros. Ruby's **
function:
任何权力的'10'应该以单个'1'开头,然后只有零。 Ruby的**功能:
10 ** 40
=> 10000000000000000000092233720368547758080
Custom xpnt
method:
自定义xpnt方法:
xpnt 10, 40
10000000000000000000000000000000000000000
=> nil
#1
3
When calculating, Ruby is supposed to convert from Fixnum to Bignum when the numbers go beyond the bounds of Fixnum. For older versions of Ruby, this fails with the ** operator:
在计算时,当数字超出Fixnum的界限时,Ruby应该从Fixnum转换为Bignum。对于旧版本的Ruby,这失败了**运算符:
$ ruby --version
ruby 1.8.7 (2012-02-08 patchlevel 358) [universal-darwin12.0]
$ irb
>> 2 ** 62
=> 4611686018427387904
>> 2 ** 63
=> -9223372036854775808
>> 2 ** 64
=> 0
Where it fails depends on the word size of the architecture. 64-bit words on the iMac in this example. Internally, the Fixnum is cast to a long integer, and the operator is handled with longs. The longs overflow at word size, and Ruby is ungracefully handling this by returning 0.
它失败的地方取决于架构的字大小。本例中iMac上的64位字。在内部,Fixnum被强制转换为长整数,操作符用long来处理。字长大小溢出,而Ruby通过返回0来解决这个问题。
Note that the * operator works correctly (converting to Bignum), where the ** fails:
请注意,*运算符正常工作(转换为Bignum),其中**失败:
>> a = 2 ** 62
=> 4611686018427387904
>> 2 ** 63
=> -9223372036854775808
>> a * 2
=> 9223372036854775808
>> 2 ** 64
=> 0
>> a * 4
=> 18446744073709551616
Moving to a newer version of Ruby will fix this. If you can't move to a newer version, then avoid using Fixnum and ** with large powers.
迁移到更新版本的Ruby将解决这个问题。如果您无法移动到更新版本,请避免使用Fixnum和**具有大功率。
#2
2
Using 1.9.3 produces the correct result. Unless you have a really good reason, try to use 1.9.3 or better since 1.8.7 is being phased out.
使用1.9.3可以生成正确的结果。除非你有充分的理由,否则尝试使用1.9.3或更高版本,因为1.8.7正在逐步淘汰。
It's also worth noting that after testing with 1.8.7-p358 on Linux I get the correct answer as well. it could be a bug in the particular version of 1.8.7 you're using.
值得注意的是,在Linux上使用1.8.7-p358进行测试后,我也得到了正确的答案。它可能是您正在使用的1.8.7特定版本中的错误。
#3
1
This is definitely a bug. It is probably dependent on the processor and/or compilation options.
这绝对是个错误。它可能取决于处理器和/或编译选项。
I wouldn't be surprised if it was fixed by this commit.
如果通过此提交修复它,我不会感到惊讶。
As others have stated, only security fixes make it to 1.8.7 nowadays, so upgrade to 1.9.3.
正如其他人所说,现在只有安全修复程序达到1.8.7,所以升级到1.9.3。
#4
0
It's not related to exponentiation explicitly. I think it's in some way related to the transition from 63 to 64 bits required for representation, though this doesn't seem 100% consistent.
它与exponentiation明确无关。我认为它在某种程度上与表示所需的63到64位的转换有关,尽管这似乎并不是100%一致的。
>> 19**14
=> 799006685782884121
>> 19**15
=> -3265617043834753317
>> (19**14)*19
=> -3265617043834753317
and
>> 2**64-1
=> -1
>> 2**64
=> 0
>> 0x7fffffffffffffff
=> 9223372036854775807
yet
>> 0x8000000000000000
=> 9223372036854775808
Also: running irb in 32-bit mode (arch -i386 irb
), I don't see this at this point, but earlier:
另外:在32位模式下运行irb(arch -i386 irb),此时我没有看到这个,但是之前:
>> 19**15
=> 15181127029874798299
>> 2**31
=> -2147483648
#5
0
Writing your own exponentiation method seems to be another way to do it that doesn't produce errors:
编写自己的求幂方法似乎是另一种不会产生错误的方法:
def xpnt(base, exponent)
sum = base
while exponent >= 2
sum = sum * base
exponent -= 1
end
puts sum
end
'10' to any power should begin with a single '1' and be followed by nothing but zeros. Ruby's **
function:
任何权力的'10'应该以单个'1'开头,然后只有零。 Ruby的**功能:
10 ** 40
=> 10000000000000000000092233720368547758080
Custom xpnt
method:
自定义xpnt方法:
xpnt 10, 40
10000000000000000000000000000000000000000
=> nil