2010-10-21 25 views
3

Je suis aux prises avec ce code en ce moment. Je veux déterminer si un nombre entier est divisible par 11. De ce que j'ai lu, un entier est divisible à 11 quand la somme (une fois +, une fois -) de ses chiffres est divisible par 11.Tester la divisibilité de Ints par 11

Par exemple : 56518 est divisible par 11, parce que 8-1 + 5-6 + 5 = 11, et 11 est divisible par 11.

Comment puis-je écrire cela dans Haskell? Merci d'avance.

+3

ya un problème avec l'aide modulo? – delnan

+0

@Justin ifan signifie le '.' comme un séparateur entre des milliers et des unités, pas un point décimal. – Yitz

+0

@Justin: Dans certains endroits, '.' est utilisé comme séparateur 1000 (et', 'pour le point décimal), donc il voulait probablement dire' 56518'. – sepp2k

Répondre

12

Un certain nombre x est divisible par y si elle est reste dans la division par y est 0. Vous pouvez juste faire

divisibleBy11 x = x `rem` 11 == 0 
+1

merci beaucoup. Y a-t-il un autre moyen d'obtenir le même résultat? – marco

+1

@ifan: Oui, pas mal. Le plus trivialement, vous pouvez remplacer 'rem' par' mod'. Vous pouvez également créer une liste ou un ensemble contenant tous les multiples de 11 et ensuite vérifier si le nombre est là ou vous pourriez utiliser la règle que vous avez mentionnée dans votre question, mais cela serait beaucoup plus lent. Mais l'un ou l'autre est beaucoup plus lent que d'utiliser 'mod' ou' rem'. – sepp2k

+0

Pointfree: '' divBy11 = (== 0). ('rem' 11)' ' –

7

IFAN Je suis sûr que vous savez que dans la vie réelle que vous utilisez mod ou rem pour cet exemple simple, mais l'algorithme que vous demandez est intéressant. Voici une façon amusante de faire qui met l'accent sur la nature fonctionnelle de 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' 
+0

c'était exactement ce que je cherchais. merci beaucoup pour votre aide – marco

0

Que diriez-vous ...

mod11 n | n < 0 = 11 - mod11 (-n) 
     | n < 11 = n 
     | otherwise = mod11 $ (n `mod` 10) - (n `div` 10) 
2

Certes, div et mod sont plus rapides, mais pourquoi pas? Je suppose que le problème est la conversion d'un numéro à une liste de chiffres:

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

56518 est converti en une chaîne "56518", et chaque symbole dans la chaîne (chaque chiffre) est converti en une chaîne elle-même avec map (:[]), à ce point nous avons ["5","6","5","1","8"], et nous lisons chaque chaîne à un seul chiffre comme une valeur entière: [5,6,5,1,8]. Terminé.

Maintenant, nous pouvons calculer la somme des chiffres de cette façon:

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

cycle [1,-1] fait une liste infinie [1, -1, 1, -1, ...], que nous jumelons la liste inversée de chiffres (toDigit x), et multiplier les éléments de chaque paire. Nous avons donc [8, -1, 5, -6, 5] et sa somme.

Maintenant, nous pouvons le faire récursive:

isDivisible x 
    | x == 11 || x == 0 = True 
    | x < 11   = False 
    | x > 11   = isDivisible (sumDigits x)