Quand la différence entre quotRem et divMod est-elle utile?

Depuis le haskell rapport:

les classes quot, rem, div Et mod les méthodes satisfont à ces lois si y est non-zéro:

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

<!-La division entière est tronquée à zéro, alors 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?

41
demandé sur grom 2008-12-04 09:29:33

3 réponses

beaucoup de langues ont un opérateur "mod" ou " % " qui donne le reste après division avec une 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.

Haskell quot et rem visent à imiter ce comportement. Je peux imaginer que la compatibilité avec la sortie d'un programme C pourrait être souhaitable dans une situation artificielle.

Haskell div et mod, et par la suite Python's / et%, suivent la convention de les mathématiciens (au moins nombre-théoriciens) toujours tronquer 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 div et mod suivez ce comportement.

36
répondu ShreevatsaR 2008-12-04 22:49:48

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 de vitesse critique et que vous travaillez sur des nombres positifs seulement, quotRem est la voie à suivre.

25
répondu luqui 2008-12-04 22:53:20

Un exemple simple où il serait question est 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

notez, bien sûr, que vous pourriez éviter de penser à ces questions en définissant simplement odd de cette façon:

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

en général, il suffit de se rappeler que, pour y > 0, x mod y toujours retourner quelque chose >= 0x rem y renvoie 0 ou quelque chose du même signe que X.

6
répondu namin 2008-12-04 07:00:36