PI π Расчет системы загрузки - PullRequest
0 голосов
/ 01 декабря 2018

спасибо, что нашли время, чтобы прочитать и (надеюсь) ответить на мой вопрос!Недавно я заинтересовался Pi (π не съедобный тип, я его уже обожаю!) И был заинтригован в расчете такого числа, я могу бегло печатать на умеренно продвинутом Python и я опытный пользователь Linux, поэтому я настроил"кластер" старых (ish) компьютеров.после некоторого копания я нашел программу на python, которая вычисляет число pi, отредактировал и сделал вывод в файл, запустил его на одном из компьютеров, и он работает потрясающе, в настоящее время он составляет около 2 миллионов цифр числа pi (крошечный по сравнению смировой рекорд 22,7 трлн!) и использует 100% ядер и 94% оперативной памяти, моя единственная проблема в том, что я не могу отменить процесс или начать все сначала, я пытаюсь понять алгоритм, чтобы я могкод в функции загрузки.функция загрузки должна открыть файл и продолжить вычисление числа пи с этого момента.Я могу немного понять алгоритм и понял, что он использует уже рассчитанные числа Пи, чтобы вычислить цифры (что объясняет снижение скорости), и поэтому возможна загрузка предварительно рассчитанных данных.Код выглядит следующим образом:

import sys


def calcPi():
    q, r, t, k, n, l = 1, 0, 1, 1, 3, 3
    while True:
        if 4*q+r-t < n*t:
            yield n
            nr = 10*(r-n*t)
            n  = ((10*(3*q+r))//t)-10*n
            q  *= 10
            r  = nr
        else:
            nr = (2*q+r)*l
            nn = (q*(7*k)+2+(r*l))//(t*l)
            q  *= k
            t  *= l
            l  += 2
            k += 1
            n  = nn
            r  = nr

pi_digits = calcPi()
i = 0
for d in pi_digits:
    sys.stdout =open("piDigits.txt", "a")
    sys.stdout.write(str(d))
    i += 1
    if i == 50:
        print("")
        i = 0

Если бы кто-нибудь мог помочь мне найти способ загрузки предварительно рассчитанных цифр числа Пи и продолжить вычисление оттуда или объяснить мне алгоритм / код, я бы хотелбыть чрезвычайно благодарным!Заранее спасибо.-Лео Корнелиус

Ответы [ 2 ]

0 голосов
/ 02 декабря 2018

Что вам нужно, это сбросить и восстановить все состояние генератора calcPi.К счастью для вас все состояние указано явно в первой строке.Вот прототип, чтобы показать вам идею:

import sys
import os.path


def calcPi(state=None):
    if state is None:
        q, r, t, k, n, l = 1, 0, 1, 1, 3, 3
        skip_first = False
    else:
        q, r, t, k, n, l = state
        skip_first = True
    while True:
        if 4 * q + r - t < n * t:
            # have to skip the first yield in the "restore state" scenario because
            # this is the same we returned the last time from this state
            if not skip_first:
                state = q, r, t, k, n, l
                yield n, state
            else:
                skip_first = False
            nr = 10 * (r - n * t)
            n = ((10 * (3 * q + r)) // t) - 10 * n
            q *= 10
            r = nr
        else:
            nr = (2 * q + r) * l
            nn = (q * (7 * k) + 2 + (r * l)) // (t * l)
            q *= k
            t *= l
            l += 2
            k += 1
            n = nn
            r = nr


initial_state = None
total_digit_cnt = 0
buf_digit_cnt = 0
state_file_name = "piState.txt"
if os.path.isfile(state_file_name):
    with open(state_file_name, "r+") as stateF:
        lines = stateF.readlines()
        if len(lines) > 0:
            last_line = lines[-1]
            # truncate the old state and save only the few last last lines
            stateF.seek(0)
            stateF.truncate(0)
            stateF.write(lines[-3])
            stateF.write(lines[-2])
            stateF.write(last_line)
            initial_state = map(long, last_line.replace('(', '').replace(')', '').split(','))
            total_digit_cnt = initial_state[-1]
            initial_state = initial_state[:-1]

if initial_state is not None:
    print str((total_digit_cnt, initial_state))

pi_digits = calcPi(initial_state)
buf = ""
state_cnt = 0
with open("piDigits.txt", "a") as outF:
    with open(state_file_name, "a+") as stateF:
        for digit, state in pi_digits:
            buf += str(digit)
            buf_digit_cnt += 1
            total_digit_cnt += 1

            if buf_digit_cnt == 500:
                print "Start dumping state %d" % state_cnt
                buf_digit_cnt = 0
                outF.write(buf)
                buf = ""
                outF.write("\n")
                outF.flush()
                # as states take much more space, clear old states
                state_cnt += 1
                if state_cnt % 50 == 0:
                    stateF.seek(0)
                    stateF.truncate(0)
                stateF.write(str((state, total_digit_cnt)) + "\n")
                stateF.flush()
                print "End dumping state %d" % state_cnt

Идея состоит в том, чтобы возвращать не только следующую цифру, но и все состояние из генератора и периодически выгружать его в другой файл.Это всего лишь прототип.В реальном коде для обработки миллионов цифр вы, вероятно, захотите вывести состояние по времени, прошедшему с момента последнего дампа, а не по количеству, поскольку вычисление каждой следующей цифры, вероятно, будет становиться все медленнее и медленнее.Однако это усложняет код восстановления для отслеживания большего количества деталей (например, сколько цифр фактически было записано в последней строке?), Поэтому я не поместил его в PoC.

0 голосов
/ 01 декабря 2018

Код, который вы используете, содержит генератор.Это функция с оператором yield.Что они делают, так это возвращают значение при вызове, а затем ждут, пока они будут вызваны снова, обычно в цикле, прежде чем вычислять следующее значение и затем получать его.Поскольку вы вычисляете бесконечное число в бесконечном цикле, программа будет работать до тех пор, пока вы ее не уничтожите, а затем вы потеряете состояние.Поэтому вам нужен способ сохранения состояния.

Я бы порекомендовал вам реализовать итератор для замены генератора.Итератор похож на генератор, но вместо того, чтобы быть функцией, он является объектом.Так что у него есть состояние.То есть, вы можете сохранить текущее значение всех этих переменных (nr, nn, q и т. Д.) Как переменные «экземпляра».Затем, когда вы хотите завершить работу, вы можете сохранить текущее состояние класса, используя библиотеку 'pickle'.Затем, чтобы продолжить сценарий с того места, где он остановился, вы загружаете файл pickle, чтобы восстановить объект в точности так, как он был до завершения программы.

...