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

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




На страницу Пред.  1, 2
 Re: Детерминированный алгоритм поиска некоторых простых чисел
Cantata в сообщении #1724865 писал(а):
Я обратила внимание, что если числа расположить в виде трапеции, где в каждой строке на два числа больше, то структура сама так выстраивается, что в каждой строке находится как минимум один квадрат.

И решила проверить как стабильно это будет продолжаться И вот проверка показала, что даже с числами 10в1000 каждая строка имеет квадрат простого числа.
Если я правильно понимаю о чём речь, то начало каждой строки трапеции растёт квадратично (как квадрат от номера строки), а длина строки линейно. А вот средний интервал между соседними простыми растёт как обратный логарифм, соответственно средний интервал между квадратами соседних простых чисел растёт примерно как удвоенное произведение простого на логарифм его же. Само простое растёт линейно от номера строки, как и длина строки, но интервалы между квадратами растут по идее чуть быстрее (в удвоенный логарифм номера строки) и потому должны быть строки без квадратов простых. Странно что Вы их не нашли ...
Покажите пожалуйста как именно начинаются первые несколько (4-5) строк трапеции? Интересно почему нет строк без квадратов простых. Ещё полезно проверить что известные максимальные интервалы между соседними простыми числами (из таблицы) точно не нарушают вашу трапецию, ведь они растут почти как квадрат логарифма, а не просто логарифм, т.е. заметно быстрее среднего.

Cantata в сообщении #1724865 писал(а):
Теперь вот стало интересно, можно ли вывести алгоритм, чтобы находить простые числа, где куча нулей - я о них выше написала уже.
Конечно, тривиально же: начать с числа вида $b=10^{1000} k$ (или любой другой степени больше 2) и перебирать числа подряд до обнаружения простого. В среднем хватит $\ln(10^{1000} k) (примерно 2300 для небольших $k$) проверок и практически никогда не больше квадрата от этого. В PARI это просто nextprime(k*10^1000).

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

Cantata
Нет, чего-то не понимаю: я не вижу квадратов простых в каждой строке трапеции начинающейся ровно с квадратов натуральных чисел:
Код:
? for(k=1,10,print(k^2," ... ",(k+1)^2-1))
1 ... 3
4 ... 8
9 ... 15
16 ... 24
25 ... 35
36 ... 48
49 ... 63
64 ... 80
81 ... 99
100 ... 120
Тут все квадраты простых если и есть, то только исключительно в строках которые и начинаются с квадрата простого. Но ведь полно строк с квадрата составного и в них точно нет квадрата простого числа. Например в строках с 64,81,100 квадрата простого нет, как не сдвигай начало строк с сохранением их длины в средней строке квадрат простого не появится.

Покажите плиз вашу трапецию ...

 Re: Детерминированный алгоритм поиска некоторых простых чисел
Dmitriy40 в сообщении #1724866 писал(а):
чего-то не понимаю: я не вижу квадратов простых в каждой строке трапеции начинающейся ровно с квадратов натуральных чисел

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

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

А почему именно нули? Чем топоры не устраивают?

Нули:

Код:
? nextprime(1000000)
%1 = 1000003
? nextprime(10000000)
%2 = 10000019
? nextprime(100000000)
%3 = 100000007

Девятки:

Код:
? precprime(100000000)
%4 = 99999989
? precprime(1000000000)
%5 = 999999937
? precprime(10000000000)
%6 = 9999999967

Топоры:

Код:
? nextprime(77777777777777777)
%7 = 77777777777777797
? nextprime(777777777777777777)
%8 = 777777777777777817
? nextprime(7777777777777777777)
%9 = 7777777777777777793

Всего и делов-то. Большие гэпы это редкость.

 Re: Детерминированный алгоритм поиска некоторых простых чисел
Yadryara в сообщении #1724874 писал(а):
А почему именно нули?

просто на глаза попались, так отличались визуально от остальных)

Yadryara в сообщении #1724874 писал(а):
Чем топоры не устраивают?

