Órbita con raíz entera
El enunciado del problema 2 de la OME (Olimpiada Matemática Española) del 1998 es
Sea p un número primo. Determinar todos los enteros k tales que sqrt(k² - k*p) es natural.
Definir las funciones
orbita :: Integer -> [Integer] orbitaDePrimo :: Integer -> [Integer]
tales que
- (orbita n) es la lista de todos los enteros k tales que sqrt(k² - k*n) es natural. Por ejemplo,
take 4 (orbita 6) == [0,-2,6,8] take 5 (orbita 36) == [0,-12,36,48,-64] take 6 (orbita 9) == [0,-3,9,12,-16,25] take 8 (orbita 27) == [0,-9,27,36,-48,75,-169,196] take 10 (orbita 111) == [0,-37,111,148,-289,400,-972,1083,-3025,3136]
- (orbitaDePrimo p) es la lista de todos los enteros k tales que sqrt(k² - k*p) es natural, suponiendo que p es un número primo. Por ejemplo,
orbitaDePrimo 5 == [0,-4,5,9] orbitaDePrimo (primes !! (10^6)) == [0,15485867,-59953011442489,59953026928356]
Soluciones
import Data.Numbers.Primes (primes) orbita :: Integer -> [Integer] orbita n = [k | k <- enteros, k^2 - k*n >= 0, esCuadrado (k^2 - k*n)] -- entero es la lista de los números enteros. Por ejemplo, -- λ> take 20 enteros -- [0,-1,1,-2,2,-3,3,-4,4,-5,5,-6,6,-7,7,-8,8,-9,9,-10] enteros :: [Integer] enteros = 0 : concat [[-n,n] | n <- [1..]] -- (esCuadrado x) se verifica si x es un cuadrado perfecto. Por -- ejemplo, -- esCuadrado 16 == True -- esCuadrado 27 == False esCuadrado :: Integer -> Bool esCuadrado x = (raizEntera x)^2 == x -- (raizEntera x) es el mayor entero cuyo cuadrado es menor o igual que -- x. Por ejemplo, -- raizEntera 16 == 4 -- raizEntera 27 == 5 raizEntera :: Integer -> Integer raizEntera x = aux (1,x) where aux (a,b) | d == x = c | c == a = c | d < x = aux (c,b) | otherwise = aux (a,c) where c = (a+b) `div` 2 d = c^2 -- 1ª definición de orbitaDePrimo -- ============================== orbitaDePrimo1 :: Integer -> [Integer] orbitaDePrimo1 2 = take 2 (orbita 2) orbitaDePrimo1 p = take 4 (orbita p) -- 2ª definición de orbitaDePrimo -- ============================== -- Basada en los siguientes cálculos -- orbitaDePrimo1 2 == [0,2] -- orbitaDePrimo1 3 == [0,-1,3,4] -- orbitaDePrimo1 5 == [0,-4,5,9] -- orbitaDePrimo1 7 == [0, 7, -9, 16] -- orbitaDePrimo1 11 == [0,11, -25, 36] -- orbitaDePrimo1 13 == [0,13, -36, 49] -- orbitaDePrimo1 17 == [0,17, -64, 81] -- orbitaDePrimo1 19 == [0,19, -81,100] -- orbitaDePrimo1 23 == [0,23,-121,144] orbitaDePrimo2 :: Integer -> [Integer] orbitaDePrimo2 p | p == 2 = [0,2] | p <= 5 = [0, -((p-1) `div` 2)^2, p, ((p+1) `div` 2)^2] | otherwise = [0, p, -((p-1) `div` 2)^2, ((p+1) `div` 2)^2] -- Comprobación de equivalencia -- ============================ -- La comprobación es -- λ> and [orbitaDePrimo1 n == orbitaDePrimo2 n | n <- take 30 primes] -- True -- Comparación de eficiencia -- ========================= -- La comparación es -- λ> orbitaDePrimo1 (primes !! 100) -- [0,547,-74529,75076] -- (4.94 secs, 4,471,368,256 bytes) -- λ> orbitaDePrimo2 (primes !! 100) -- [0,547,-74529,75076] -- (0.01 secs, 302,096 bytes)