Número primo de Sheldon
En el episodio número 73 de la serie «The Big Bang Theory», Sheldon Cooper enuncia lo siguiente:
«El mejor número es el 73. El 73 es el 21-ésimo número primo. Al invertir sus cifras obtenemos 37, que es el primo número 12. Y al invertir este obtenemos 21, que es el producto de, agarraos fuerte, 7 y 3.»
Se define un número primo de Sheldon como: el n-ésimo número primo p(n) será un primo de Sheldon si cumple que el producto de sus dígitos es n y si, además, el número que se obtiene al invertir sus cifras, rev(p(n)), es el rev(n)-ésimo número primo; es decir, si rev(p(n)) = p(rev(n)).
Definir la función
1 |
esPrimoSheldon :: Int -> Bool |
tal que (esPrimoSheldon x) se verifica si x un primo de Sheldon. Por ejemplo,
1 2 3 |
_ esPrimoSheldon 73 == True esPrimoSheldon 79 == False |
Comprobar con QuickCheck que 73 es el único primo de Sheldon.
Referencia: Este ejercicio está basado en la noticia Descubierta una nueva propiedad de los números primos gracias a The Big Bang Theory donde podéis leer más información sobre el tema, entre ello la prueba de que el 73 es el único número primo de Sheldon.
Nota: Este ejercicio ha sido propuesto por Ángel Ruiz Campos.
Soluciones
[schedule expon=’2019-06-12′ expat=»06:00″]
- Las soluciones se pueden escribir en los comentarios hasta el 12 de junio.
- El código se debe escribir entre una línea con <pre lang=»haskell»> y otra con </pre>
Pensamiento
El mejor número es el 73. El 73 es el 21-ésimo número primo. Al invertir sus cifras obtenemos 37, que es el primo número 12. Y al invertir este obtenemos 21, que es el producto de, agarraos fuerte, 7 y 3.
Sheldon Cooper
[/schedule]
[schedule on=’2019-06-12′ at=»06:00″]
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 |
import Data.Char (digitToInt) import Data.List (elemIndex) import Data.Maybe (fromJust) import Data.Numbers.Primes (isPrime, primes) import Test.QuickCheck (Property, (==>), quickCheck) -- 1ª definición -- ============= esPrimoSheldon :: Int -> Bool esPrimoSheldon x = n > 0 && x == primes !! (n - 1) && inverso x == primes !! (inverso n - 1) where n = productoDigitos x -- (productoDigitos x) es el producto de los dígitos de x. Por ejemplo, -- productoDigitos 73 == 21 productoDigitos :: Int -> Int productoDigitos x = product (map digitToInt (show x)) -- (inverso x) es el número obtenido invirtiendo el orden de los dígitos -- de x. Por ejemplo, -- inverso 735 == 537 inverso :: Int -> Int inverso x = read (reverse (show x)) -- 2ª definición -- ============= esPrimoSheldon2 :: Int -> Bool esPrimoSheldon2 x = n > 0 && x == primes !! (n - 1) && inverso2 x == primes !! (inverso2 n - 1) where n = productoDigitos2 x -- (productoDigitos2 x) es el producto de los dígitos de x. Por ejemplo, -- productoDigitos2 73 == 21 productoDigitos2 :: Int -> Int productoDigitos2 = product . map digitToInt . show -- (inverso2 x) es el número obtenido invirtiendo el orden de los dígitos -- de x. Por ejemplo, -- inverso2 735 == 537 inverso2 :: Int -> Int inverso2 = read . reverse . show -- 3ª definición -- ============= esPrimoSheldon3 :: Int -> Bool esPrimoSheldon3 n = isPrime n && p1 && p2 where p = primes i1 = fromJust (elemIndex n p) + 1 i2 = read (reverse (show i1)) p1 = i1 == product (map digitToInt (show n)) p2 = read (reverse (show n)) == p !! (i2 - 1) -- Propiedad de primo de Sheldon -- ============================= -- La propiedad es prop_primoDeShelldon :: Int -> Property prop_primoDeShelldon x = x >= 0 ==> esPrimoSheldon x == (x == 73) -- La comprobación es -- λ> quickCheck prop_primoDeShelldon -- +++ OK, passed 100 tests. |
[/schedule]
Proof: https://www.math.dartmouth.edu/~carlp/sheldonresub011119.pdf
Solución óptima:
Complicándose un poco más…
esPrimoSheldon = (==73)
O(1)
*Main> :main
+++ OK, passed 100000 tests (0.304% = 73).
esPrimoSheldon :: Int -> Bool
esPrimoSheldon x | not(isPrime x) || not(isPrime (inverso x)) = False
|otherwise = posicion x == inverso (posicion (inverso x)) &&
sort (primeFactors (posicion x)) == sort (digitos x)
posicion :: Int -> Int
posicion x | not (isPrime x) = error «no es primo»
| otherwise = head [n | n <- [0..], primes !! n == x] + 1
inverso :: Int -> Int
inverso x = aDigito (reverse (digitos x))
aDigito :: [Int] -> Int
aDigito [] = 0
aDigito (x:xs) = x *10^length(xs) + aDigito xs
digitos :: Int -> [Int]
digitos x = [read [y] | y <- show x]
prop_primoSheldon :: Int -> Property
prop_primoSheldon n = isPrime n && n /= 73 ==> not (esPrimoSheldon n)