Добрый день, Аркадий!

Прошу прощения за некропостинг, но на письмо отвечу.

Я остановился на 40 000, поскольку решето Эратосфена на Рефале оказалось сильно 
медленным, и его время растёт нелинейно от длины исходного списка. Причём, мне 
показалось, что даже квадратично. Поэтому результата в 176 100 я просто не 
дождусь.

Время я замерял для переславской реализации Рефала-5. Рефал-5λ сильно медленнее 
(в разы), поэтому мне стыдно было показывать эти числа 😳.

 

В последующей переписке Антон Орлов продолжил оффтопик, мне уже лень пытаться 
переписывать его примеры на Рефал.

 

С уважением,
Александр Коновалов

 

From: Arkady Klimov arkady.klimov_AT_gmail.com [mailto:refal@botik.ru] 
Sent: Thursday, October 10, 2019 4:50 PM
To: refal@botik.ru
Subject: Re: Список всех простых чисел

 

Александр, а можно попросить вас пропустить вариант для 176100 вместо 40000 - 
тогда результаты (времена) будут сопоставимы.

Я подумал еще об одной оптимизации. Сейчас произведение простых формируется 
сразу, а ведь оно может и не понадобиться.

То есть для последнего "поколения" эта работа лишняя.

Наверно, лучше накапливать в виде списка, а при подаче на Filter для следующего 
шага все перемножить.

Интересно, для Хаскела это тоже актуально, или там умножение pp*n ленивое?

А еще хотелось бы посмотреть статистику по числу (доле) отсеянных (прошедших) 
через каждый из фильтров (это мне уже как математику интересно).

И соответствующие значения lim.

Я так понимаю, что количество поколений здесь 4-5, да?

Аркадий

 

ср, 9 окт. 2019 г. в 13:13, Александр Коновалов a.v.konovalov87_AT_mail.ru 
<http://a.v.konovalov87_AT_mail.ru>  <refal@botik.ru <mailto:refal@botik.ru> >:

Добрый день всем!

Нужно спасать рассылку от офтопа.

Переписал исходник Сергея Михайловича на Рефал-5. Функции primesE, primesAD и 
primesA переписаны максимально близко к тексту, ради этого пришлось ввести 
функции filter, o (композиция функций), bind-right (чтобы связать Mod со вторым 
аргументом), eq и neq.

Рефал не поддерживает ленивые вычисления и бесконечные списки, поэтому все 
функции на входе принимают последовательность чисел от 2 до 40 000.

Понятно, что вызов <filter (o ((neq 0) (bind-right (Mod s.n)))) e.ns> на Рефале 
будет выполняться медленно. Поэтому я также написал оптимизированные версии 
primesE-opt и primesA-opt, в которых фильтрация выполняется не функцией высшего 
порядка, а специально написанной функцией. Функция primesE в этом случае 
ускорилась на порядок, primesA — незначительно.

Замеры времени есть в исходнике. Масштаб величин примерно такой же: primesE на 
порядок медленнее primesAD, primesAD на порядок медленнее primesA. Функции 
primesE-opt и primesAD требуют одинакового времени работы, но первая делает 
гораздо больше шагов. Причина этого расхождения, по-видимому, в длинной 
арифметике, в вычислении gcd(pp, n), поскольку pp — длинное число. 

 

С уважением,
Александр Коновалов

 

-----Original Message-----
From: Sergei M. Abramov abram_AT_botik.ru <refal@botik.ru 
<mailto:refal@botik.ru> > 
Sent: Tuesday, October 8, 2019 10:29 PM
To: refal@botik.ru <mailto:refal@botik.ru> 
Subject: Список всех простых чисел

 

День добрый, всем!

 

Простите, что не про Рефал.  Просто не могу вспомнить то, что (как мне 
помнится) случилось в обстановке рефал-компании на заре моей профессиональной 
деятельности (практика в НИЦЭВТе или работа в нем).

 

По каким-то причинам я задумался тогда над построением списка всех простых 
чисел.  И в некий момент сам придумал алгоритм, которрый опирался вот на какое 
определение последовательности простых чисел:

 

1.  Очередное натуральное число n будет простым, если оно взаимнопросто со 
всеми ранее найдеными простыми числами.

 

или (что то же самое, но уже совсем близко к коду)

 

2.  Очередное натуральное число n -- простое, если gcd(pp,n)==1, где pp -- 
произведение всех ранее найденых простых чисел.

 

Понятно, что нужна сверхдлинная целочисленная арифметика.  Но,

