¿Cuándo es útil la diferencia entre quotRem y divMod?
Pregunta
Del informe haskell:
Las clases quot, rem, div y mod los 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 una división entera truncada hacia cero, mientras que el resultado dediv
se trunca hacia el infinito negativo.
Por ejemplo:
Prelude> (-12) `quot` 5
-2
Prelude> (-12) `div` 5
-3
¿Cuáles son algunos ejemplos de dónde importa la diferencia entre cómo se trunca el resultado?
Solución
Muchos idiomas tienen un " mod " o "%" operador que da el resto después de la división con truncamiento hacia 0; por ejemplo, C, C ++ y Java, y probablemente C #, dirían:
(-11)/5 = -2
(-11)%5 = -1
5*((-11)/5) + (-11)%5 = 5*(-2) + (-1) = -11.
El Haskell quot
y rem
están destinados a imitar este comportamiento. Me imagino que la compatibilidad con la salida de algún programa en C podría ser deseable en alguna situación artificial.
Haskell's div
y mod
, y posteriormente Python / y%, siguen la convención de matemáticos (al menos teóricos de números) siempre truncando hacia abajo división (no hacia 0 - hacia infinito negativo) para que el resto sea siempre no negativo. Así en Python,
(-11)/5 = -3
(-11)%5 = 4
5*((-11)/5) + (-11)%5 = 5*(-3) + 4 = -11.
Haskell div
y mod
siguen este comportamiento.
Otros consejos
Esta no es exactamente una respuesta a su pregunta, pero en GHC en x86, "Rem en Int se compilará en una sola instrucción de máquina, mientras que divMod trabaja bastante más". Entonces, si se encuentra en una sección de velocidad crítica y trabaja solo con números positivos, "Rem es el camino a seguir".
Un ejemplo simple donde importaría es probar si un número 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 que, por supuesto, puede evitar pensar en estos problemas simplemente definiendo impar de esta manera:
let odd x = x `rem` 2 /= 0
odd 1 // True
odd (-1) // True
En general, solo recuerde eso, para y > 0
, x mod y
siempre devuelve algo > = 0
mientras que x rem y
devuelve 0 o algo del mismo signo que x.