Первичный номер для хранения больших жестких дисков - Сито Аткина

Я реализовал Сито Аткина, и он отлично работает до простых чисел около 100 000 000 или около того. Помимо этого, он ломается из-за проблем с памятью.

В алгоритме я хочу заменить массив на основе массива на массив на жестком диске. Функции файла Python "wb" и функции Seek могут делать трюк. Прежде чем я пойду изобретать новые колеса, может ли кто-нибудь предложить совет? С самого начала появляются два вопроса:

  • Есть ли способ "обрезать" сито Аткина для работы с сегментом в памяти и
  • Есть ли способ приостановить действие и вернуться к нему позже - предлагая мне сериализовать переменные памяти и восстановить их.

Почему я это делаю? Старый geezer ищет развлечение и поддерживать лапшу.

Ответ 1

Реализация SoA в Python звучит весело, но обратите внимание, что, вероятно, на практике это будет медленнее, чем SoE. Для некоторых хороших монолитных реализаций SOE см. fooobar.com/questions/14495/.... Это может дать вам некоторое представление о скорости и использовании памяти очень простых реализаций. Версия numpy будет ресеть до 10 000 М на моем ноутбуке.

То, что вы действительно хотите, это сегментированное сито. Это позволяет ограничить использование памяти до некоторого разумного предела (например, 1M + O (sqrt (n)), и последнее может быть уменьшено при необходимости). Хорошее обсуждение и код на С++ показано на primesieve.org. Вы можете найти другие примеры в Python. primegen, реализация Bernstein в реализации SoA реализована как сегментированное сито (ваш вопрос 1: Да, SoA может быть сегментирован). Это тесно связано (но не идентично) с просеиванием диапазона. Так мы можем использовать сито для нахождения простых чисел между 10 ^ 18 и 10 ^ 18 + 1е6 за долю секунды - мы, конечно же, не просеиваем все числа до 10 ^ 18 + 1е6.

Вовлечение жесткого диска - IMO, движение в неправильном направлении. Мы должны иметь возможность просеивать быстрее, чем мы можем считывать значения с диска (по крайней мере, с хорошей реализацией C). Дистанционное и/или сегментированное сито должно делать то, что вам нужно.

Есть лучшие способы сделать хранилище, что поможет некоторым. Мой SoE, как и некоторые другие, использует колесо mod-30, поэтому имеет 8 кандидатов на 30 целых чисел, поэтому использует один байт на 30 значений. Похоже, что Bernstein SoA делает что-то подобное, используя 2 байта на 60 значений. Реализации python RWH не совсем там, но достаточно близки к 10 бит на 30 значений. К сожалению, похоже, что собственный массив bool Python использует около 10 байт на бит, а numpy - байт на бит. Либо вы используете сегментированное сито и не слишком беспокоитесь об этом, либо находите способ быть более эффективным в хранилище Python.

Ответ 2

Прежде всего, вы должны убедиться, что вы храните свои данные эффективным образом. Вы можете легко хранить данные до 100 000 000 простых чисел в 12,5 МБ памяти с помощью растрового изображения, пропуская очевидные простые числа (четные числа и т.д.), Вы могли бы сделать представление еще более компактным. Это также помогает при хранении данных на жестком диске. Вы попадаете в беду на 100 000 000 простых чисел, что вы не храните данные эффективно.

Некоторые подсказки, если вы не получите лучшего ответа.

1.Есть ли способ "вырезать" сито Аткина для работы с сегментом в памяти.

Да, для части, подобной Eratosthenes, вы можете запустить несколько элементов в списке ситов в "parallell" (по одному блоку за раз) и таким образом минимизировать доступ к диску.

Первая часть несколько сложнее, вам нужно будет обработать 4*x**2+y**2, 3*x**2+y**2 и 3*x**2-y**2 в более упорядоченном порядке. Один из способов состоит в том, чтобы сначала вычислить их, а затем отсортировать числа, есть алгоритмы сортировки, которые хорошо работают на диске (все еще O (N log N)), но это повредит временной сложности. Лучшим способом было бы перебрать по x и y таким образом, чтобы вы запускали по блоку за раз, так как блок определяется интервалом, который вы могли бы, например, просто перебрать по всем x и y такое, что lo <= 4*x**2+y**2 <= hi.

2. Есть способ приостановить действие и вернуться к нему позже - предлагая мне сериализовать переменные памяти и восстановить их

Чтобы достичь этого (независимо от того, как и когда программа завершается), вы должны сначала регистрировать обращения к диску (fx использовать базу данных SQL для хранения данных, но с осторожностью вы можете сделать это самостоятельно).

Во-вторых, поскольку операции в первой части не являются безусловными, вы должны убедиться, что вы не повторяете эти операции. Однако, поскольку вы будете запускать этот блок-блок за блоком, вы можете просто определить, какой последний обработанный блок и возобновить его (если вы можете получить частично обработанный блок, вы просто отбросите это и повторите этот блок). Для части Erastothenes это неправдоподобно, чтобы вы могли просто пробежать все это, но для увеличения скорости вы могли сохранить список произведенных простых чисел после того, как просеивание их было сделано (так что вы возобновляете с просеиванием после последнего произведенного штриха).

В качестве побочного продукта вы даже можете создать программу таким образом, чтобы она могла сохранять данные с первого шага, даже когда второй шаг работает, и тем самым в более поздний момент, расширяя лимит, продолжая первый шаг, а затем повторить второй шаг. Возможно, даже если у вас есть две программы, где вы завершаете первый, когда вы устали от него, а затем подайте его на выход в часть Eratosthenes (тем самым не нужно определять предел).

Ответ 3

Вы можете попробовать использовать обработчик signal, чтобы поймать, когда ваше приложение завершено. Это может затем сохранить ваше текущее состояние перед завершением. Следующий script показывает простое числовое число, продолжающееся при его перезапуске.

import signal, os, cPickle

class MyState:
    def __init__(self):
        self.count = 1

def stop_handler(signum, frame):
    global running
    running = False

signal.signal(signal.SIGINT, stop_handler)
running = True
state_filename = "state.txt"

if os.path.isfile(state_filename):
    with open(state_filename, "rb") as f_state:
        my_state = cPickle.load(f_state)
else:
    my_state = MyState()

while running:
    print my_state.count
    my_state.count += 1

with open(state_filename, "wb") as f_state:
    cPickle.dump(my_state, f_state)

Что касается улучшения записи на диск, вы можете попробовать экспериментировать с увеличением буферизации собственных файлов Python буфером размером 1 МБ или более, например. open('output.txt', 'w', 2**20). Использование обработчика with также должно гарантировать, что ваш файл будет очищен и закрыт.

Ответ 4

Существует способ сжатия массива. Это может стоить некоторой эффективности в зависимости от интерпретатора python, но вы сможете сохранить больше памяти, прежде чем прибегать к дискам. Если вы выполняете поиск в Интернете, вы, вероятно, найдете другие ситовые реализации, которые используют сжатие.

Пренебрегая сжатием, один из самых простых способов сохранения памяти на диске будет состоять из файла с отображением памяти. Python имеет mmap модуль, который обеспечивает функциональность. Вам нужно будет кодировать и из необработанных байтов, но это довольно просто, используя модуль struct.

>>> import struct
>>> struct.pack('H', 0xcafe)
b'\xfe\xca'
>>> struct.unpack('H', b'\xfe\xca')
(51966,)