2008-12-04 25 views
35

Desde el informe Haskell:¿Cuándo es útil la diferencia entre quotRem y divMod?

El quot, rem, div y clase mod métodos satisfacen estas leyes si y es distinto de cero:

(x `quot` y)*y + (x `rem` y) == x 
(x `div` y)*y + (x `mod` y) == x 

quot es la división entera trunca hacia cero, mientras que el resultado de div se trunca hacia el infinito negativo.

Por ejemplo:

Prelude> (-12) `quot` 5 
-2 
Prelude> (-12) `div` 5 
-3 

¿Cuáles son algunos ejemplos en los que la diferencia entre la forma en que el resultado es materia truncados?

Respuesta

35

Muchos idiomas tienen un operador "mod" o "%" que da el resto después de la división con truncamiento hacia 0; por ejemplo, C, C++ y Java, C# y, probablemente, diría:

(-11)/5 = -2 
(-11)%5 = -1 
5*((-11)/5) + (-11)%5 = 5*(-2) + (-1) = -11. 

de quot y rem están destinados a imitar este comportamiento Haskell. Me imagino que la compatibilidad con la producción de algún programa de C podría ser deseable en alguna situación artificial.

de divmod% Haskell y, y, posteriormente, Python/e, siguen la convención de los matemáticos (por lo menos número-teóricos) en Siempre truncar abajo división (no hacia 0 - hacia el infinito negativo) para que el resto se siempre no negativo Así, en Python,

(-11)/5 = -3 
(-11)%5 = 4 
5*((-11)/5) + (-11)%5 = 5*(-3) + 4 = -11. 

de Haskell div y mod siguen este comportamiento.

+5

"para que el resto siempre sea no negativo" Técnicamente, el signo de 'mod' sigue el signo del segundo operando. – newacct

+0

Huh, tienes razón. No entiendo esta decisión de diseño ... – ShreevatsaR

+0

es para mantener la propiedad que '(q, r) = divMod x y' si y solo si' x = q * y + r'. Ejecute un ejemplo, es inteligente cómo funciona. – luqui

6

Un ejemplo simple donde importaría es probar si un entero es par o impar.

let buggyOdd x = x `rem` 2 == 1 
buggyOdd 1 // True 
buggyOdd (-1) // False (wrong!) 

let odd x = x `mod` 2 == 1 
odd 1 // True 
odd (-1) // True 

Tenga en cuenta, por supuesto, se podría evitar pensar en estos temas por definir sólo extraña de esta manera:

let odd x = x `rem` 2 /= 0 
odd 1 // True 
odd (-1) // True 

En general, sólo recuerda que, por y > 0, x mod y siempre vuelven algo >= 0 mientras x rem y devuelve 0 o algo del mismo signo que x.

23

Esto no es exactamente una respuesta a su pregunta, pero en GHC en x86, quotRem on Int compilará hasta una sola instrucción de máquina, mientras que divMod hace bastante más trabajo. Entonces, si se encuentra en una sección de velocidad crítica y solo trabaja con números positivos, quimio es el camino a seguir.

+2

Para resolver los primos SPOJ, usar rem en lugar de mod hace que mi archivo de prueba se ejecute en 4.758 en lugar de 5.533. Esto significa que la versión más rápida es un 16% más rápida en Ubuntu de 32 bits, Haskell Platform 2011. –

+0

@TimPerry, no creo que eso siga. ¿Qué pasa si hiciste un 'mod' en todo tu programa y viste la misma mejora? – luqui

+0

Dije que cuando cambié las llamadas en mi código de primes de mod a rem y vi una aceleración del 20%. No es un comentario teórico. Fue una descripción de un evento. Solo cambié una cosa (aunque en varios lugares) y vi una aceleración del 20%. Parece que un 20% de aceleración * DID * sigue. –

Cuestiones relacionadas