Метод Герона в Python

Метод Герона генерирует последовательность чисел, которые представляют все более и более точные приближения для √ п. Первое число в последовательности является произвольным предположением; каждое второе число в последовательности получается из предыдущего числа prev по формуле:

    (1/2)*(prev+n/prev)

Я должен написать функцию heron(), которая принимает на вход два числа: n и ошибка. Функция должна начинаться с начального предположения 1,0 для √n, а затем многократно генерировать лучшие приближения до тех пор, пока разница (точнее, абсолютное значение разницы) между последовательными приближениями не более чем ошибка.

    usage:
    >>> heron(4.0, 0.5)
    2.05
    >>> heron(4.0, 0.1)
    2.000609756097561

это немного сложно, но мне нужно будет отслеживать четыре переменные:

    # n, error, prev and current

Мне также понадобится цикл while с условием:

    ((current - prev) > error):

Общее правило для цикла while таково:

    # old current goes into new prev

Итак, это то, что я получил до сих пор, это немного, потому что для начала я не знаю, как включить оператор 'if' в цикл while.

def heron(n, error):
    guess = 1
    current = 1
    prev = 0
    while (current - prev) > error:
        previous==1/2*(guess+n/guess):
           print (previous) # just a simple print statement
                            # in order to see what i have so far

Может кто-нибудь дать мне несколько указателей в правильном направлении, пожалуйста?

благодарю вас


person Snarre    schedule 17.05.2013    source источник
comment
Пожалуйста, будьте конкретны в своем вопросе. Что вам нужно?   -  person zw324    schedule 18.05.2013
comment
Ну, это сложно, я думаю, мне нужно найти способ заставить цикл while применять формулу с результатом, полученным в предыдущем цикле. поэтому допустим, что в первом цикле результат был 3, и допустим, что n равно 5. тогда новая формула должна выглядеть так: 1/2 * (3 + 5/3), что = 2,33333333333333335, и это число теперь входит в формулу в следующем цикле, пока условие больше не будет выполняться. Я просто не могу заставить цикл while работать так.   -  person Snarre    schedule 18.05.2013
comment
@Snarre, пожалуйста, пометьте ответ как принятый, если он вам помог.   -  person elyase    schedule 24.05.2013


Ответы (5)


Если вы не хотите использовать генераторы, то самым простым будет:

def heron(n, error):
    prev, new = 1.0, 0.5 * (1 + n)
    while abs(new - prev) > error:
        prev, new = new, 0.5 * (new + n/new)
    return new

Вы также можете сгенерировать «бесконечную» последовательность номеров цапель:

def heron(n):
    prev = 1.0
    yield prev, float('inf')
    while True:
        new = 0.5 * (prev + n/prev)
        error = new - prev
        yield new, error
        prev = new

Теперь вы можете вывести сколько угодно чисел, например:

list(islice(heron(2), 3))     # First 3 numbers and associated errors

Генерировать до тех пор, пока ошибка больше 0,01:

list(takewhile(lambda x:x[1] > 0.01, heron(2)))
person elyase    schedule 17.05.2013

Просто чтобы опираться на ответ @elyase, вот как вы можете получить квадратный корень произвольной точности из генератора чисел цапли, который они предоставили. (генератор просто выдает следующее число в последовательности цапель)

def heron(n): ### posted by elyase
    a = 1.0
    yield a
    while True:
        a = 0.5 * (a + n/a)
        yield a

def sqrt_heron(n, err):
    g = heron(n)
    prev = g.next()
    current = g.next()
    while( (prev - current) > err):
        prev = current
        current = g.next()
        print current, prev
    return current

print sqrt_heron(169.0,0.1)

Помимо синтаксиса Python, вещь, которая может вас запутать, заключается в том, что вам нужны два предположения, вычисленные из вашего первоначального предположения, чтобы начать, и вы сравниваете, насколько далеко друг от друга эти два предположения. Условие while должно быть (prev - current) > err, а не (current - prev) > err, поскольку мы ожидаем, что предыдущее предположение будет ближе к квадрату (и, следовательно, больше), чем текущее предположение, которое должно быть ближе к квадратному корню. Поскольку начальным предположением может быть любое положительное число, нам нужно вычислить две итерации от него, чтобы гарантировать, что current будет меньше prev.

