2012-08-17 13 views
8

Me encontré con este problema cuando traté de calcular 3 ** 557 en irb. Ruby y MacRuby están instalados en mi Mac (OS X 10.8). Y la versión de ruby ​​es 1.8.7, de MacRuby 0.12 (ruby 1.9.2). rib y macirb me dieron dos respuestas diferentes en el cálculo de 3 ** 557. (macirb's tiene razón.)Exponencia en Ruby 1.8.7 Devuelve respuestas incorrectas

$ irb 
>> 3**557 
=> 54755702179342762063551440788945541007926808765326951193810107165429610423703291760740244724326099993131913104272587572918520442872536889724676586931200965615875242243330408150984753872526006744122187638040962508934109837755428764447134683114539218909666971979603 

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

Y luego intenté con algo más grande, p. 3 ** 5337, y obtuve la misma respuesta esta vez.

Entonces, ¿esto es un error en Ruby 1.8.7, o debería usar otra forma de calcular la exponenciación?

+0

Sin relación con Rubí específicamente, pero es posible que desee ver en [exponenciación modular] (http://en.wikipedia.org/wiki/Modular_exponentiation) dependiendo de lo que esté haciendo con el resultado. – jli

+0

No tengo una MRI pre-1.9.3 instalada, pero eso da el resultado correcto. –

+0

¿Qué modelo exacto de mac estás usando? No puedo reproducir esto en mi MacPro (Xeon) con la misma versión de Ruby (1.8.7 p358). Tampoco puedo en un antiguo 1.8.6 ejecutando en 32 bits. –

Respuesta

3

Al calcular, Ru se supone que convierte de Fixnum a Bignum cuando los números van más allá de los límites de Fixnum. Para versiones anteriores de Ruby, esto no funciona con el operador **:

$ ruby --version 
ruby 1.8.7 (2012-02-08 patchlevel 358) [universal-darwin12.0] 
$ irb 
>> 2 ** 62 
=> 4611686018427387904 
>> 2 ** 63 
=> -9223372036854775808 
>> 2 ** 64 
=> 0 

En caso de que no depende del tamaño de palabra de la arquitectura. Palabras de 64 bits en el iMac en este ejemplo. Internamente, el Fixnum se convierte en un entero largo y el operador se maneja con longs. Los largos desbordan al tamaño de la palabra, y Ruby se ungracefully el manejo de esta devolviendo 0.

Tenga en cuenta que el operador * funciona correctamente (la conversión a Bignum), donde la falla **:

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

El cambio a una La versión más nueva de Ruby solucionará esto. Si no puede pasar a una versión más nueva, evite usar Fixnum y ** con grandes poderes.

2

El uso de 1.9.3 produce el resultado correcto. A menos que tenga una muy buena razón, trate de usar 1.9.3 o mejor ya que 1.8.7 está siendo eliminado.

También vale la pena señalar que después de probar con 1.8.7-p358 en Linux, también recibo la respuesta correcta. podría ser un error en la versión particular de 1.8.7 que estás usando.

+0

¡Gracias! Se podría instalar con Xcode $ ruby ​​--version ruby ​​1.8.7 (2012-02-08 patchlevel 358) [universal-darwin12.0] – Vej

+0

XCode no incluye Ruby, pero OS X generalmente incluye alguna versión con el sistema, aunque cualquiera que sea serio acerca de Ruby usa 'rvm' o' rbenv' para cambiarlo por un En general, no es una buena idea meterse con el sistema Ruby, ya que técnicamente es propiedad del sistema y Apple y puede ser parchado por capricho. – tadman

+0

Ahora estoy usando JewelryBox para actualizar mi Ruby a 1.9.3-p194 . – Vej

1

Esto es definitivamente un error. Es probable que dependa del procesador y/o de las opciones de compilación.

No me sorprendería que lo haya solucionado this commit.

Como han dicho otros, solo las correcciones de seguridad hacen que sean 1.8.7 en la actualidad, así que actualícese a 1.9.3.

0

No está relacionado explícitamente con la exponenciación. Creo que de alguna manera está relacionado con la transición de 63 a 64 bits requerida para la representación, aunque esto no parece ser 100% consistente.

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

y

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

todavía

>> 0x8000000000000000 
=> 9223372036854775808 

también: correr IRB en el modo de 32 bits (arch -i386 irb), no veo esto en este momento, pero antes:

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

Escribir su propio método de exponenciación parece que hay otra manera de hacerlo que no produce errores:

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

'10' a ningún poder debe comenzar con un solo '1' y seguir por nada pero ceros. de Ruby ** función:

10 ** 40 
=> 10000000000000000000092233720368547758080 

personalizada xpnt método:

xpnt 10, 40 
10000000000000000000000000000000000000000 
=> nil 
Cuestiones relacionadas