Код:
Пример 3: 100 ведущих семёрок, 5 переменных цифр
=

Поиск 1 простых чисел с 100 ведущими семёрками и 5 переменными цифрами...
✅ Найден простой число №1:
  777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777700067
  Длина: 105
  Время поиска этой пары: 0.49 мс

 Re: Детерминированный алгоритм поиска некоторых простых чисел
Аватара пользователя
Ну да, 100 7-к можно и так:

Код:
? nextprime(777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777700000)
%10 = 777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777700067


А 101 так:

Код:
? nextprime(777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777770000)
%13 = 777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777770167

Понятно же как 102 сделать.

 Re: Детерминированный алгоритм поиска некоторых простых чисел
Cantata в сообщении #1724871 писал(а):
Начальное число беру достаточно большое. И есть ограничение по высоте трапеции - его основание заканчивается на квадрате начального числа.
Мне почему-то кажется, что так правильно.
Начальное число - длина самой короткой строки (макушки трапеции), от нее вниз идет расширение каждый раз число с шагом плюс два, плюс четыре, плюс шесть и до квадрата числа.
И всё же непонятно, приведите пример хоть какой-нибудь трапеции высотой не менее 4-5 (можно только левые числа если правее они увеличиваются подряд, но хотя бы в одной строке и самое правое число).
Непонятно например как вообще трапеция получается конечной высоты, почему не продолжается ниже.

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

Так ли это? Я могу безбоязненно его показать?

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

Yadryara в сообщении #1724879 писал(а):
Понятно же как 102 сделать.

Мы играем в угадайку? Или таким образом тестируем модель? Я код не проверяла, у меня каша в голове от всего. Чат бот сейчас его написал и вот результат:

Код:
======================================================================
Пример 7: 97 ведущих семёрок, 5 переменные цифр (102 знака всего)
=

Поиск 1 простых чисел с 97 ведущими семёрками и 5 переменными цифрами...
✅ Найден простой число №1:
  777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777700673
  Длина: 102
  Время поиска этой пары: 4.77 мс


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

Yadryara в сообщении #1724874 писал(а):
А почему именно нули? Чем топоры не устраивают?

Кстати, вы играете не по правилам, либо не читали описание этого метода полностью?
Он привязан к началу заданных интервалов и не может эффективно работать как решето. Он точечно ищет около начала интервала - это совсем другое.

Я сейчас внимательнее код посмотрела, что мне чат-бот написал для поиска "топоров", так вот, мой метод он там не использовал, сказал, что нецелесообразно)
Предыдущие два ответа аннулируются)

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

Сначала мы с ним думали, что метод как-то связан с некоторыми числами Люка.
Дипсик уверенно назвал несколько штук, мы их проверили на диапазоне от 10в5 до 10в100 и получили чуть меньше тысячи простых, но со 100% подтверждением метода.
Так как для всех выбранных чисел Люка во всех диапазонах нашлось простое число.

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

 Re: Детерминированный алгоритм поиска некоторых простых чисел
Cantata в сообщении #1724885 писал(а):
Так ли это? Я могу безбоязненно его показать?
Понятия не имею про какой алгоритм Вы говорите и потому не могу ответить на эти вопросы.
Алгоритм выдающий числа из этого вашего сообщения и так уже опубликован мною, дважды, ничего интересного в нём нет.
Интересующий меня пример трапеции вполне можете показать в личке.

 Re: Детерминированный алгоритм поиска некоторых простых чисел
Аватара пользователя
Cantata в сообщении #1724885 писал(а):
Мы играем в угадайку?

Я пока не играю.

Имел в виду 102 7-ки подряд, а не 97.

Cantata в сообщении #1724885 писал(а):
Кстати, вы играете не по правилам, либо не читали описание этого метода полностью?

Я пока не играю.

Смотря какого "этого метода".

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

Ну да, собственно об этом и речь. Функции precprime и nextprime как раз ищут простое поблизости от заданного числа.

Захватывая при этом и само число, ежели оно простое. То есть

