2008-12-04 7 views
35

D'après le rapport de haskell:Quand la différence entre quotRem et divMod est-elle utile?

Le quot, rem, div, et la classe mod méthodes satisfont à ces lois si y est non nul:

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

quot est division entière tronquée vers zéro, tandis que le résultat de div est tronqué vers l'infini négatif.

Par exemple:

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

Quels sont quelques exemples où la différence entre la façon dont le résultat est tronqué questions?

Répondre

35

De nombreuses langues ont un opérateur "mod" ou "%" qui donne le reste après la division avec la troncature vers 0; par exemple C, C++ et Java, et probablement C#, dirait:

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

quot et rem Haskell sont destinés à imiter ce comportement. Je peux imaginer la compatibilité avec la sortie de certains programmes C pourrait être souhaitable dans une situation artificielle.

Haskell de div et mod, puis Python/et%, suivent la convention des mathématiciens (au moins nombre théoriciens) en tronquant toujours bas division (pas vers 0 - vers l'infini négatif) de sorte que le reste est toujours non négatif. Ainsi en Python,

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

Haskell et de divmod suivent ce comportement.

+5

"pour que le reste soit toujours non négatif" Techniquement, le signe de "mod" suit le signe du second opérande. – newacct

+0

Euh, vous avez raison. Je ne comprends pas cette décision de conception ... – ShreevatsaR

+0

c'est de maintenir la propriété que '(q, r) = divMod x y' si et seulement si' x = q * y + r'. Exécutez un exemple, c'est intelligent comment cela fonctionne. – luqui

6

Un exemple simple dans lequel il serait important de tester si un entier est pair ou impair.

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 

Remarque, bien sûr, vous pourriez ne pas penser à ces questions en définissant simplement étrange de cette façon:

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

En général, rappelez-vous que, pour y > 0, x mod y reviennent toujours quelque chose >= 0 tout x rem y renvoie 0 ou quelque chose du même signe que x.

23

Ce n'est pas exactement une réponse à votre question, mais dans GHC sur x86, quotRem sur Int compilera jusqu'à une seule instruction machine, alors que divMod fait un peu plus de travail. Donc, si vous êtes dans une section critique en termes de vitesse et que vous travaillez uniquement sur des nombres positifs, quotRem est la solution.

+2

Pour résoudre les nombres premiers SPOJ, utiliser rem plutôt que mod rend mon fichier de test exécuté en 4.758 plutôt qu'en 5.533s. Cela signifie que la version plus rapide est 16% plus rapide sous Ubuntu 32 bits, plate-forme Haskell 2011. –

+0

@TimPerry, je ne pense pas que cela suit. Et si vous faisiez un mod dans tout votre programme et que vous voyiez la même amélioration? – luqui

+0

J'ai déclaré que lorsque j'ai changé les appels dans mon code primes de mod à rem et j'ai vu une accélération de 20%. Ce n'est pas un commentaire théorique. C'était une description d'un événement. J'ai seulement changé une chose (quoique plusieurs endroits) et j'ai vu une accélération de 20%. Il semble que 20% d'accélération * DID * suivent. –

Questions connexes