Когда разница между 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.