Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




На страницу Пред.  1 ... 4, 5, 6, 7, 8  След.
 Re: Точное количество простых чисел в интервале
Аватара пользователя
Нет, я пока с сегодняшней программой не разбирался. Продолжил возиться предыдущей версией и время существенно улучшил, действуя в некотором смысле наоборот. Грубо говоря, сначала нашёл nseg, затем лямбду:

(Не уменьшал, а увеличивал лямбду)

Код:
x=                  Нулей      Лямбда  Сегментов      |Platt - pi(x)|                Время

1000000000000       45000      0.00008       100          0.31946          4min,  1,523 ms
1000000000000       45000      0.00009       200          0.28642          3min, 38,045 ms
1000000000000       45000      0.00010       300          0.07089          3min, 19,845 ms
1000000000000       45000      0.00011       300          0.07336          3min,  1,169 ms
1000000000000       45000      0.00012       300          0.02808          2min, 52,673 ms
1000000000000       45000      0.00013       300          0.06626          2min, 41,329 ms
1000000000000       45000      0.00014       300          0.06944          2min, 27,725 ms
1000000000000       45000      0.00015       300          0.06361          2min, 25,542 ms
1000000000000       45000      0.00016       300          0.01556          2min, 20,693 ms
1000000000000       45000      0.00017       300          0.07810          2min, 10,201 ms
1000000000000       45000      0.00018       300          0.00858          2min,  4,651 ms
1000000000000       45000      0.00019       300          0.11393          2min,  5,056 ms
1000000000000       45000      0.00020       300          0.09194          2min,  1,546 ms
1000000000000       45000      0.00021       300          0.07540          1min, 52,210 ms
1000000000000       45000      0.00022       300          0.04057          1min, 49,172 ms
1000000000000       45000      0.00023       300          0.11425          1min, 51,446 ms
1000000000000       45000      0.00024       300          0.10044          1min, 53,050 ms
1000000000000       45000      0.00025       300          0.13505          1min, 44,113 ms
1000000000000       45000      0.00026       300          0.02716          1min, 37,662 ms
1000000000000       45000      0.00027       300          0.12467          1min, 38,691 ms
1000000000000       45000      0.00028       300          0.10477          1min, 42,295 ms
1000000000000       45000      0.00029       300          0.08366          1min, 45,348 ms
1000000000000       45000      0.00030       300          0.02732          1min, 41,093 ms
1000000000000       45000      0.00031       300          0.02589          1min, 36,984 ms
1000000000000       45000      0.00032       300          0.05201          1min, 30,949 ms
1000000000000       45000      0.00033       300          0.02480          1min, 26,527 ms
1000000000000       45000      0.00034       300          0.15210          1min, 27,875 ms
1000000000000       45000      0.00035       300          0.02856          1min, 31,717 ms
1000000000000       45000      0.00036       300          0.05715          1min, 33,362 ms
1000000000000       45000      0.00037       300          0.15788          1min, 34,138 ms
1000000000000       45000      0.00038       300          0.02834          1min, 35,642 ms
1000000000000       45000      0.00039       300          0.00048          1min, 36,616 ms
1000000000000       45000      0.00040       300          0.12627          1min, 37,747 ms

А затем уменьшал количество нулей:

Код:
x=                  Нулей      Лямбда  Сегментов      |Platt - pi(x)|                Время

1000000000000       40000      0.00033       300          0.02480          1min, 24,858 ms
1000000000000       35000      0.00033       300          0.02480          1min, 22,973 ms
1000000000000       30000      0.00033       300          0.02480          1min, 21,929 ms
1000000000000       25000      0.00033       300          0.02480          1min, 20,894 ms
1000000000000       20000      0.00033       300          0.02480          1min, 20,002 ms
1000000000000       15000      0.00033       300          0.02660          1min, 17,990 ms
1000000000000       14000      0.00033       300          0.03350          1min, 18,734 ms
1000000000000       13000      0.00033       300          0.03415          1min, 17,365 ms
1000000000000       12000      0.00033       300          0.06699          1min, 17,642 ms
1000000000000       11000      0.00033       300          0.17045          1min, 17,318 ms
1000000000000       10000      0.00033       300          0.30050          1min, 16,795 ms
1000000000000        9000      0.00033       300          0.88171          1min, 16,605 ms

И в итоге всё равно до ваших 69 секунд не добрался. Хотя, насколько помню, раньше мой комп был побыстрее вашего на разных тестах.

Может не стоит компилировать, а надо считать в интерпретаторе...

Я делал и такие сравнения:

В Убунте:

Код:
? #
   timer = 1 (on)
? primepi(10^12)
cpu time = 2min, 42,281 ms, real time = 2min, 42,496 ms.
%1 = 37607912018

В Винде:

Код:
? #
   timer = 1 (on)
? primepi(10^12)
time = 1min, 29,047 ms.
%1 = 37607912018

wrest в сообщении #1730859 писал(а):
Я не понял о чём этот вопрос и проигнорировал его.

О среднем вкладе дзета-нулей. Вы по ссылке прошли?

 Re: Точное количество простых чисел в интервале
wrest в сообщении #1730826 писал(а):
Код:
my(width = 10^6);
Это неправильно, не у всех предел таблицы простых оставлен по умолчанию, намного лучше так: my(width = default(primelimit));.

 Re: Точное количество простых чисел в интервале
Аватара пользователя
Кстати, вот ИИ был со мной не согласен. По его подсказке я нашёл константу A332645. И вот вроде как из неё получается похожая константа:

Код:
? 2*sqrt(0.02310499/Pi)
%9 = 0.171517

 Re: Точное количество простых чисел в интервале
А вот, кстати, и сложность $O(\sqrt{x})$
С жульничеством в виде предвычисленных нулей и некоторой таблицы простых но как есть уж:
Код:
? platt_pi(10^11,45340,0.0001268,500,5.0,0)
time = 15,523 ms.
4118054812.5273000831643713882480218902
? platt_pi(10^12,154278,4.468 e-5,500,5.0,0)
time = 55,486 ms.
37607912017.550705964941789851875733662
? platt_pi(10^13,508919,1.597 e-5,500,5.5,0)
time = 3min, 16,114 ms.
346065536838.85394245273471371805510235
?