gcd(pp,n) обещал посчитаться быстрее, чем деление n по очереди на все 
сомножители из pp.

 

Я этот алгоритм (точнее подход, поскольку сам алгоритм похитрее, о нем в конце) 
придумал сам и очень этим гордился.  Но потом в рефал-компании кто-то мне дал 
книжку.  Серегей Романенко?  Андрей или Алик Климов?  Колля Кондратьев?  -- не 
помню.

 

Книжка была кого-то из великих...  Дейскстра?  Вирт?  И, почему-то, мне 
кажется, что называлась она "Записки из башни слоновой кости".  А в книжке, как 
мне сегодня кажется, были программистсткие побасенки.

 

Ну, и был коротенький шутливый этюд (близко к тексту):

 

================  Цитата по памяти ===============================
Для эффективной генерации всех простых чисел мнe достаточно всего двух ячеек 
памяти:

 

integer pp, n;

n  := 2;

pp := 1;

while ( True ) do begin

   if ( gcd(pp, n)=1 ) then begin

      println(n);

      pp := pp * n;

   end;

   n := n + 1;

end;

==================================================================

 

С тех пор я узнал, что хотя я и самостоятельно нашел такой подход к генерации 
простых, но я был не единственным (и, скорее всего, не

первым)

 

ПРОСЬБА О ПОМОЩИ:

 

1.  Коллеги, если кто-то может мне дать имя автора, название книги, которая мне 
помнится, то я буду благодарен.

 

2.  И если есть еще какие-либо ссылки на такой подход к проверке простоты -- 
gcd(pp, n)=1,-- то тоже полезно.

 

Почему вспомнил?  Вспомнил я про эту историю во время очередной своей лекции по 
Хаскеллю в ЯрГУ.  Ну, и сегодня написал немного строк на Хаскелле -- приложены. 
 Взгляните, для интереса.

 

primesAD -- это генератор, прямо в лоб переписан приведенный выше 
паскале-подобный текст.

 

А теперь поговорим про решето.  Решето вообще (не обязательно

Эратосфена) -- это когда берем начальное пространство поиска -- например, 
[2..].  И дальше всегда делаем такую пару операций:

 

1.  Некие первые элементы (один или больше) в текущем прастранстве поиска -- 
заведомо простые числа -- выдаем их в результат.

 

2.  Затем при помощи только что найденых простых фильтруем (сужаем) 
пространство поиска.

 

Если брать только одно простое n из пространства поиска и фильтровать 
предикатом ((/=0).(`mod`n)) -- то это решето Эратосфена.

 

А если брать много заведомо простых из пространства поиска, вычислять их 
произведение pp и фильтровать предикатом ((==1).(gcd pp)) -- то это решето ...  
назову решетом Абрамова ;-) Пока Вы мне не подскажете другого автора такого же 
подхода (или где искать).

 

Три остальные программки в Хаскелле -- это разные варианты решета:

 

primesE, primesE1 -- решето Эратосфена (отличии в изобразительных средствах).

 

primesА -- решето Абрамова.

 

А заканчивается файл статистикой (время счета и память) прогона некоторых 
тестов в HUGSе и в GHCi.

 

Посмотрите статистику...  Шуточный этюд "достаточно две ячейки памяти"

имеет нешуточное приложение, как мне кажется ;-)

 

Я уж молчу про то, что gcd по Евклиду (как оно описано в прелюдии

хаскелля) не самая эффективная реализация gcd (по Кнуту).

 

Всего доброго,

 

Сергей Абрамов




 

-- 

_______________

С уважением, 

Аркадий Климов,
с.н.с. ИППМ РАН,
+7(499)135-32-95
+7(916)072-81-48

  • Спи... Sergei M. Abramov
    • ... Александр Коновалов a . v . konovalov87_AT_mail . ru
      • ... Arkady Klimov arkady . klimov_AT_gmail . com
        • ... Sergei M. Abramov
          • ... Andrei Klimov andrei_AT_klimov . net
          • ... Sergei M. Abramov
          • ... Arkady Klimov arkady . klimov_AT_gmail . com
            • ... Sergei M. Abramov
              • ... Anton Orlov orlovan_AT_gmail . com
                • ... Sergei M. Abramov
        • ... Александр Коновалов a . v . konovalov87_AT_mail . ru
          • ... Sergei M. Abramov
            • ... Boyko Bantchev boykobb_AT_gmail . com
              • ... Александр Коновалов a . v . konovalov87_AT_mail . ru
                • ... Boyko Bantchev boykobb_AT_gmail . com

Ответить