Когда разница между quotRem и divMod полезна?

Из отчета haskell:

Класс quot, rem, div и mod методы удовлетворяют этим законам, если y не равен нулю:

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

quot является целым делением, усеченным к нулю, а результат divусекается к отрицательной бесконечности.

Например:

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

Каковы некоторые примеры того, где разница между тем, как результат усечен, имеет значение?

Ответ 1

У многих языков есть оператор "mod" или "%", который дает остаток после деления с усечением в сторону 0; например C, С++ и Java, и, возможно, С#, скажет:

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

Haskell quot и rem предназначены для имитации этого поведения. Я могу представить себе, что совместимость с выходом некоторой программы на C может быть желательной в некоторой надуманной ситуации.

Haskell div и mod, а затем Python/и%, следуют соглашению математиков (по крайней мере теоретиков числа) при всегда усечении вниз деления (не в направлении 0 - к отрицательной бесконечности), так что остаток всегда неотрицательна. Таким образом, в Python

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

Haskell div и mod следуют этому поведению.

Ответ 2

Это не совсем ответ на ваш вопрос, но в GHC на x86 quotRem on Int будет скомпилировать до одной машинной команды, тогда как divMod выполняет немного больше работы. Поэтому, если вы находитесь в критическом критически важном разделе и работаете только с положительными номерами, quotRem - это способ пойти.

Ответ 3

Простой пример, где это имеет значение, - это тестирование, если целое число четное или нечетное.

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

Обратите внимание, что вы, конечно, можете не думать об этих проблемах, просто определяя нечетные таким образом:

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

В общем, просто помните, что для y > 0, x mod y всегда возвращайте что-то >= 0, а x rem y возвращает 0 или что-то похожее на значок x.