Кстати primepi(10^13) в pari/gp мне дождаться на планшете вообще не удалось. Думаю, что больше часа.

И свысока смотрящий на это всё primecount:
Код:
~/primecount/build $ time ./primecount 10^11
4118054813

real    0m0.034s
user    0m0.062s
sys     0m0.026s
~/primecount/build $ time ./primecount 10^12
37607912018

real    0m0.047s
user    0m0.100s
sys     0m0.034s
~/primecount/build $ time ./primecount 10^13
346065536839

real    0m0.087s
user    0m0.271s
sys     0m0.053s
~/primecount/build $


-- добавлено через 9 минут --

Yadryara в сообщении #1730862 писал(а):
(Не уменьшал, а увеличивал лямбду)

У величивая лямбду вы увеличиваете размер решета, то есть смещаетесь из аналитической в переборную часть, нарушая заветы Платта. :D

 Re: Точное количество простых чисел в интервале
wrest в сообщении #1730899 писал(а):
И свысока смотрящий на это всё primecount:
Вы бы это, запускали бы его в один поток, что ли ... Параметром -t=1.
Ну и для показа времени у него есть параметр --time.

 Re: Точное количество простых чисел в интервале
Dmitriy40 в сообщении #1730881 писал(а):
wrest в сообщении #1730826 писал(а):
Код:
my(width = 10^6);
Это неправильно, не у всех предел таблицы простых оставлен по умолчанию, намного лучше так: my(width = default(primelimit));.

width это ширина окна для быстрого замера скорости, а замеряется она как раз правильно -- в районе primelimit для "быстрого" режима, затем вокруг 10*primelimit^2 то есть за таблицей для "среднего", и потом вокруг 2^63 для "медленного".
У Платта центр решета находится на конце интервала, то есть вот он когда вычислял $\pi(10^{24})$ то для вычисления поправки решетил диапазон шириной $10^{15}$ :от $10^{24}-5\cdot 10^{14}$ до $10^{24}+5\cdot 10^{14}$

-- добавлено через 4 минуты --

Dmitriy40 в сообщении #1730903 писал(а):
Вы бы это, запускали бы его в один поток, что ли ...

Так там же в показаниях времени есть user - это сумма по всем потокам. Заодно и коэффициент многопоточности видно.
Кстати в нормальном линуксе запуск через GNU time показывает ещё пик потребления памяти, на планшете с этим немного сложнее но тоже можно, так вот primecount потребляет мизер какой-то.

 Re: Точное количество простых чисел в интервале
wrest в сообщении #1730910 писал(а):
а замеряется она как раз правильно -- в районе primelimit
Да, извините, проглядел буквально строкой выше. :facepalm:

wrest в сообщении #1730910 писал(а):
Так там же в показаниях времени есть user - это сумма по всем потокам. Заодно и коэффициент многопоточности видно.
ОК.

 Re: Точное количество простых чисел в интервале
Yadryara в сообщении #1730862 писал(а):
О среднем вкладе дзета-нулей. Вы по ссылке прошли?

Нет, я прочитал ваш вопрос "что вы думаете о константе", не понял вопрос и проигнорировал. Я вам как-то писал, что я так делаю. Вы не потрудились хоть как-то развернуть вопрос, а я ваши загадки не разгадываю. Что я могу думать о какой-то непонятной константе? Ничего...

-- добавлено через 6 минут --

Dmitriy40 в сообщении #1730911 писал(а):
проглядел буквально строкой выше.

Да, и эта фунция печатает что она намерила.
У меня например primelimit теперь повышен до 10^8:
Код:
? platt_opt(10^12)
Измеренные стоимости:
  primelimit = 100000000, порог таблицы = 1.00 e16, порог 64 бит = 9.22 e18
  Простые (быстрый, < 1.00 e16):   1.95 мкс
  Простые (средний, < 2^63):   11.97 мкс
  Простые (медленный, > 2^63): 29.16 мкс
  Загрузка нуля:               2.00 мкс
  Вычисление нуля (phihat):    164.50 мкс

Оптимальные параметры для x=1.00 e12 (по времени счёта):
  lam =    4.468 e-5
  nzeros = 154278
  c =      5.0

Оценка погрешности:
  Хвост нулей:        0.145
  Хвост главн. члена: 2.56 e-9
  I_{-1}:             0.000159
  Хвост решета:       0.192
  Суммарная:          0.337
  OK: погрешность < 0.5

Прогноз времени:
  Загрузка нулей:   0.3 с
  Ряд phihat:       25.4 с
  Решето:           31.5 с
  Сумма:            57.2 с
Вызов:
platt_pi(1000000000000,154278,4.468 e-5,500,5.0)

time = 1,294 ms.
?

Думаю, Платт примерно так и делал: померил на своём суперкластере стоимость в расчёте на единицу (но только не загрузки нуля, а его вычисления), сбаласировал параметры и запустил на 40 000 потоко-часов.
У меня из расчёта вышло 100 000 потоко-часов (на планшете) для 10^24, 800 млрд. нулей. Платт обошёлся меньшим количеством - но он их вычислял, а не скачивал.
По крайней мере, "механика" вычислений Платта теперь более-менее ясна.

1 Отличная работаDmitriy40
 Re: Точное количество простых чисел в интервале
Yadryara в сообщении #1730862 писал(а):
И в итоге всё равно до ваших 69 секунд не добрался.

Пробуйте версию 5. Запустите platt_opt(10^12) он выдаст параметры. Скопируйте то, что на следующей строке после "Запуск:" и запустите.

А, ну ещё я увеличил primelimit до 10^8
Но это вроде на 10^12 ещё не так сильно сказывается.
Настраивается в файле gprc, поищите где он у вас.

 Re: Точное количество простых чисел в интервале
wrest в сообщении #1730942 писал(а):
Запустите platt_opt(10^12) он выдаст параметры. Скопируйте то, что на следующей строке после "Запуск:" и запустите.

Запустил в телефоне :D
Там primelimit по умолчанию, 10^6