Код:
? precprime(997)
%26 = 997
? nextprime(997)
%27 = 997

Лично мне это неудобно, приходится помнить о такой особенности. Чтобы соседей посмотреть можно делать так:

Код:
? precprime(997-1)
%28 = 991
? nextprime(997+1)
%29 = 1009

 Re: Детерминированный алгоритм поиска некоторых простых чисел
Yadryara
Спасибо, у меня нет цели искать все простые числа.

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

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

Кстати, я проверку полную не делала ни для одного построения. Сейчас посмотрела на небольшом числе и не в каждой строке есть квадрат простого.
Поэтому, похоже, что гипотеза не подтверждается. Либо нужно брать большей длины числа. Либо возвращаться к некоторым числам Люка.
С ними был 100% результат))

 Re: Детерминированный алгоритм поиска некоторых простых чисел
Аватара пользователя
Cantata в сообщении #1724865 писал(а):
Теперь вот стало интересно, можно ли вывести алгоритм, чтобы находить простые числа, где куча нулей - я о них выше написала уже.
Есть такая теорема. Формулирую для десятичной системы счисления.
Теорема. Пусть заданы два натуральных числа $A$ и $B$, причём, запись числа $B$ заканчивается на одну из цифр $1$, $3$, $7$ или $9$. Тогда существует такое натуральное число $C$, что если записать подряд числа $A$, $C$ и $B$, то получится простое число.

Результат "записи подряд" для краткости часто записывают как $\overline{ACB}$.
Если запись числа $B$ содержит $n$ цифр, а запись числа $C$$k$ цифр, то получившееся число можно записать в виде $p=10^n(10^kA+C)+B$
Если Вам хочется вставить между $A$ и $C$ и/или между $C$ и $B$ какое-то количество нулей, увеличьте соответствующим образом $n$ и $k$.

Например, если взять $A=2\,718\,281\,828\,459\,045$ (первые $16$ цифр числа $e$), $B=3\,141\,592\,653\,589\,793$ (первые $16$ цифр числа $\pi$), то вставка между ними однозначного числа (считая $0$ однозначным) не даёт простых чисел, но находятся $3$ двузначных числа, дающих простые числа:
Код:
For[k=0,k<=9,k++,If[PrimeQ[p=10^16 (10A+k)+B],Print["k = ",k,", p = ",p]]]
For[k=10,k<=99,k++,If[PrimeQ[p=10^16 (100A+k)+B],Print["k = ",k,", p = ",p]]]
k = 39, p = 2718281828459045393141592653589793
k = 82, p = 2718281828459045823141592653589793
k = 97, p = 2718281828459045973141592653589793

 Re: Детерминированный алгоритм поиска некоторых простых чисел
Someone в сообщении #1724895 писал(а):
Есть такая теорема. Формулирую для десятичной системы счисления.
Теорема. Пусть заданы два натуральных числа $A$ и $B$, причём, запись числа $B$ заканчивается на одну из цифр $1$, $3$, $7$ или $9$. Тогда существует такое натуральное число $C$, что если записать подряд числа $A$, $C$ и $B$, то получится простое число.

Спасибо!

 Re: Детерминированный алгоритм поиска некоторых простых чисел
Здравствуйте. Вот итоговый результат, который вроде как работает не хуже случайного поиска, но и не лучше.


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

случайный старт (рандом), детерминированная формула и гибридный вариант.
Код включает оптимизации (Smart K, wheel-sieve, быстрый отсев) и выводит статистически корректное сравнение в понятном виде.

Код в оффтопе:

(Оффтоп)

Код:
[syntax lang="python"]import random
import statistics
import math
import subprocess
import sys

# Авто-подключение gmpy2
try:
    from gmpy2 import is_prime, isqrt, mpz
