-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathPrimos_circulares.hs
133 lines (106 loc) · 3.97 KB
/
Primos_circulares.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
-- Primos_circulares.hs
-- Primos circulares
-- José A. Alonso Jiménez <https://jaalonso.github.io>
-- Sevilla, 7-junio-2022
-- ---------------------------------------------------------------------
-- ---------------------------------------------------------------------
-- Un primo circular es un número tal que todas las rotaciones de sus
-- dígitos producen números primos. Por ejemplo, 195 es un primo
-- circular ya que las rotaciones de sus dígitos son 197, 971 y 719 y
-- los tres números son primos.
--
-- Definir la constante
-- circulares :: [Integer]
-- cuyo valor es la lista de los números primos circulares. Por ejemplo,
-- take 16 circulares == [2,3,5,7,11,13,17,31,37,71,73,79,97,113,131,197]
-- circulares !! 50 == 933199
-- ---------------------------------------------------------------------
{-# OPTIONS_GHC -fno-warn-type-defaults #-}
{-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}
{-# OPTIONS_GHC -fno-warn-unused-imports #-}
module Primos_circulares where
import Data.Numbers.Primes (isPrime, primes)
import Test.QuickCheck (Positive (Positive), quickCheck)
-- 1ª solución
-- ===========
circulares1 :: [Integer]
circulares1 = filter esCircular1 primes
-- (esCircular1 n) se verifica si n es un número circular. Por ejemplo,
-- esCircular1 197 == True
-- esCircular1 157 == False
esCircular1 :: Integer -> Bool
esCircular1 = all (isPrime . read) . rotaciones1 . show
-- (rotaciones1 xs) es la lista de las rotaciones obtenidas desplazando
-- el primer elemento xs al final. Por ejemplo,
-- rotaciones1 [2,3,5] == [[2,3,5],[3,5,2],[5,2,3]]
rotaciones1 :: [a] -> [[a]]
rotaciones1 xs = reverse (aux (length xs) [xs])
where aux 1 yss = yss
aux n (ys:yss) = aux (n-1) (rota ys : ys :yss)
-- 2ª solución
-- ===========
circulares2 :: [Integer]
circulares2 = filter esCircular2 primes
esCircular2 :: Integer -> Bool
esCircular2 = all (isPrime . read) . rotaciones2 . show
rotaciones2 :: [a] -> [[a]]
rotaciones2 xs = take (length xs) (iterate rota xs)
-- (rota xs) es la lista añadiendo el primer elemento de xs al
-- final. Por ejemplo,
-- rota [3,2,5,7] == [2,5,7,3]
rota :: [a] -> [a]
rota (x:xs) = xs ++ [x]
-- 3ª solución
-- ===========
circulares3 :: [Integer]
circulares3 = filter (all isPrime . rotaciones3) primes
rotaciones3 :: Integer -> [Integer]
rotaciones3 n = [read (take m (drop i (cycle s))) | i <- [1..m]]
where s = show n
m = length s
-- 4ª definición
-- =============
-- Nota. La 4ª definición es una mejora observando que para que n sea un
-- número primo circular es necesario que todos los dígitos de n sean
-- impares, salvo para n = 2.
circulares4 :: [Integer]
circulares4 = 2 : filter esCircular4 primes
-- (esCircular4 n) se verifica si n es un número circular. Por ejemplo,
-- esCircular4 197 == True
-- esCircular4 157 == False
esCircular4 :: Integer -> Bool
esCircular4 n = digitosImpares n &&
all (isPrime . read) (rotaciones2 (show n))
-- (digitosImpares n) se verifica si todos los dígitos de n son
-- impares. Por ejemplo,
-- digitosImpares 7351 == True
-- digitosImpares 7341 == False
digitosImpares :: Integer -> Bool
digitosImpares = all (`elem` "135679") . show
-- Comprobación de equivalencia
-- ============================
-- La propiedad es
prop_circulares :: Positive Int -> Bool
prop_circulares (Positive n) =
all (== circulares1 !! n)
[circulares2 !! n,
circulares3 !! n,
circulares4 !! n]
-- La comprobación es
-- λ> quickCheckWith (stdArgs {maxSize=50}) prop_circulares
-- +++ OK, passed 100 tests.
-- Comparación de eficiencia
-- =========================
-- La comparación es
-- λ> circulares1 !! 46
-- 331999
-- (2.08 secs, 7,229,208,200 bytes)
-- λ> circulares2 !! 46
-- 331999
-- (1.93 secs, 7,165,043,992 bytes)
-- λ> circulares3 !! 46
-- 331999
-- (0.74 secs, 2,469,098,648 bytes)
-- λ> circulares4 !! 46
-- 331999
-- (0.28 secs, 917,501,600 bytes)