Проверка делимости Ints на 11

Я борюсь с этим кодом прямо сейчас. Я хочу определить, делится ли целое число на 11. Из того, что я прочитал, целое число делится на 11, когда сумма (один раз +, один раз -) его цифр делится на 11.

Например: 56518 делится на 11, потому что 8-1+5-6+5 = 11, а 11 делится на 11.

Как я могу записать это в Haskell? Заранее спасибо.


person marco    schedule 21.10.2010    source источник
comment
Что-то не так с использованием по модулю?   -  person    schedule 21.10.2010
comment
@Justin ifan означает '.' как разделитель между тысячами и единицами, а не десятичная точка.   -  person Yitz    schedule 21.10.2010
comment
@Justin: в некоторых регионах . используется как разделитель тысяч (и , для десятичной точки), поэтому он, вероятно, имел в виду 56518.   -  person sepp2k    schedule 21.10.2010
comment
@Yitz @sepp2k - Дох! Спрыгнул с пистолета. Совсем забыл, что, видимо, существуют и другие локали.   -  person Justin Niessner    schedule 21.10.2010
comment
@ifan: 34672 не соответствует вашему правилу. 2-7+6-4+3 = 0   -  person Matt Ellen    schedule 22.10.2010
comment
Как называется это правило и каковы ограничения? Кажется, Мэтт доказал, что это неправильно.   -  person Jonas Elfström    schedule 22.10.2010


Ответы (4)


Число x делится на y, если его остаток при делении на y равен 0. Так что вы можете просто сделать

divisibleBy11 x = x `rem` 11 == 0
person sepp2k    schedule 21.10.2010
comment
большое большое спасибо. есть ли другой способ получить тот же результат? - person marco; 21.10.2010
comment
@ifan: Да, довольно много. Наиболее тривиально вы можете заменить rem на mod. Вы также можете создать список или набор, содержащий все числа, кратные 11, а затем проверить, есть ли там число, или вы можете использовать правило, которое вы упомянули в своем вопросе, но это было бы намного медленнее. Но любой из них намного медленнее, чем использование mod или rem. - person sepp2k; 21.10.2010
comment
Без очков: divBy11 = (==0) . (`rem` 11) - person digitalis_; 06.02.2017

ifan Я уверен, вы знаете, что в реальной жизни вы бы использовали mod или rem для этого простого примера, но алгоритм, о котором вы спрашиваете, интересен. Вот интересный способ сделать это, который подчеркивает функциональную природу Haskell:

digits = map (`mod` 10) . takeWhile (> 0) . iterate (`div` 10)

divisible11 = (== 0) . head . dropWhile (>= 11) . iterate (reduce11 . digits)
  where
    reduce11 []     = 0
    reduce11 (d:ds) = foldl combine d $ zip (cycle [(-), (+)]) ds
    combine d (op, d') = d `op` d'
person Yitz    schedule 21.10.2010
comment
это было именно то, что я искал. большое спасибо за вашу помощь - person marco; 21.10.2010

Конечно, div и mod быстрее, но почему бы и нет? Я предполагаю, что проблема заключается в преобразовании числа в список цифр:

toDigits = map (read . (:[])) . show

56518 преобразуется в строку "56518", и каждый символ в строке (каждая цифра) преобразуется в саму строку с map (:[]), на данный момент у нас есть ["5","6","5","1","8"], и мы читаем каждую строку из одной цифры как целочисленное значение: [5,6,5,1,8]. Сделанный.

Теперь мы можем вычислить сумму цифр следующим образом:

sumDigits x = sum (zipWith (*) (cycle [1,-1]) (reverse (toDigits x)))

cycle [1,-1] образует бесконечный список [1, -1, 1, -1, ...], который мы соединяем с перевернутым списком цифр (toDigit x) и умножаем элементы каждой пары. Итак, у нас есть [8, -1, 5, -6, 5] и его сумма.

Теперь мы можем сделать это рекурсивно:

isDivisible x
  | x == 11 || x == 0 = True
  | x < 11            = False
  | x > 11            = isDivisible (sumDigits x)
person sastanin    schedule 22.10.2010

Как насчет...

mod11 n | n < 0 = 11 - mod11 (-n) 
        | n < 11 = n
        | otherwise = mod11 $ (n `mod` 10) - (n `div` 10) 
person Landei    schedule 22.10.2010