except ImportError:
    try:
        subprocess.check_call([sys.executable, "-m", "pip", "install", "gmpy2", "-q"],
                              stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        from gmpy2 import is_prime, isqrt, mpz
    except Exception:
        # Fallback на чистый Python, если установка не удалась
        def mpz(x): return int(x)
        def isqrt(n): return math.isqrt(int(n))
        def is_prime(n, k=10):
            n = int(n)
            if n < 2: return False
            if n in (2, 3): return True
            if n % 2 == 0: return False
            r, d = 0, n - 1
            while d % 2 == 0: r += 1; d //= 2
            witnesses = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37] if n < 2**64 else [random.randint(2, n-2) for _ in range(k)]
            for a in witnesses:
                x = pow(a, d, n)
                if x in (1, n-1): continue
                for _ in range(r-1):
                    x = pow(x, 2, n)
                    if x == n-1: break
                else: return False
            return True

CONFIG = {
    'N_digits': 500,          # Размер чисел
    'iterations': 50,         # Количество тестов
    'seed': 42,               # Для повторяемости результатов
    'max_steps': 200000,      # Лимит попыток
}

PRE_FILTER = [7, 11, 13, 17, 19, 23, 29, 31]

def get_smart_structural_start(N_digits):
    k = random.randint(10, 99)
    for _ in range(500):
        N = mpz(10)**(2 * N_digits)
        m_val = isqrt(1 + k*N + (k-1)*k)
        if m_val % 2 == 0: m_val += 1
        if m_val % 3 != 0 and m_val % 5 != 0:
            return int(m_val), k
        k += 1
        if k > 200: k = 10
    return int(m_val), k

def find_prime_engineered(start, max_steps=200000):
    curr = int(start)
    if curr % 2 == 0: curr += 1
    while curr % 3 == 0 or curr % 5 == 0:
        curr += 2
       
    checks = 0
    wheel = [6, 4, 2, 4, 2, 4, 6, 2]
    rem = curr % 30
    wheel_map = {1:0, 7:1, 11:2, 13:3, 17:4, 19:5, 23:6, 29:7}
    w_idx = wheel_map.get(rem, 0)
   
    while checks < max_steps:
        is_small = False
        for p in PRE_FILTER:
            if curr % p == 0:
                is_small = True
                break
        if not is_small:
            checks += 1
            if is_prime(curr):
                return checks, True
        curr += wheel[w_idx]
        w_idx = (w_idx + 1) % len(wheel)
    return checks, False

def run_benchmark(cfg):
    random.seed(cfg['seed'])
    rand_res, struct_res, hybrid_res = [], [], []
    N = cfg['N_digits']
    for _ in range(cfg['iterations']):
        s_r = random.randint(10**(N-1), 10**N - 1)
        if s_r % 2 == 0: s_r += 1
        c_r, _ = find_prime_engineered(s_r, cfg['max_steps'])
        rand_res.append(c_r)

        m_s, _ = get_smart_structural_start(N)
        c_s, _ = find_prime_engineered(m_s, cfg['max_steps'])
        struct_res.append(c_s)

        offset = random.randint(-2000, 2000)
        s_h = m_s + offset
        if s_h < 10**(N-1): s_h += 4000
        if s_h % 2 == 0: s_h += 1
        c_h, _ = find_prime_engineered(s_h, cfg['max_steps'])
        hybrid_res.append(c_h)
       
    return rand_res, struct_res, hybrid_res