Код:
? default(parisize,2G)
  ***   Warning: new stack size = 2000000000 (1907.349 Mbytes).
? platt_pi(1000000000000,163130,4.250 e-5,500,5.0)
Составляющие погрешности (хвост нулей может быть больше!):
  1. Хвост нулей (оптимистично):  0.145
  2. Хвост главн. члена:          2.43 e-9
  3. I_{-1}:                      0.000176
  4. Размер решета:               4.250 e8
  5. Хвост решета:                0.183
  6. Пропущенные нули:            0
  7. Неточность нулей:            0.0219
  Суммарная:                      0.350
  OK: оптимистично погрешность  < 0.5, можно вычислять
Получаем 163130 нулей ... готово за 252 мс
Вычисляем главный член ...        37607950312.302 готово за 13 мс
Вычисляем остаток ряда phihat ... 796.168  (готово за 16467 мс)
Вычисляем поправку решетом ...    634.297   (старт: 9.998 e11 длина: 4.250 e8 ) (готово за 13428 мс)
Сумма ...                         37607951742.075
Поправки Мёбиуса ...              -39723.776 (готово за 0 мс)
37607912018.298773195012541715451536946
? ##
  ***   last result computed in 30,863 ms.
?

 Re: Точное количество простых чисел в интервале
Аватара пользователя
wrest в сообщении #1730916 писал(а):
Вы не потрудились хоть как-то развернуть вопрос

В том-то и дело что потрудился. Но vicvolf умудрился не понять, что в левом столбце степени десятки, а не количество нулей.

wrest в сообщении #1730956 писал(а):
Запустил в телефоне

Если правильно понимаю, то он справился с $\pi(10^{12})$ за всего лишь 30 секунд? Ну дела... :appl:

 Re: Точное количество простых чисел в интервале
Yadryara в сообщении #1730970 писал(а):
Если правильно понимаю, то он справился с $\pi(10^{12})$ за всего лишь 30 секунд? Ну дела...

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

Дальнейшее ускорение, в рамках pari/gp, лежит в двух направлениях:
1. Параллелизация. Тут у меня почти готово, результаты по коэффициенту весьма неплохие.
2. Компиляция. Тут надо внимательно шаг за шагом смотреть что и как. Где короткие числа, где длинные, какая нужна битность/точность на плавающую точку. У Платта было немало там головной боли, судя по статье.

Алгоритмически, оставаясь в русле статьи Платта, кажется что уже всё сделано. По решету у Платта непонятно как именно он делал, так что в точности восстановить наверное не выйдет. Полагаю, это где-то реализовано типа в primesieve или подобном софте. Но это в общем-то технические детали реализации специфической задачи решета в диапазоне.

Возвращаясь к цифрам Платта.
Цитата:
We set λ = 6273445730170391× 2^−84 (note that this is exactly representable in
IEEE 754 double precision floating point). We used the first 69, 778, 732, 700 zeros
to compute the sum (those to height 20, 950, 046, 000) which in turn dictated that
we sieve a region of width about 6 × 10^15.


platt_opt дает мне довольно похожие значения:
Код:
Оптимальные параметры для x=1.00 e24 (по времени счёта):
  lam =    3.308 e-11
  nzeros = 8.06 e11
  primes = 4.96 e14

Т.е. предлагает использовать на порядок меньшую лямбду, на порядок больше нулей и на порядок меньше ширину решета.

Цитата:
The sum over zeros and the prime sieve all parallelise trivially and we used the
University of Bristol Bluecrystal Phase II cluster to perform all the computations,
consuming approximately 63, 000 CPU hours

Тут мне platt_opt прогнозииует 111 000 часов.

Но кстати из статьи Платта неясно, всё-таки, вошло ли время на вычисление самих нулей в общее время. Если нет, и Платт как и я немношко спрямил углы использованием готовых нулей, то расчёт на удивление похож. То, что у меня рассчитывается прогноз для планшета в пределах порядка величины потраченной Платтом, так сейчас мобильные девайсы по пиковой производительности очень хороши, а статья Платта аж 2013 года, тогда процессоры были медленнее.

 Re: Точное количество простых чисел в интервале
platt_v7_par.gp ВЕРСИЯ 7 Параллельная
Codebase (набор скриптов), скачать в файл например platt_v7_par.gp
Глобальных переменных нет, всё в функциях.

(Оффтоп)

Код:
\\ ============================================================
\\  platt_v7_par.gp — аналитическое pi(x) методом Платта
\\  (явная формула Римана + гауссово сглаживание + обращение Мёбиуса)
\\  Статья на основе которой работает алгоритм
\\  David J. Platt Computing π(x) Analytically
\\  https://arxiv.org/abs/1203.5712
\\  https://doi.org/10.48550/arXiv.1203.5712
\\
\\ ПАРАЛЛЕЛЬНАЯ ВЕРСИЯ
\\
\\  Нули берутся из таблицы Одлыжко (zeros1 = 10^5 нулей,
\\  zeros6 = 10^6 нулей). Нулевая часть — рядами (лемма 6.1),
\\  решётная поправка — сегментами с разложением Тейлора (§5).
\\
\\  БЫСТРЫЙ СТАРТ
\\  ---------------
\\    \r platt_v7_par.gp
\\    \p 50
\\    platt_pi(10^8, 100, 0.04, 100,5,0)   \\ -> 5761455.00...
\\    primepi(10^8)                     \\ сверка: 5761455
\\
\\  ИНТЕРФЕЙС
\\  ---------
\\    platt_pi(x, nzeros, lam, nseg,prime_sieve,verbose)
\\      x      — аргумент pi(x);
\\      nzeros — сколько нулей дзета использовать;
\\      lam    — параметр сглаживания;
\\      nseg   — число сегментов Тейлора в решётной поправке, рекомендуется 100.
\\      prime_sieve — ширина решета в конце интервала для поправки, от 4 до 7
\\      verbose — 1 печатать статистику, 0 просто вернуть результат
\\
\\  ПАРАМЕТРЫ (проверенные ориентиры)
\\  ---------------------------------
\\    Правило: нулей нужно до высоты ~6/lam; lam балансирует
\\    длину интеграла главного члена (~1/lam) и ширину решета (~lam).
\\    Функция platt_opt(x) проводит измерение производительности
\\    и на его основе выдаёт оптимальные по времен вычислений параметры
\\
\\  Точность: погрешность << 0.5, округление platt_pi даёт точное целое.
\\ ============================================================

