Exponential in Ruby 1.8.7.

I met this problem when I tried to calculate 3 ** 557 in irb. Ruby and MacRuby are both installed on my Mac (OS X 10.8). And the ruby ​​version is 1.8.7, MacRuby 0.12 (ruby 1.9.2). rib and macirb gave me two different answers to calculate 3 ** 557. (macirb is right.)

$ irb >> 3**557 => 54755702179342762063551440788945541007926808765326951193810107165429610423703291760740244724326099993131913104272587572918520442872536889724676586931200965615875242243330408150984753872526006744122187638040962508934109837755428764447134683114539218909666971979603 $ macirb irb(main):001:0> 3**557 => 57087217942658063217290581978966727348872586279944803346410228520919738045995056049600505293676159316424182057188730248707922985741467061108015301244570536546607487919981026877250949414156613856336341922395385463291076789878575326012378057561766997352898452974964563 

And then I tried something more, for example. 3 ** 5337, and this time I got the same answer.

So, is this a bug in Ruby 1.8.7, or should I use a different way of calculating exponentiality?

+8
ruby bignum exponential
source share
5 answers

In computing, Ruby is supposed to convert from Fixnum to Bignum when numbers go beyond Fixnum. For older versions of Ruby, this does not work with the ** operator:

 $ 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 this fails depends on the size of the word architecture. 64-bit words on iMac in this example. Internally, Fixnum is cast to a long integer, and the statement is processed to be long. Long overflows at the size of a word, and Ruby ruthlessly copes with this, returning 0.

Note that the * operator works correctly (conversion to Bignum), where ** fails:

 >> a = 2 ** 62 => 4611686018427387904 >> 2 ** 63 => -9223372036854775808 >> a * 2 => 9223372036854775808 >> 2 ** 64 => 0 >> a * 4 => 18446744073709551616 

The transition to the new version of Ruby will be fixed. If you cannot upgrade to a newer version, avoid using Fixnum and ** with more authority.

+3
source share

Using 1.9.3 gives the correct result. If you don't have a really good reason, try using 1.9.3 or better, since 1.8.7 is reset.

It is also worth noting that after testing with 1.8.7-p358 on Linux, I get the correct answer. it may be a bug in the specific version 1.8.7 that you are using.

+2
source share

This is definitely a mistake. This probably depends on the parameters of the processor and / or compilation.

I would not be surprised if he had corrected this commit .

As others noted, only security fixes allow you to do this to 1.8.7 at the moment, so upgrade to 1.9.3.

+1
source share

This is clearly not related to elevation. I think this is somehow related to the transition from 63 to 64 bits needed for presentation, although this does not seem to be 100% consistent.

 >> 19**14 => 799006685782884121 >> 19**15 => -3265617043834753317 >> (19**14)*19 => -3265617043834753317 

and

 >> 2**64-1 => -1 >> 2**64 => 0 >> 0x7fffffffffffffff => 9223372036854775807 

till

 >> 0x8000000000000000 => 9223372036854775808 

Also: starting irb in 32-bit mode ( arch -i386 irb ), I do not see this at this stage, but earlier:

 >> 19**15 => 15181127029874798299 >> 2**31 => -2147483648 
0
source share

Writing your own exponential method seems to be another way to do this, which does not create errors:

 def xpnt(base, exponent) sum = base while exponent >= 2 sum = sum * base exponent -= 1 end puts sum end 

'10 'for any power should start with one "1", followed only by zeros. Ruby function ** :

 10 ** 40 => 10000000000000000000092233720368547758080 

Custom xpnt method:

 xpnt 10, 40 10000000000000000000000000000000000000000 => nil 
0
source share

All Articles