def print_results_simple(rand, struct, hybrid, N):
    """Выводит понятную таблицу с пояснениями"""
   
    def get_stats(data):
        return statistics.mean(data), statistics.stdev(data)
   
    m_r, s_r = get_stats(rand)
    m_s, s_s = get_stats(struct)
    m_h, s_h = get_stats(hybrid)
    n = len(rand)

    print(f"\nСравнение методов поиска простых чисел ({N} цифр, {n} запусков):")
    print("Число в колонке 'Среднее' — сколько раз в среднем пришлось проверить число, чтобы найти простое.")
    print("Число в колонке 'Разброс' — насколько результаты отличаются друг от друга (чем меньше, тем стабильнее).")
    print("-" * 95)
    print(f"{'Метод поиска':<20} | {'Среднее (попыток)':>18} | {'Разброс':>10} | {'Лучший / Худший случай':>22}")
    print("-" * 95)
    print(f"{'Случайный старт':<20} | {m_r:>18.1f} | {s_r:>10.1f} | {min(rand):>6} / {max(rand):<6}")
    print(f"{'Формула (Structural)':<20} | {m_s:>18.1f} | {s_s:>10.1f} | {min(struct):>6} / {max(struct):<6}")
    print(f"{'Формула + сдвиг':<20} | {m_h:>18.1f} | {s_h:>10.1f} | {min(hybrid):>6} / {max(hybrid):<6}")
    print("-" * 95)

    # Простая проверка значимости
    def t_test(m1, s1, m2, s2, n):
        se = math.sqrt(s1**2/n + s2**2/n)
        return abs(m1 - m2) / se if se > 0 else 0

    t_rs = t_test(m_r, s_r, m_s, s_s, n)
    t_rh = t_test(m_r, s_r, m_h, s_h, n)
   
    best_name = "Случайный старт"
    best_val = m_r
    if m_s < best_val: best_name, best_val = "Формула (Structural)", m_s
    if m_h < best_val: best_name, best_val = "Формула + сдвиг", m_h

    print(f"\nИтог:")
    if t_rs < 2.0 and t_rh < 2.0:
        print("Все три метода работают примерно одинаково. Различия в цифрах — это случайность, а не закономерность.")
    else:
        print(f"Метод '{best_name}' показал лучший результат в среднем ({best_val:.1f} попыток), и это различие статистически значимо.")

if __name__ == "__main__":
    cfg = CONFIG.copy()
    if cfg['N_digits'] >= 1000:
        cfg['iterations'] = 30
    r, s, h = run_benchmark(cfg)
    print_results_simple(r, s, h, cfg['N_digits'])[/syntax]


Полученный результат:
Код:
Сравнение методов поиска простых чисел (500 цифр, 50 запусков):
Число в колонке 'Среднее' — сколько раз в среднем пришлось проверить число, чтобы найти простое.
Число в колонке 'Разброс' — насколько результаты отличаются друг от друга (чем меньше, тем стабильнее).
-----------------------------------------------------------------------------------------------
Метод поиска         |  Среднее (попыток) |    Разброс | Лучший / Худший случай
-----------------------------------------------------------------------------------------------
Случайный старт      |              227.4 |      246.5 |      1 / 1002 
Формула (Structural) |              159.1 |      202.0 |      1 / 726   
Формула + сдвиг      |              166.3 |      186.1 |      3 / 755   
-----------------------------------------------------------------------------------------------

Итог:
Все три метода работают примерно одинаково. Различия в цифрах — это случайность, а не закономерность.



Суть метода

Алгоритм генерирует начальную точку для поиска больших простых чисел с помощью фиксированной формулы:

m = \left\lfloor \sqrt{1 + k \cdot 10^{2n} + (k-1) \cdot k} \right\rfloor

Формула выведена из геометрической раскладки натуральных чисел в виде трапеции и гарантирует, что при одинаковых входных параметрах (N, k) старт всегда будет одинаковым.

Ключевые оптимизации

- Smart K — автоматический подбор коэффициента k, чтобы вычисленное m гарантированно не делилось на 3 и 5.
- Колесный шаг (Wheel 2·3·5) — перебор ведётся только по числам, взаимно простым с 30, с помощью фиксированного паттерна шагов [6,4,2,4,2,4,6,2]. Исключает операции деления в цикле.
- Быстрый отсев — проверка делимости малыми простыми (7, 11, 13, …, 31) перед вызовом ресурсоёмкого теста простоты.


Эмпирические результаты:
Протестирован на числах длиной 50–1500 цифр (суммарно >500 запусков). Среднее количество вызовов is_prime статистически эквивалентно случайному поиску.
Метод не ускоряет асимптотику, но обеспечивает детерминизм, воспроизводимость и предсказуемые границы худшего случая.

 Re: Детерминированный алгоритм поиска некоторых простых чисел