\\ ================= НУЛИ ДЗЕТА-ФУНКЦИИ =================
\\ должны быть в файле zeros1 (0^5 шт.) и zeros6 (2*10^6 шт.)
\\ например нули из таблиц Одлыжко
\\ отсюда: https://www-users.cse.umn.edu/~odlyzko/zeta_tables/index.html
\\ ================= НУЛИ ДЗЕТА-ФУНКЦИИ =================
load_zeros(n) = {
  my(filename=if(n>10^5,"zeros6", "zeros1"));
  my(fd, vals, val, i);
    fd = fileopen(filename, "r");
    vals = vector(n);
    for(i = 1, n,
        val = eval(fileread(fd));
        if(val == 0, fileclose(fd);error("Не хватает нулей в файле ", filename," Надо: ",n," Есть:",i));
        vals[i] = val;
    );
    fileclose(fd);
    return(vals);
}

\\ ============ СГЛАЖЕННАЯ НУЛЕВАЯ ЧАСТЬ (Phihat) ============

phihat(s, x, lam) = (x^s/s)*exp(lam^2*s^2/2);

\\ int_0^Del phihat(s0+I*h) dh рядом Тейлора (лемма 6.1)

step_incr(s0, Del, x, lam, K) = {
  my(A = log(x) + s0*lam^2, ph0 = phihat(s0,x,lam));
  my(eD = exp(I*Del*A), invIA = 1/(I*A), Ik = vector(K+1), c, s=0, n, m, k);

  \\ Предвычисление степеней один раз на вызов
  my(pow_s0 = vector(K+1), pow_lam = vector(K\2+1));
  my(inv_s0 = -I/s0, half_lam2 = -lam^2/2);
  pow_s0[1] = 1;
  for(n=1, K, pow_s0[n+1] = pow_s0[n]*inv_s0);
  pow_lam[1] = 1;
  for(m=1, K\2, pow_lam[m+1] = pow_lam[m]*half_lam2/m);

  Ik[1] = (eD - 1)*invIA;
  for(k=1, K, Ik[k+1] = Del^k*eD*invIA - k*invIA*Ik[k]);

  for(k=0, K,
    c = 0;
    for(m=0, k\2,
      n = k - 2*m;
      c += pow_s0[n+1] * pow_lam[m+1];
    );
    s += c*Ik[k+1];
  );
  ph0*s
}

