Voici mon approche légèrement différente pour cette tâche qui est beaucoup plus efficace.
La clé est de stimuler pas vérifier tout le chemin jusqu'à la fin, mais seulement jusqu'à sa racine carrée. Je veux dire que si nous voulons trouver des composites de 100, nous n'avons pas besoin de contrôler tous les 100 nombres. Nous avons seulement besoin de contrôler jusqu'à sqrt 100
(comme [2..10]
) pour voir (mod 100 x) == 0
. Nous commençons à partir de 2 puisque vous ne voulez pas 1 et le nombre lui-même. Une fois que nous avons les chiffres satisfaisants 100 div x
devrait nous donner l'autre. Donc, si 2 est un composite alors 100 div 2
(50) est un autre comme 4 rendements 25 et 5 rendements 20. Bien sûr, quand nous arrivons à 10, il nous en donnera 10 autres et nous n'évaluerons que l'un d'entre eux. Cool..!
Donc, c'est le code
kcomposites :: Int -> [Int]
kcomposites k =
let factors n = concat [bool [x, n `div` x] [x] (x^2 == n)
| x <- [2..limit], n `mod` x == 0]
where limit = truncate . sqrt . realToFrac $ n
in foldr (\n rs -> bool rs (n:rs) (k == (length . factors $ n))) [] [2..]
Voici les performances de ce code pour k = 19 pour les premiers 5 éléments;
*Main> take 5 . kcomposites $ 19
[576,1600,2916,3136,7744]
(0.43 secs, 174,826,272 bytes)
et voici la performance de votre code pour k = 19 pour les 5 premiers éléments;
*Main> take 5 . kcomposite $ 19
[576,1600,2916,3136,7744]
(17.61 secs, 6,246,022,504 bytes)
Note: Je ne conseillerais pas de vérifier k = 5 pour 5 éléments. Même ce code a pris comme 15 minutes pour arriver à [64,729,15625,117649,1771561]
le code ci-dessus prendra probablement une quantité folle de temps (comme un jour ou plus peut-être).
Permet de les comparer avec take 3
.
*Main> take 3 . kcomposites $ 5
[64,729,15625]
(1.14 secs, 472,228,880 bytes)
*Main> take 3 . kcomposite $ 5
[64,729,15625]
(69.84 secs, 25,409,801,688 bytes)
On dirait que vous avez inversé x et n. Vous avez besoin de '(longueur (facteurs x)) == n-2'. –
Aussi n + 2 bien sûr, pas n-2. –