Cantata в сообщении #1725177 писал(а):
Полученный результат:
Для чисел из 500 знаков может попасться интервал между простыми более миллиона, именно он и будет худшим случаем. То что на 50 запусков худшим оказался случай с интервалом порядка тысячи - случайность, это как раз средний интервал между простыми в этом диапазоне. Т.е. 50 запусков оказалось достаточно чтобы попасть на средний интервал и слишком мало чтобы попасть на большие интервалы.

Cantata в сообщении #1725177 писал(а):
Ключевые оптимизации
Проводилась ли проверка скорости без них?
Потому что все эти оптимизации могут быть реализованы и в самой is_prime и тогда выполнять их самим нет смысла (библиотечная функция должна быть быстрее).

Cantata в сообщении #1725177 писал(а):
Код в оффтопе:
Зря убрали в оффтоп и тем более code, тег syntax и так хорошо его сворачивает, достаточно его одного, сравните:
Код: [ скачать ] [ спрятать ]
Используется синтаксис Python
import random
import statistics
import math
import subprocess
import sys

# Авто-подключение gmpy2
try:
    from gmpy2 import is_prime, isqrt, mpz
except ImportError:
    try:
        subprocess.check_call([sys.executable, "-m", "pip", "install", "gmpy2", "-q"],
                              stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        from gmpy2 import is_prime, isqrt, mpz
    except Exception:
        # Fallback на чистый Python, если установка не удалась
        def mpz(x): return int(x)
        def isqrt(n): return math.isqrt(int(n))
        def is_prime(n, k=10):
            n = int(n)
            if n < 2: return False
            if n in (2, 3): return True
            if n % 2 == 0: return False
            r, d = 0, n - 1
            while d % 2 == 0: r += 1; d //= 2
            witnesses = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37] if n < 2**64 else [random.randint(2, n-2) for _ in range(k)]
            for a in witnesses:
                x = pow(a, d, n)
                if x in (1, n-1): continue
                for _ in range(r-1):
                    x = pow(x, 2, n)
                    if x == n-1: break
                else: return False
            return True

CONFIG = {
    'N_digits': 500,          # Размер чисел
    'iterations': 50,         # Количество тестов
    'seed': 42,               # Для повторяемости результатов
    'max_steps': 200000,      # Лимит попыток
}

PRE_FILTER = [7, 11, 13, 17, 19, 23, 29, 31]

def get_smart_structural_start(N_digits):
    k = random.randint(10, 99)
    for _ in range(500):
        N = mpz(10)**(2 * N_digits)
        m_val = isqrt(1 + k*N + (k-1)*k)
        if m_val % 2 == 0: m_val += 1
        if m_val % 3 != 0 and m_val % 5 != 0:
            return int(m_val), k
        k += 1
        if k > 200: k = 10
    return int(m_val), k

def find_prime_engineered(start, max_steps=200000):
    curr = int(start)
    if curr % 2 == 0: curr += 1
    while curr % 3 == 0 or curr % 5 == 0:
        curr += 2
       
    checks = 0
    wheel = [6, 4, 2, 4, 2, 4, 6, 2]
    rem = curr % 30
    wheel_map = {1:0, 7:1, 11:2, 13:3, 17:4, 19:5, 23:6, 29:7}
    w_idx = wheel_map.get(rem, 0)
   
    while checks < max_steps:
        is_small = False
        for p in PRE_FILTER:
            if curr % p == 0:
                is_small = True
                break
        if not is_small:
            checks += 1
            if is_prime(curr):
                return checks, True
        curr += wheel[w_idx]
        w_idx = (w_idx + 1) % len(wheel)
    return checks, False

