Ir al contenido principal

Método de Herón para calcular la raíz cuadrada

El método de Herón para calcular la raíz cuadrada de un número se basa en las siguientes propiedades:

  • Si \(y\) es una aproximación de la raíz cuadrada de \(x\), entonces \[\frac{y+\frac{x}{y}}{2}\] es una aproximación mejor.
  • El límite de la sucesión definida por \begin{align} x_{0} &= 1 \newline x_{n+1} &= \frac{x_n+\frac{x}{x_n}}{2} \end{align} es la raíz cuadrada de x.

Definir la función

   raiz :: Double -> Double

tal que raiz x es la raíz cuadrada de x calculada usando la propiedad anterior con una aproximación de 0.00001 y tomando como valor inicial 1. Por ejemplo,

   raiz 9  ==  3.000000001396984

Soluciones

A continuación se muestran las soluciones en Haskell y las soluciones en Python.

Soluciones en Haskell

module Metodo_de_Heron_para_calcular_la_raiz_cuadrada where

import Test.QuickCheck
import Test.Hspec (Spec, hspec, it, shouldBe)

-- 1ª solución
-- ===========

raiz :: Double -> Double
raiz x = raizAux 1
  where raizAux y | aceptable y = y
                  | otherwise   = raizAux (mejora y)
        aceptable y = abs(y*y-x) < 0.00001
        mejora y    = 0.5*(y+x/y)

-- 2ª solución
-- ===========

raiz2 :: Double -> Double
raiz2 x = until aceptable mejora 1
  where aceptable y = abs(y*y-x) < 0.00001
        mejora y    = 0.5*(y+x/y)

-- Comprobación de equivalencia
-- ============================

-- La propiedad es
prop_raiz :: Positive Double -> Bool
prop_raiz (Positive x) =
  raiz x ~= sqrt x &&
  raiz2 x ~= sqrt x
  where
    a ~= b = abs (a-b) < 0.001

-- La comprobación es
--    λ> quickCheck prop_raiz
--    +++ OK, passed 100 tests.

-- Verificación
-- ============

verifica :: IO ()
verifica = hspec spec

spec :: Spec
spec = do
  it "e1" $
    raiz 9 `shouldBe`  3.000000001396984
  it "e2" $
    raiz2 9 `shouldBe`  3.000000001396984

-- La verificación es
--    λ> verifica
--
--    e1
--    e2
--
--    Finished in 0.0008 seconds
--    2 examples, 0 failures

Soluciones en Python

# 1ª solución
# ===========

def raiz(x : float) -> float:
    def aceptable(y: float) -> bool:
        return abs(y*y-x) < 0.00001
    def mejora(y: float) -> float:
        return 0.5*(y+x/y)
    def raizAux(y: float) -> float:
        if aceptable(y):
            return y
        return raizAux(mejora(y))
    return raizAux(1)

# 2ª solución
# ===========

def raiz2(x: float) -> float:
    def aceptable(y: float) -> bool:
        return abs(y*y-x) < 0.00001
    def mejora(y: float) -> float:
        return 0.5*(y+x/y)
    y = 1.0
    while not aceptable(y):
        y = mejora(y)
    return y

# Verificación
# ============

def test_raiz() -> None:
    assert raiz(9)  ==  3.000000001396984
    assert raiz2(9)  ==  3.000000001396984
    print("Verificado")

# La verificación es
#    >>> test_raiz()
#    Verificado