Ir al contenido principal

Distancia esperada entre dos puntos de un cuadrado unitario

Definir, por simulación, la función

distanciaEsperada :: Int -> Double

tal que (distanciaEsperada n) es la distancia esperada entre n puntos del cuadrado unitario de vértices opuestos (0,0) y (1,1), elegidos aleatoriamente. Por ejemplo,

distanciaEsperada 10    ==  0.4815946544198219
distanciaEsperada 10    ==  0.5558438642543654
distanciaEsperada 100   ==  0.5699663553203216
distanciaEsperada 100   ==  0.5085629461572269
distanciaEsperada 1000  ==  0.5376963424746385
distanciaEsperada 1000  ==  0.523432374720393

Nota. El valor exacto de la distancia esperada es

(sqrt(2) + 2 + 5*log(1+sqrt(2)))/15 = 0.5214054331647207

Soluciones

import System.Random
import System.IO.Unsafe

-- (aleatorio a b) es un número aleatorio entre a y b. Por ejemplo,
--    λ> aleatorio 0 1000
--    681
--    λ> aleatorio 0 1000
--    66
aleatorio :: Random t => t -> t -> t
aleatorio a b = unsafePerformIO $
                getStdRandom (randomR (a,b))

-- (aleatorios m n) es una lista infinita de números aleatorios entre m y
-- n. Por ejemplo,
--    λ> take 20 (aleatorios 2 9)
--    [6,5,3,9,6,3,6,6,2,7,9,6,8,6,2,4,2,6,9,4]
--    λ> take 20 (aleatorios 2 9)
--    [3,7,7,5,7,7,5,8,6,4,7,2,8,8,2,8,7,6,5,5]
--    λ> take 3 (aleatorios 0 1.0)
--    [0.7808059324830976,0.13619706746099292,0.2348891848186122]
aleatorios :: Random t => t -> t -> [t]
aleatorios m n = aleatorio m n : aleatorios m n

type Punto = (Double,Double)

-- (puntosDelCuadrado n) es una lista de n puntos del cuadrado
-- unitario de vértices opuestos (0,0) y (1,1). Por ejemplo,
--    λ> puntosDelCuadrado 3
--    [(0.10932257643522625,0.7099956121231793),
--     (0.16098424598126437,0.5581017987539308),
--     (0.6774875277724967, 0.8870082327978139)]
--    λ> puntosDelCuadrado 3
--    [(0.6344417902106956, 0.24924560438268484),
--     (0.1094807024051736, 0.9341963885040684),
--     (0.33330496979798485,0.18440873262644397)]
puntosDelCuadrado :: Int -> [Punto]
puntosDelCuadrado n =
  take n (zip (aleatorios 0.0 1.0) (aleatorios 0.0 1.0))

-- (distancia p1 p2) es la distancia entre los puntos p1 y p2. Por
-- ejemplo,
--    distancia (0,0) (3,4)  ==  5.0
distancia :: Punto -> Punto -> Double
distancia (x1,y1) (x2,y2) = sqrt ((x1-x2)^2+(y1-y2)^2)

-- (distancias ps) es la lista de las distancias entre los elementos 1º
-- y 2º, 3º y 4º, ... de ps. Por ejemplo,
--    distancias [(0,0),(3,4),(1,1),(7,9)]  ==  [5.0,10.0]
distancias :: [Punto] -> [Double]
distancias []         = []
distancias (p1:p2:ps) = distancia p1 p2 : distancias ps

-- (distanciaEsperada n) es la distancia esperada entre n puntos
-- aleatorios en el cuadrado unitario. Por ejemplo,
--    distanciaEsperada 10    ==  0.4815946544198219
--    distanciaEsperada 10    ==  0.5558438642543654
--    distanciaEsperada 100   ==  0.5699663553203216
--    distanciaEsperada 100   ==  0.5085629461572269
--    distanciaEsperada 1000  ==  0.5376963424746385
--    distanciaEsperada 1000  ==  0.523432374720393
distanciaEsperada :: Int -> Double
distanciaEsperada n = sum ds / fromIntegral n
    where ps = puntosDelCuadrado (2*n)
          ds = distancias ps