def run_benchmark(cfg):
    random.seed(cfg['seed'])
    rand_res, struct_res, hybrid_res = [], [], []
    N = cfg['N_digits']
    for _ in range(cfg['iterations']):
        s_r = random.randint(10**(N-1), 10**N - 1)
        if s_r % 2 == 0: s_r += 1
        c_r, _ = find_prime_engineered(s_r, cfg['max_steps'])
        rand_res.append(c_r)

        m_s, _ = get_smart_structural_start(N)
        c_s, _ = find_prime_engineered(m_s, cfg['max_steps'])
        struct_res.append(c_s)

        offset = random.randint(-2000, 2000)
        s_h = m_s + offset
        if s_h < 10**(N-1): s_h += 4000
        if s_h % 2 == 0: s_h += 1
        c_h, _ = find_prime_engineered(s_h, cfg['max_steps'])
        hybrid_res.append(c_h)
       
    return rand_res, struct_res, hybrid_res

def print_results_simple(rand, struct, hybrid, N):
    """Выводит понятную таблицу с пояснениями"""
   
    def get_stats(data):
        return statistics.mean(data), statistics.stdev(data)
   
    m_r, s_r = get_stats(rand)
    m_s, s_s = get_stats(struct)
    m_h, s_h = get_stats(hybrid)
    n = len(rand)

    print(f"\nСравнение методов поиска простых чисел ({N} цифр, {n} запусков):")
    print("Число в колонке 'Среднее' — сколько раз в среднем пришлось проверить число, чтобы найти простое.")
    print("Число в колонке 'Разброс' — насколько результаты отличаются друг от друга (чем меньше, тем стабильнее).")
    print("-" * 95)
    print(f"{'Метод поиска':<20} | {'Среднее (попыток)':>18} | {'Разброс':>10} | {'Лучший / Худший случай':>22}")
    print("-" * 95)
    print(f"{'Случайный старт':<20} | {m_r:>18.1f} | {s_r:>10.1f} | {min(rand):>6} / {max(rand):<6}")
    print(f"{'Формула (Structural)':<20} | {m_s:>18.1f} | {s_s:>10.1f} | {min(struct):>6} / {max(struct):<6}")
    print(f"{'Формула + сдвиг':<20} | {m_h:>18.1f} | {s_h:>10.1f} | {min(hybrid):>6} / {max(hybrid):<6}")
    print("-" * 95)

    # Простая проверка значимости
    def t_test(m1, s1, m2, s2, n):
        se = math.sqrt(s1**2/n + s2**2/n)
        return abs(m1 - m2) / se if se > 0 else 0

    t_rs = t_test(m_r, s_r, m_s, s_s, n)
    t_rh = t_test(m_r, s_r, m_h, s_h, n)
   
    best_name = "Случайный старт"
    best_val = m_r
    if m_s < best_val: best_name, best_val = "Формула (Structural)", m_s
    if m_h < best_val: best_name, best_val = "Формула + сдвиг", m_h

    print(f"\nИтог:")
    if t_rs < 2.0 and t_rh < 2.0:
        print("Все три метода работают примерно одинаково. Различия в цифрах — это случайность, а не закономерность.")
    else:
        print(f"Метод '{best_name}' показал лучший результат в среднем ({best_val:.1f} попыток), и это различие статистически значимо.")

if __name__ == "__main__":
    cfg = CONFIG.copy()
    if cfg['N_digits'] >= 1000:
        cfg['iterations'] = 30
    r, s, h = run_benchmark(cfg)
    print_results_simple(r, s, h, cfg['N_digits'])


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

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

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

 Re: Детерминированный алгоритм поиска некоторых простых чисел
Dmitriy40 в сообщении #1725185 писал(а):
Детерминизм и воспроизводимость - да, впрочем как и любой метод выбора начальных чисел без фактора случайности, а вот про худший случай - нет, точнее он сильно хуже наблюдаемого из такой малой статистики, и тоже обеспечивается практически любым другим методом, ведь всё это следует не из метода, а из самого распределения простых чисел.

Да, тоже пришла к этому выводу. Просто раз уж тему открыла, нужно было результат показать.

Dmitriy40 в сообщении #1725185 писал(а):
В общем так и непонятно чем же предлагаемый метод выбора начального числа m (а всё что дальше - более-менее тривиально) лучше любого другого метода, включая и просто случайный выбор m заданного размера. Я никаких значимых преимуществ не вижу.

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