\\ Re Phihat для всех нулей; адаптивный шаг Del = ratio*|1/2+I*t|
\\ ПАРАЛЛЕЛЬНАЯ ВЕРСИЯ
Phihat_re_all(x, lam, zeros, K) = {
  my(n=#zeros);
  if(n < 2, return(vector(n)));
 
  \\ Экспорт функций для параллельного использования
  export(step_incr);
  export(phihat);
 
  \\ Параллельное вычисление всех шагов
  my(steps = parvector(n-1, j, step_incr(1/2 + I*zeros[j], zeros[j+1] - zeros[j], x, lam, K)));
 
  \\ Последовательное накопление
  my(G = 0, GatZ = vector(n));
  GatZ[1] = 0;
  for(j=2, n, G += steps[j-1]; GatZ[j] = G);
  vector(n, j, imag(G - GatZ[j]))
}

\\ Re Phihat(1): главный член, адаптивный шаг Del = ratio*|1+I*t|
Phihat_re_at_1(x, lam, ratio, K) = {
  my(T = 8/lam, t=0, tnext, G=0, Del);
  while(t < T,
    Del = ratio*sqrt(1+t^2);
    tnext = min(t + Del, T);
    G += step_incr(1 + I*t, tnext - t, x, lam, K);
    t = tnext;
  );
  imag(G)
}

\\ ============ РЕШЁТНАЯ ПОПРАВКА (§5 Платта) ============

\\ Вспомогательная функция для обработки одного сегмента
\\ Все параметры передаются явно (не через нужно для параллельности)
process_segment(j, a, b, x0, jx, x, lo, sq2lam, sqrtpi, invx, w) = {
  my(N=0, S1=0, S2=0, C=0, d, g, eg, ph0, ph1, ph2, ph3);
  if(b >= a,
    if(j < jx,
      forprime(p=a, b, d=x0-p; S1+=d; S2+=d*d; N++);
      C=N;
    , if(j > jx,
        forprime(p=a, b, d=x0-p; S1+=d; S2+=d*d; N++);
        C=0;
      , forprime(p=a, b, if(p<x, C++); d=x0-p; S1+=d; S2+=d*d; N++);
      )
    );
    g=log(x0*invx)/sq2lam; eg=exp(-g*g);
    ph0=0.5*erfc(g);
    ph1=-eg/(sqrtpi*sq2lam*x0);
    ph2=eg/(sqrtpi*sq2lam*x0*x0)*(2*g/sq2lam+1);
    ph3=eg/(sqrtpi*sq2lam*x0^3)*(2/sq2lam^2 - 2 - (2*g/sq2lam)^2 - 3*(2*g/sq2lam));
    ph1 += ph3*w^2/8;
    C - (ph0*N - ph1*S1 + ph2*S2/2);
  , 0)
}

\\ sum_{p^m} (chi-phi)/m; сегменты + Тейлор для phi (erfc один раз в сегмент)
\\ Ширина окна = 2*c*lam*x, c=5 рекомендуется (проверено: c=5,8,10 дают одно и то же)
\\ ПАРАЛЛЕЛЬНАЯ ВЕРСИЯ

sieve_corr_taylor(x, lam, nseg, c=5) = {
  my(lo=x*exp(-c*lam), hi=x*exp(c*lam));
  my(sq2lam=sqrt(2)*lam, sqrtpi=sqrt(Pi), invx=1/x);
  my(w=(hi-lo)/nseg);
  my(B=vector(nseg+1, j, round(lo + (j-1)*(hi-lo)/nseg)));
 
  \\ Индекс сегмента, содержащего границу x
  my(jx=1);
  while(jx<nseg && B[jx+1]<=x, jx++);

  \\ Экспорт функции для параллельного использования
  export(process_segment);
 
  \\ Параллельная обработка всех сегментов
  my(s = vecsum(parvector(nseg, j,
    my(a=B[j], b=B[j+1]-1, x0);
    if(b >= a, x0=(a+b)/2, x0=0);
    process_segment(j, a, b, x0, jx, x, lo, sq2lam, sqrtpi, invx, w)
  )));

  \\ Степени простых (последовательно, их мало)
  my(m=2, q);
  while(2^m<=hi,
    forprime(p=ceil(lo^(1/m)), floor(hi^(1/m)),
      q=p^m;
      if(q>=lo&&q<=hi, s+=((q<x)-0.5*erfc(log(q*invx)/sq2lam))/m);
    );
    m++;
  );
  s
}

\\ ============ ОБРАЩЕНИЕ МЁБИУСА ============

\\ точное f(y)=sum (1/n) pi(y^{1/n}) встроенным primepi
ftarget(y) = sum(n=1, floor(log(y)/log(2)), primepi(sqrtn(y,n))/n);

\\ ============ СБОРКА ============

platt_pi(x, nzeros, lam, nseg=100, c=5, verbose=2) = {
  if(verbose>1,
    platt_error_estimates(x, nzeros, 4*10^(-9), lam, nseg, c);
  );
  my(s,res,t0);
  if(verbose,
    t0=getwalltime();
    print1("Получаем ", nzeros, " нулей ...");
    );
  my(zeros = load_zeros(nzeros));
  if(verbose,
    print(" готово за ", getwalltime()-t0, " мс");
    t0=getwalltime();
    print1("Вычисляем главный член ...        ");
    );
  my(re1 = Phihat_re_at_1(x, lam, 0.5, 40));
  if(verbose,
    print(strprintf("%.3f",re1), " готово за ", getwalltime()-t0, " мс");
    t0=getwalltime();
    print1("Вычисляем остаток ряда phihat ... ");
  );
  \\ ПАРАЛЛЕЛЬНАЯ ВЕРСИЯ: Phihat_re_all теперь использует parvector
  my(rez = Phihat_re_all(x, lam, zeros, 20));
  my(zsum = sum(j=1, #rez, rez[j]));
  if(verbose,
    print(strprintf("%.3f", -2*zsum),"  готово за ", getwalltime()-t0, " мс");
    t0=getwalltime();
    print1("Вычисляем поправку решетом ...    ");
  );
  \\ ПАРАЛЛЕЛЬНАЯ ВЕРСИЯ: sieve_corr_taylor теперь использует parvector
  res=sieve_corr_taylor(x, lam, nseg, c);
  if(verbose,
    print(strprintf("%.3f",res),"    длина ",strprintf("%.4g",x*(exp(c*lam)-exp(-c*lam)))," готово за ", getwalltime()-t0, " мс");
  );
  res=re1 - 2*zsum - log(2) + res;
  if(verbose,
    print("Сумма Phi ...                     ",strprintf("%.3f",res));
    t0=getwalltime();
    print1("Поправка Мёбиуса ...              ");
  );
 
  \\ ПАРАЛЛЕЛЬНАЯ ВЕРСИЯ: поправки Мёбиуса
  export(ftarget);
  my(nmax = floor(log(x)/log(2)));
  s = vecsum(parvector(nmax-1, n,
    my(nn = n+1);
    if(moebius(nn)!=0, (moebius(nn)/nn)*ftarget(sqrtn(x,nn)), 0)
  ));
 
  if(verbose,
    print(strprintf("%.3f",s),"   готово за ", getwalltime()-t0, " мс");
  );
  return(res+s);
}

\\ Оценка погрешностей
platt_error_estimates(x, nzeros, zero_acc, lam, nseg, c) = {
  my(zeros = load_zeros(nzeros));
  my( T1=zeros[nzeros], T=8/lam);
  my(E1, E2, E3, E4, E5, E6, Etotal);
  \\ Эмпирический коэффициент, в надежде что нули осциллируют
  my(kE1 = 1/4);

  E1 = kE1*2*intnum(t=T1, T, sqrt(x)/t * exp(-lam^2*t^2/2) * log(t)/(2*Pi));

  E2 = exp(lam^2*(1-T^2)/2) * (x/(T*log(x)) + 1/(lam^2*T^2*x));

  E3 = exp(lam^2/2)/(2*Pi*x*lam) * (5/sqrt(2*Pi) + 2/lam);

  E4 = x*lam*sqrt(2)/log(x) * exp(-c^2/2)/(sqrt(Pi)*c^2);

  my(N_exp = T1/(2*Pi)*log(T1/(2*Pi)) - T1/(2*Pi) + 7/8);
  my(bound = 0.137*log(T1) + 0.443*log(log(T1)) + 1.588);
  my(diff = abs(N_exp - nzeros));
  E5 = if(diff > bound, diff, 0);

  E6 = zero_acc * sum(j=1, nzeros,
    my(g=zeros[j]);
    sqrt(x)/sqrt(1/4+g^2)*exp(lam^2*(1/4-g^2)/2)
  );

  Etotal = E1 + E2 + E3 + E4 + E5 + E6;

  print("Составляющие погрешности (хвост нулей может быть больше!):");
  printf("  1. Хвост нулей (оптимистично):  %.3g\n", E1);
  printf("  2. Хвост главн. члена:          %.3g\n", E2);
  printf("  3. I_{-1}:                      %.3g\n", E3);
   print("  4. Размер решета:               ",strprintf("%.4g",x*(exp(c*lam)-exp(-c*lam))));
  printf("  5. Хвост решета:                %.3g\n", E4);
  print("  6. Пропущенные нули:            ", E5);
  printf("  7. Неточность нулей:            %.3g\n", E6);
  printf("  Суммарная:                      %.3g\n", Etotal);
  if(Etotal < 0.5,
    print("  OK: оптимистично погрешность  < 0.5, можно вычислять"),
    print("  ВНИМАНИЕ: погрешность         > 0.5, вероятна ошибка")
  );
}


\\ ===== Подбор оптимальных параметров с измерением реальными функциями =====
platt_opt(x) = {
  my(E_max=0.15, kE1=1/4);
  my(lam, T1, nzeros, c, T);
  my(E1, E2, E3, E4, Etotal, budget, budget_E4);
  my(n_primes, time_total, i, best_time, best_lam, best_nzeros, best_c, best_T1);
  my(lam_min, lam_max, lam_step);
  my(cost_prime, cost_zero, cost_load);
  my(N_max = 10^6);  \\ максимальное доступное число нулей (zeros6)

  \\ === Измерение стоимостей реальными функциями ===

  \\ 1. Стоимость простого: запуск sieve_corr_taylor на окне шириной 10^8
  my(lam_test = 1e7/x);
  my(nseg_test = 500);
  my(t0 = getwalltime());
  sieve_corr_taylor(x, lam_test, nseg_test, 5);
  my(time_sieve = (getwalltime()-t0)*1e-3);
  my(width_test = x*(exp(5*lam_test)-exp(-5*lam_test)));
  my(n_primes_test = width_test/log(x));
  cost_prime = time_sieve / n_primes_test;

  \\ 2. Стоимость загрузки нулей
  my(n_test = 5000);
  n_test = min(n_test, 10^6);
  t0 = getwalltime();
  my(zeros = load_zeros(n_test));
  cost_load = (getwalltime()-t0)/n_test*1e-3;

  \\ 3. Стоимость вычисления нуля: запуск Phihat_re_all
  my(test_lam = 1e-4);
  t0 = getwalltime();
  Phihat_re_all(x, test_lam, zeros, 20);
  cost_zero = (getwalltime()-t0)/n_test*1e-3;

  printf("Измеренные стоимости:\n");
  printf("  Простое (решето):     %.2f мкс\n", cost_prime*1e6);
  printf("  Загрузка нуля:        %.2f мкс\n", cost_load*1e6);
  printf("  Вычисление нуля:      %.2f мкс\n", cost_zero*1e6);

  \\ === Начальное приближение lam ===
  lam = 1e-4;
  for(i=1, 10,
    lam = sqrt(3*cost_zero*log(x)/(2*Pi*cost_prime*5*x) * log(6/(2*Pi*lam*exp(1))));
  );
  lam_min = lam/3;
  lam_max = lam*3;
  lam_step = (lam_max - lam_min)/20;

  best_time = 1e30;
  best_lam = 0; best_nzeros = 0; best_c = 0; best_T1 = 0;

  \\ === Перебор lam ===
  for(k=0, 20,
    lam = lam_min + k*lam_step;
    T = 8/lam;

    \\ Фиксированные погрешности для данного lam
    E2 = exp(lam^2*(1-T^2)/2) * (x/(T*log(x)) + 1/(lam^2*T^2*x));
    E3 = exp(lam^2/2)/(2*Pi*x*lam) * (5/sqrt(2*Pi) + 2/lam);

    \\ Бюджет погрешности для E1 + E4
    budget = E_max - E2 - E3;
    if(budget <= 0, next);

    \\ Перебор T1 (высота нулей)
    my(T1_min = 4/lam, T1_max = T);
    my(n_T1 = 10);
    for(j=0, n_T1,
      T1 = T1_min + j*(T1_max - T1_min)/n_T1;

      \\ Ограничение на число нулей
      nzeros = round(T1/(2*Pi)*log(T1/(2*Pi*exp(1))) + 7/8);
      \\ if(nzeros > N_max, next);

      \\ Погрешность хвоста нулей
      E1 = kE1*2*intnum(t=T1, T, sqrt(x)/t * exp(-lam^2*t^2/2) * log(t)/(2*Pi));
      if(E1 >= budget, next);

      \\ Оставшийся бюджет для E4
      budget_E4 = budget - E1;

      \\ Подбор c: минимальное c такое, что E4(c) <= budget_E4
      c = 3;
      E4 = x*lam*sqrt(2)/log(x) * exp(-c^2/2)/(sqrt(Pi)*c^2);
      while(E4 > budget_E4 && c < 15,
        c += 0.25;
        E4 = x*lam*sqrt(2)/log(x) * exp(-c^2/2)/(sqrt(Pi)*c^2);
      );
      if(E4 > budget_E4, next);

      \\ Время
      n_primes = 2*c*lam*x/log(x);
      time_total = (cost_load + cost_zero)*nzeros + cost_prime*n_primes + 0.02;

      if(time_total < best_time,
        best_time = time_total;
        best_lam = lam;
        best_nzeros = nzeros;
        best_c = c;
        best_T1 = T1;
      );
    );
  );

  if(best_time >= 1e30,
    print("ВНИМАНИЕ: не найдены параметры с погрешностью < ", E_max);
    return([0, 0, 0, 0, 0]);
  );

  \\ === Вывод результата ===
  lam = best_lam; nzeros = best_nzeros; c = best_c; T1 = best_T1;
  T = 8/lam;
  E1 = kE1*2*intnum(t=T1, T, sqrt(x)/t * exp(-lam^2*t^2/2) * log(t)/(2*Pi));
  E2 = exp(lam^2*(1-T^2)/2) * (x/(T*log(x)) + 1/(lam^2*T^2*x));
  E3 = exp(lam^2/2)/(2*Pi*x*lam) * (5/sqrt(2*Pi) + 2/lam);
  E4 = x*lam*sqrt(2)/log(x) * exp(-c^2/2)/(sqrt(Pi)*c^2);
  Etotal = E1 + E2 + E3 + E4;
  n_primes = 2*c*lam*x/log(x);
  time_total = (cost_load + cost_zero)*nzeros + cost_prime*n_primes + 0.02;

  printf("\nОптимальные параметры для x=%.3g (по времени счёта):\n", x);
  printf("  lam =    %.4g\n", lam);
  printf("  nzeros = %.4g   = (%d)\n", nzeros, nzeros);
  printf("  c =      %.2f\n", c);
  printf("  sieve =  %.4g\n", x*(exp(c*lam)-exp(-c*lam)));
  printf("\nОценка погрешности:\n");
  printf("  Хвост нулей:        %.3g\n", E1);
  printf("  Хвост главн. члена: %.3g\n", E2);
  printf("  I_{-1}:             %.3g\n", E3);
  printf("  Хвост решета:       %.3g\n", E4);
  printf("  Суммарная:          %.3g\n", Etotal);
  if(Etotal < 0.5,
    print("  OK: погрешность < 0.5"),
    print("  ВНИМАНИЕ: погрешность >= 0.5")
  );
  printf("\nПрогноз времени:\n");
  printf("  Загрузка нулей:   %.1f с\n", 1.2*cost_load*nzeros);
  printf("  Ряд phihat:       %.1f с\n", 1.2*cost_zero*nzeros);
  printf("  Решето:           %.1f с\n", 1.2*cost_prime*n_primes);
  printf("  Итого:            %.1f с\n", 1.2*time_total);

  print("Вызов: ");
  print("platt_pi(",x,",",nzeros,",",strprintf("%.4g",lam),",",500,",",strprintf("%.2f",c),",1)");
  print();
}

Запуск на ноуте:

(Оффтоп)

Код:
? platt_opt(10^14)
Измеренные стоимости:
  Простое (решето):     0.34 мкс
  Загрузка нуля:        3.40 мкс
  Вычисление нуля:      91.00 мкс

Оптимальные параметры для x=1.00 e14 (по времени счёта):
  lam =    8.085 e-6
  nzeros = 1.134 e6   = (1133595)
  c =      5.5
  sieve =  8.894 e9

Оценка погрешности:
  Хвост нулей:        0.101
  Хвост главн. члена: 3.97 e-8
  I_{-1}:             4.87 e-5
  Хвост решета:       0.179
  Суммарная:          0.279
  OK: погрешность < 0.5

Прогноз времени:
  Загрузка нулей:   3.9 с
  Ряд phihat:       103.2 с
  Решето:           93.6 с
  Итого:            200.6 с
Вызов:
platt_pi(100000000000000,1133595,8.085 e-6,500,5.5,1)

cpu time = 10,676 ms, real time = 1,701 ms.
? platt_pi(100000000000000,1133595,8.085 e-6,500,5.5,1)
Получаем 1133595 нулей ... готово за 3167 мс
Вычисляем главный член ...        3204942065789.476 готово за 14 мс
Вычисляем остаток ряда phihat ... 18188.361  готово за 121628 мс
Вычисляем поправку решетом ...    867.002    длина 8.894 e9 готово за 126806 мс
Сумма Phi ...                     3204942084844.146
Поправка Мёбиуса ...              -334042.484   готово за 3 мс
cpu time = 27min, 46,689 ms, real time = 4min, 11,643 ms.
3204941750801.6614053754253971336487334
?

Коэффициент параллельности очень хороший
cpu time = 27min, 46,689 ms, real time = 4min, 11,643 ms. (у меня 8 потоков)
10:14 считается за 4 минуты, но это ноутбук с тротлингом и вот этим всем.
Некоторые функции разделены на параллельную и последовательную части выделением новых функций наружу.
Поправлены некоторые коэффициенты, влияющие на точность. Переделан бенчмарк производительности и подбор параметров: две функции сведены в одну platt_opt(), и теперь должно попадать в погрешность 0.5 всегда. Ну или по крайней мере до 10^14 8-) Бенчмарк запускает реальные функции и запускает параллельно. Ошибка бенчмарка по времени выполнения у меня получатся 10-30%, думаю норм.
При verbose=0 в основной функции platt_pi() возвращается только результат, verbose=1 печатается статистика и тайминги, verbose=2 дополнительно печатается оценка погрешностей до вычислений.

Поскольку ноутбук беру в руки редко, а на планшете нет параллельного pari/gp, вряд ли буду что-то обновлять в ближайшее время.

 Re: Точное количество простых чисел в интервале
Аватара пользователя
Для детального разбирательства предлагаю сверяться со статьёй которую перевёл и адаптировал для форумного формата. Конечно пользовался помощью Гуглопереводчика и ИИ Гугла.
____________________________________________________

ВЫЧИСЛЕНИЕ $\pi(x)$ АНАЛИТИЧЕСКИМ МЕТОДОМ.

ДЭВИД Дж. ПЛАТТ.

Аннотация. Мы описываем строгую реализацию аналитического метода Лагариаса и Одлыжко для оценки функции подсчёта простых чисел и его использование для безусловного вычисления количества простых чисел меньших $10^{24}$.

1. Введение.

Вычисление точных значений функции $\pi(x)$, которая подсчитывает количество простых чисел, меньших или равных $x$, занимало математиков с древних времен. Ранние методы включали перечисление всех простых чисел меньше целевого x (используя, например, решето Эратосфена), а затем их подсчёт. В 1870-м году Мейссель [12] описал комбинаторный метод, который он в конечном итоге использовал для ручного вычисления $\pi(10^9)$ [13] (хотя и не совсем точно). Алгоритм впоследствии был улучшен Лемером, затем Лагариасом, Миллером и Одлыжко, а совсем недавно — Делеглизом и Риватом. В 2007-м году Оливейра и Сильва использовал алгоритм для вычисления $\pi(10^{23})$.

Теорема о простых числах гласит, что все методы, основанные на перечислении простых чисел, должны иметь временную сложность $\Omega(x \log^{-1} x)$. Последние версии комбинаторного метода достигают $O(x^{2/3} \log^{-2} x)$.

В своей статье 1987-го года [9] Лагариас и Одлыжко описали аналитический алгоритм (в одной форме) с временной сложностью $O(x^{1/2+\epsilon})$. В 2010-м году Бюте, Франке, Йост и Кляйнюнг объявили значение $\pi(10^{24})$ [5], зависящее от гипотезы Римана. Их подход «похож на подход, описанный Лагариасом и Одлыжко, но использует явную формулу Вейля вместо комплексных кривых интегралов». В этой статье описывается реализация, возвращающаяся к явной формуле Римана, которую мы использовали для безусловного вычисления $\pi(10^{24})$.


2. Замечание о строгости

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

Однако есть определенные аспекты, над которыми мы имеем больший контроль. Оценка ошибки округления, которая будет накапливаться при сложных вычислениях с плавающей запятой — это нетривиальная задача, которую мы избегаем. Вместо этого мы полагаемся на интервальную арифметику (см. [14] для хорошего введения). Таким образом, вместо хранения одного приближения с плавающей запятой, мы храним интервал, состоящий из двух чисел с плавающей запятой, чтобы охватить истинное значение. Затем мы перегружаем стандартные операторы и функции для обработки таких интервалов.

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


3. Аналитический алгоритм

Аналитический алгоритм основан на формуле Перрона.

Теорема 3.1 (формула Перрона). Пусть $a(n)$ — арифметическая функция с рядом Дирихле
$$g(s) = \sum_{n=1}^{\infty} \frac{a(n)}{n^s}$$

Теперь, если $g(s)$ абсолютно сходится всякий раз, когда $\Re s > \sigma_a$, то для $c > \sigma_a$ и $x > 0$ мы имеем:
$$\sum_{n \le x}{}^* a(n) = \frac{1}{2\pi i} \int_{c-i\infty}^{c+i\infty} g(s) \frac{x^s}{s} ds$$
где $*$ в знаке суммирования указывает, что если $x$ — целое число, то включается только $1/2$ члена $a(x)$.

 Re: Точное количество простых чисел в интервале
Аватара пользователя
Доказательство. См. страницу 245 [1] и последующее примечание.

Актуальность формулы Перрона для рассматриваемого вопроса вытекает из ряда, абсолютно сходящегося при $\Re s > 1$,
$$\log \zeta(s) = \sum_{n=2}^{\infty} \frac{\Lambda(n)}{n^s \log n}.$$
Здесь $\Lambda$ — функция фон Мангольдта, поэтому $\frac{\Lambda(n)}{\log n}$ равно $\frac{1}{m}$ при простых степенях $p^m$ и нулю в остальных случаях. Определим
$$\pi^*(x) := \sum_{p^m \le x} \frac{1}{m}$$
где, если $x$ — простая степень, мы берем только половину ее вклада в сумму. Затем применяя формулу Перрона, получаем для $c > 1$ и $x > 0$
$$\sum_{n \le x}{}^* \frac{\Lambda(n)}{\log n} = \pi^*(x) = \frac{1}{2\pi i} \int_{c-i\infty}^{c+i\infty} \log \zeta(s) \frac{x^s}{s} ds \qquad\qquad\qquad \text{(3.1)}$$
Здесь отметим, что хотя мы можем легко восстановить $\pi(x)$ из $\pi^*(x)$, медленная скорость сходимости интеграла обрекает на неудачу любую попытку использовать его в этом контексте.

На этом этапе Лагариас и Одлыжко вводят «подходящую» пару преобразований Меллина $\varphi(t)$ и $\hat{\varphi}(s)$ и выводят
$$\pi^*(x) = \frac{1}{2\pi i} \int_{\sigma-i\infty}^{\sigma+i\infty} \log \zeta(s) \hat{\varphi}(s) ds + \sum_{p^m} \frac{1}{m} [\chi_x(p^m) - \varphi(p^m)] \qquad\qquad\qquad \text{(3.2)}$$
где $\chi_x(t)$ определяется как
$$\chi_x(t) := \begin{cases} 1 & t < x \\ 1/2 & t = x \\ 0 & t > x \end{cases}$$
Заметим, что взятие $\hat{\varphi}(s) = \frac{x^s}{s}$ делает $\varphi(t) = \chi_x(t)$, и мы восстанавливаем (3.1).
Таким образом, оценка $\pi^*(x)$ теперь разделяется на оценку интеграла и суммирование $\varphi(t)$, вычисленных в простых степенях в окрестности $x$.

В своей докторской диссертации [8] Галвей исследовал предложенный алгоритм и предложил использовать пару преобразований Меллина
$$\hat{\varphi}(s) := \frac{x^s}{s} \exp\left(\frac{\lambda^2 s^2}{2}\right) \quad \text{и} \quad \varphi(t) := \frac{1}{2} \operatorname{erfc}\left(\frac{\log\frac{t}{x}}{\sqrt{2}\lambda}\right) \qquad\qquad\qquad \text{(3.3)}$$
Здесь $\operatorname{erfc}$ — дополнительная функция ошибок
$$\operatorname{erfc}(x) := \frac{2}{\sqrt{\pi}} \int_{x}^{\infty} \exp\left(-t^2\right) dt$$
и $\lambda$ — положительный вещественный параметр, используемый для балансировки сходимости интеграла с шириной простого решета.
Галвей показал, что $\varphi$ и $\hat{\varphi}$, как определено в (3.3), действительно «подходят» и, используя аргументы, основанные на принципе неопределённости, предположил что они в некотором смысле оптимальны. Он также дал строгую оценку ошибки, вносимой усечением простого решета до некоторой конечной ширины.


4. Вычисление $\frac{1}{2\pi i} \int_{\sigma-i\infty}^{\sigma+i\infty} \log \zeta(s) \hat{\varphi}(s) ds$

На этом этапе мы отклоняемся от линии, выбранной Лагариасом и Одлыжко. Вместо того чтобы пытаться численно оценить интеграл в (3.2), мы используем подход, более близкий к духу Римана, и оцениваем его через нетривиальные нули ζ, что приводит к теореме 4.7 ниже.

Прежде чем продолжить, нам понадобится пара лемм.

Лемма 4.1. Лемма «Вокруг полюса». Пусть f — мероморфная функция с простым полюсом в α с вычетом R, и пусть Γ — полукруговой контур против часовой стрелки от α + ε до α - ε. Тогда
$$\lim_{\epsilon \to 0^+} \int_{\Gamma} f(z) dz = \pi i R.$$

Доказательство. См. страницу 29 [18].

 [ Сообщений: 117 ]  На страницу Пред.  1 ... 4, 5, 6, 7, 8  След.


Соглашение о конфиденциальности | Общие правила

Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group