person qwwqwwq    schedule 18.05.2013

Другие ответы, которые я пишу, используют функцию генератора Python. Я люблю генераторы, но они излишни для этой простой задачи. Ниже решения с простыми while циклами.

Комментарии под кодом. heron0() это то, что вы просили; heron() - моя предложенная версия.

def heron0(n, error):
    guess = 1.0
    prev = 0.0
    while (guess - prev) > error:
        prev = guess
        guess = 0.5*(guess+n/guess)
        print("DEBUG: New guess: %f" % guess)
    return guess

def _close_enough(guess, n, allowed_error):
    low = n - allowed_error
    high = n + allowed_error
    return low <= guess**2 <= high

def heron(n, allowed_error):
    guess = 1.0
    while not _close_enough(guess, n, allowed_error):
        guess = 0.5*(guess+n/guess)
        print("DEBUG: New guess: %f" % guess)
    return guess

print("Result: %f" % heron0(4, 1e-6))
print("Result: %f" % heron(4, 1e-6))

Комментарии:

  • Вам действительно не нужны оба guess и current. Вы можете использовать guess, чтобы сохранить текущее предположение.

  • Я не знаю, почему вы спрашивали о включении оператора if в цикл while. Во-первых, это просто: вы просто вставляете его и делаете отступ для операторов, которые находятся под if. Во-вторых, этой задаче это не нужно.

  • Легко и быстро определить, близко ли guess к prev. Но я думаю, что для численной точности было бы лучше напрямую проверить, насколько хорош квадратный корень guess. Итак, возведите в квадрат значение guess и посмотрите, близко ли оно к n. Посмотрите, как в Python разрешено проверять, является ли значение одновременно большим или равным меньшему значению, а также меньшим или равным высокому значению. (Альтернативный способ проверки: abs(n - guess**2) <= allowed_error)

  • В Python 2.x, если вы разделите целое число на целое число, вы, вероятно, получите целочисленный результат. Таким образом, 1/2 вполне может иметь результат 0. Есть несколько способов исправить это, или вы можете запустить свою программу на Python 3.x, которая гарантирует, что 1/2 возвращает 0.5, но просто сделать начальное значение для guess числом с плавающей запятой.

person steveha    schedule 18.05.2013

Я думаю, что это соответствует вашим требованиям (примечание: я написал это с помощью python 2.7.10): он не предполагает догадку 1 и принимает «число» и «допуск» в качестве аргументов для «n» и «ошибка». Кроме того, он не использует переменные «предыдущий» и «текущий» или цикл while — это часть ваших требований или ваши мысли относительно решения?

def heron(num, guess, tolerance):
    if guess**2 != num:
        ##print "guess =", guess
        if abs(float(num) - float(guess)**2) > float(tolerance):
            avg_guess = 0.5 * (float(guess) + (float(num) / float(guess)))
            return heron(num, avg_guess, tolerance)
        print "Given your tolerance, this is Heron's best guess:", guess
    else:
        print guess, "is correct!"

Раскомментируйте команду печати, если хотите увидеть ход догадок.

person MmmHmm    schedule 04.04.2016

Я имел дело с той же проблемой и не так много инструментов для ее решения, так как мои знания в Python очень ограничены.
Я придумал это решение, которое не очень элегантно и продвинуто, но оно решает проблему с помощью алгоритма Герона. Просто хочу поделиться этим здесь:

print("Please enter a positive integer 'x' to find its square root.")
x = int(input("x ="))
g = int(input("What's your best guess: "))
results = [g]
if g * g == x:
    print("Good guess! The square root of", x, "is", g)
else:
    g = (g + (x / g)) / 2
    results.append(g)
    while results[-1] != results[-2]:
        g = (g + (x / g)) / 2
        results.append(g)
    else:
        print(results)
        print("Not quite. The square root of", x, "is", results[-1])
person Toshiro Nifume    schedule 05.06.2020