Dmitriy40 в сообщении #1725185 писал(а):
Проводилась ли проверка скорости без них?

Да, были проверки, пришли к оптимизации. Вот тут можно итоги посмотреть:

-- добавлено через 35 секунд --

Код:
СРАВНЕНИЕ: Без оптимизаций vs Оптимизированная версия (N=500)

  Выполнено 10/50 запусков...
  Выполнено 20/50 запусков...
  Выполнено 30/50 запусков...
  Выполнено 40/50 запусков...
  Выполнено 50/50 запусков...

=================================================================
РЕЗУЛЬТАТЫ СРАВНЕНИЯ (N=500, n=50)
=================================================================
Метод                     | Ср. время (мс) | Вызовов is_prime | Доля проверок
-----------------------------------------------------------------
Без оптимизаций           |        181.8 |            483.3 |       100.0%
Оптимизированный          |        182.0 |            148.4 |        30.7%
-----------------------------------------------------------------
Ускорение по времени: 1.00x
Экономия вызовов is_prime: ~69% (за счёт колеса и пре-фильтра)
=================================================================


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

Если рассматривать, что он воспроизводит те же значения, при одинаковых данных, то можно поискать оптимизации для k.

Вот наглядно видно:
Код:
СКАНИРОВАНИЕ K | N=50 | k ∈ [10, 100)
FAST MODE (прерывание после 30 проверок)

============================================================
ТОП-10 ЗНАЧЕНИЙ K (N=50)
============================================================
k    |  Проверок | Оценка
------------------------------------------------------------
20   |         1 |  Мгновенно
26   |         1 |  Мгновенно
32   |         1 |  Мгновенно
65   |         1 |  Мгновенно
69   |         1 |  Мгновенно
90   |         1 |  Мгновенно
92   |         1 |  Мгновенно
39   |         2 |  Мгновенно
41   |         2 |  Мгновенно
47   |         2 |  Мгновенно
------------------------------------------------------------
  Время: 0.02 сек | Найдено: 76 | Пропущено: 14
Рекомендуемый k для N=50: 20 (всего 1 проверок)


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

Код:
СКАНИРОВАНИЕ K | N=60 | k ∈ [10, 100)
FAST MODE (прерывание после 30 проверок)

============================================================
ТОП-10 ЗНАЧЕНИЙ K (N=60)
============================================================
k    |  Проверок | Оценка
------------------------------------------------------------
64   |         1 |  Мгновенно
85   |         1 |  Мгновенно
14   |         2 |  Мгновенно
37   |         2 |  Мгновенно
53   |         2 |  Мгновенно
42   |         3 |  Отлично
67   |         3 |  Отлично
80   |         3 |  Отлично
34   |         4 |  Отлично
47   |         4 |  Отлично
------------------------------------------------------------
  Время: 0.10 сек | Найдено: 68 | Пропущено: 22
Рекомендуемый k для N=60: 64 (всего 1 проверок)


-- добавлено через 40 секунд --

Код:
СКАНИРОВАНИЕ K | N=70 | k ∈ [10, 100)
FAST MODE (прерывание после 30 проверок)

============================================================
ТОП-10 ЗНАЧЕНИЙ K (N=70)
============================================================
k    |  Проверок | Оценка
------------------------------------------------------------
27   |         1 |  Мгновенно
35   |         1 |  Мгновенно
51   |         1 |  Мгновенно
61   |         1 |  Мгновенно
83   |         1 |  Мгновенно
14   |         2 |  Мгновенно
43   |         2 |  Мгновенно
88   |         2 |  Мгновенно
25   |         3 |  Отлично
38   |         3 |  Отлично
------------------------------------------------------------
  Время: 0.04 сек | Найдено: 62 | Пропущено: 28
Рекомендуемый k для N=70: 27 (всего 1 проверок)

 [ Сообщений: 30 ]  На страницу Пред.  1, 2


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