Алгоритм BPSW проверки на простоту

Тема в разделе "WASM.A&O", создана пользователем maxdiver, 7 июн 2007.

  1. maxdiver

    maxdiver Max

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    308
    Адрес:
    Саратов
    Помогите плиз, уже который день мучаюсь ;)
    Написал алгоритм BPSW, но на числе 29 он даёт ошибку (ну и на некоторых других тоже).
    Может, у кого есть рабочий код, чтобы хотя бы сравнить значения переменных и найти, где происходит ошибка?


    Вот сам код (функции идут в обратном порядке, чтобы было понятнее):
    Код (Text):
    1. //! Алгоритм Бэйли-Померанс-Селфридж-Вагстафф (BPSW) проверки n на простоту
    2. template <class T>
    3. bool baillie_pomerance_selfridge_wagstaff (T n)
    4. {
    5.  
    6.     // сначала проверяем на тривиальные делители - до 5
    7.     int div = prime_div_trivial (n, 5);
    8.     if (div == 1)
    9.         return true;
    10.     if (div > 1)
    11.         return false;
    12.     // если div == 0, то на тривиальные делители n не делится
    13.  
    14.     // тест Миллера-Рабина по базису 2
    15.     if (!miller_rabin (n, 2))
    16.         return false;
    17.  
    18.     // усиленный тест Лукаса-Селфриджа
    19.     return lucas_selfridge (n, 0);
    20.  
    21. }
    22.  
    23.  
    24. //! Усиленный алгоритм Миллера-Рабина проверки n на простоту по базису b
    25. template <class T, class T2>
    26. bool miller_rabin (T n, T2 b)
    27. {
    28.  
    29.     // сначала проверяем тривиальные случаи
    30.     if (n == 2)
    31.         return true;
    32.     if (n < 2 || even (n))
    33.         return false;
    34.  
    35.     // проверяем, что n и b взаимно просты (иначе это приведет к ошибке)
    36.     // если они не взаимно просты, то либо n не просто, либо нужно увеличить b
    37.     if (b < 2)
    38.         b = 2;
    39.     for (T g; (g = gcd (n, b)) != 1; ++b)
    40.         if (n > g)
    41.             return false;
    42.  
    43.     // разлагаем n-1 = q*2^p
    44.     T n_1 = n;
    45.     --n_1;
    46.     T p, q;
    47.     transform_num (n_1, p, q);
    48.  
    49.     // вычисляем b^q mod n, если оно равно 1 или n-1, то n, вероятно, простое
    50.     T rem = powmod (T(b), q, n);
    51.     if (rem == 1 || rem == n_1)
    52.         return true;
    53.  
    54.     // теперь вычисляем b^2q, b^4q, ... , b^((n-1)/2)
    55.     // если какое-либо из них равно n-1, то n, вероятно, простое
    56.     for (T i=1; i<p; i++)
    57.     {
    58.         mulmod (rem, rem, n);
    59.         if (rem == n_1)
    60.             return true;
    61.     }
    62.  
    63.     return false;
    64.  
    65. }
    66.  
    67.  
    68. //! Усиленный алгоритм Лукаса-Селфриджа проверки n на простоту. Используется усиленный алгоритм Лукаса с параметрами Селфриджа. Второй параметр unused не используется, он только дает тип
    69. template <class T, class T2>
    70. bool lucas_selfridge (const T & n, T2 unused)
    71. {
    72.  
    73.     // сначала проверяем тривиальные случаи
    74.     if (n == 2)
    75.         return true;
    76.     if (n < 2 || even (n))
    77.         return false;
    78.  
    79.     // проверяем, что n не является точным квадратом, иначе алгоритм даст ошибку
    80.     if (perfect_square (n))
    81.         return false;
    82.  
    83.     // алгоритм Селфриджа: находим первое число d такое, что:
    84.     // jacobi(d,n)=-1 и оно принадлежит ряду { 5,-7,9,-11,13,... }
    85.     T2 dd;
    86.     for (T2 d_abs = 5, d_sign = 1; ; d_sign = -d_sign, ++++d_abs)
    87.     {
    88.         dd = d_abs * d_sign;
    89.         T g = gcd (n, d_abs);
    90.         if (1 < g && g < n)
    91.             // нашли делитель - d_abs
    92.             return false;
    93.         if (jacobi (T(dd), n) == -1)
    94.             break;
    95.     }
    96.  
    97.     // параметры Селфриджа
    98.     T2
    99.         p = 1,
    100.         q = (p*p - dd) / 4;
    101.    
    102.     // разлагаем n+1 = d*2^s
    103.     T n_1 = n;
    104.     ++n_1;
    105.     T s, d;
    106.     transform_num (n_1, s, d);
    107.  
    108.     // алгоритм Лукаса
    109.     T
    110.         u = 1,
    111.         v = p,
    112.         u2m = 1,
    113.         v2m = p,
    114.         qm = q,
    115.         qm2 = q*2,
    116.         qkd = q;
    117.     for (unsigned bit = 1, bits = bits_in_number(d); bit < bits; bit++)
    118.     {
    119.         mulmod (u2m, v2m, n);
    120.         mulmod (v2m, v2m, n);
    121.         v2m -= qm2;
    122.         if (v2m < 0)
    123.             v2m += n;
    124.         mulmod (qm, qm, n);
    125.         qm2 = qm;
    126.         redouble (qm2);
    127.         if (test_bit (d, bit))
    128.         {
    129.             T t1, t2;
    130.             t1 = u2m;
    131.             mulmod (t1, v, n);
    132.             t2 = v2m;
    133.             mulmod (t2, u, n);
    134.             u = t1 + t2;
    135.             if (!even (u))
    136.                 u += n;
    137.             bisect (u);
    138.             u %= n;
    139.            
    140.             T t3, t4;
    141.             t3 = v2m;
    142.             mulmod (t3, v, n);
    143.             t4 = u2m;
    144.             mulmod (t4, u, n);
    145.             mulmod (t4, (T)dd, n);
    146.             v = t3 + t4;
    147.             if (!even (v))
    148.                 v += n;
    149.             bisect (v);
    150.             v %= n;
    151.             mulmod (qkd, qm, n);
    152.         }
    153.     }
    154.  
    155.     // точно простое (или псевдо-простое)
    156.     if (u == 0 || v == 0)
    157.         return true;
    158.  
    159.     // дополнительные проверки, иначе некоторые составные числа "превратятся" в простые
    160.     T qkd2 = qkd;
    161.     redouble (qkd2);
    162.     for (T2 r = 1; r < s; ++r)
    163.     {
    164.         mulmod (v, v, n);
    165.         v -= qkd2;
    166.         if (v == 0)
    167.             return true;
    168.         if (v < 0)
    169.             v += n;
    170.         if (r < s-1)
    171.         {
    172.             mulmod (qkd, qkd, n);
    173.             qkd2 = qkd;
    174.             redouble (qkd2);
    175.         }
    176.     }
    177.  
    178.     return false;
    179.  
    180. }
    Ну и вспомогательные функции, ничего интересного, но на всякий случай:
    Код (Text):
    1. //! Модуль 64-битного числа
    2. long long abs (long long n)
    3. {
    4.     return n < 0 ? -n : n;
    5. }
    6.  
    7. unsigned long long abs (unsigned long long n)
    8. {
    9.     return n;
    10. }
    11.  
    12. //! Возвращает true, если n четное
    13. template <class T>
    14. bool even (const T & n)
    15. {
    16.     // return n % 2 == 0;
    17.     return (n & 1) == 0;
    18. }
    19.  
    20. //! Делит число на 2
    21. template <class T>
    22. void bisect (T & n)
    23. {
    24.     // n /= 2;
    25.     n >>= 1;
    26. }
    27.  
    28. //! Умножает число на 2
    29. template <class T>
    30. void redouble (T & n)
    31. {
    32.     // n *= 2;
    33.     n <<= 1;
    34. }
    35.  
    36. //! Возвращает true, если n - точный квадрат простого числа
    37. template <class T>
    38. bool perfect_square (const T & n)
    39. {
    40.     T sq = (T) ceil (sqrt ((double)n));
    41.     return sq*sq == n;
    42. }
    43.  
    44. //! Вычисляет корень из числа, округляя его вниз
    45. template <class T>
    46. T sq_root (const T & n)
    47. {
    48.     return (T) floor (sqrt ((double) n));
    49. }
    50.  
    51. //! Возвращает количество бит в числе (т.е. минимальное количество бит, которыми можно представить данное число)
    52. template <class T>
    53. unsigned bits_in_number (T n)
    54. {
    55.     if (n == 0)
    56.         return 1;
    57.     unsigned result = 0;
    58.     while (n)
    59.     {
    60.         bisect (n);
    61.         ++result;
    62.     }
    63.     return result;
    64. }
    65.  
    66. //! Возвращает значение k-го бита числа (биты нумеруются с нуля)
    67. template <class T>
    68. bool test_bit (const T & n, unsigned k)
    69. {
    70.     return (n & (T(1) << k)) != 0;
    71. }
    72.  
    73. //! Умножает a *= b (mod n)
    74. template <class T>
    75. void mulmod (T & a, const T & b, const T & n)
    76. {
    77.     a *= b;
    78.     a %= n;
    79. }
    80.  
    81. //! Вычисляет a^k mod n. Использует бинарное возведение в степень
    82. template <class T, class T2>
    83. T powmod (T a, T2 k, const T & n)
    84. {
    85.     T res = 1;
    86.     while (k)
    87.         if (!even (k))
    88.         {
    89.             mulmod (res, a, n);
    90.             --k;
    91.         }
    92.         else
    93.         {
    94.             mulmod (a, a, n);
    95.             bisect (k);
    96.         }
    97.     return res;
    98. }
    99.  
    100. //! Переводит число n в форму q*2^p
    101. template <class T>
    102. void transform_num (T n, T & p, T & q)
    103. {
    104.     T p_res = 0;
    105.     while (even (n))
    106.     {
    107.         ++p_res;
    108.         bisect (n);
    109.     }
    110.     p = p_res;
    111.     q = n;
    112. }
    113.  
    114. //! Алгоритм Евклида
    115. template <class T, class T2>
    116. T gcd (const T & a, const T2 & b)
    117. {
    118.     return (a == 0) ? b : gcd (b % a, a);
    119. }
    120.  
    121. //! Вычисляет jacobi(a,b)
    122. template <class T>
    123. T jacobi (T a, T b)
    124. {
    125.  
    126. #pragma warning (push)
    127. #pragma warning (disable: 4146)
    128.  
    129.     if (a == 0)
    130.         return 0;
    131.     if (a == 1)
    132.         return 1;
    133.    
    134.     if (a < 0)
    135.         if ((b & 2) == 0)
    136.             return jacobi (-a, b);
    137.         else
    138.             return - jacobi (-a, b);
    139.    
    140.     T e, a1;
    141.     transform_num (a, e, a1);
    142.    
    143.     T s;
    144.     if (even (e) || (b & 7) == 1 || (b & 7) == 7)
    145.         s = 1;
    146.     else
    147.         s = -1;
    148.     if ((b & 3) == 3 && (a1 & 3) == 3)
    149.         s = -s;
    150.     if (a1 == 1)
    151.         return s;
    152.     return s * jacobi (b % a1, a1);
    153.  
    154. #pragma warning (pop)
    155.  
    156. }
    157.  
    158. //! Вычисляет pi(b) первых простых чисел. Возвращает ссылку на вектор с простыми (в векторе может оказаться больше простых, чем надо) и в pi - pi(b)
    159. template <class T, class T2>
    160. const std::vector<T> & get_primes (const T & b, T2 & pi)
    161. {
    162.  
    163.     static std::vector<T> primes;
    164.     static T counted_b;
    165.  
    166.     // если результат уже был вычислен ранее, возвращаем его, иначе довычисляем простые
    167.     if (counted_b >= b)
    168.         pi = T2 (std::upper_bound (primes.begin(), primes.end(), b) - primes.begin());
    169.     else
    170.     {
    171.    
    172.         // число 2 обрабатываем отдельно
    173.         if (counted_b == 0)
    174.         {
    175.             primes.push_back (2);
    176.             counted_b = 2;
    177.         }
    178.  
    179.         // теперь обрабатываем все нечётные, пока не наберём нужное количество простых
    180.         T first = counted_b == 2 ? 3 : primes.back()+2;
    181.         for (T cur=first; cur<=b; ++++cur)
    182.         {
    183.             bool cur_is_prime = true;
    184.             for (std::vector<T>::const_iterator iter = primes.begin(), end = primes.end();
    185.                 iter != end; ++iter)
    186.             {
    187.                 const T & div = *iter;
    188.                 if (div * div > cur)
    189.                     break;
    190.                 if (cur % div == 0)
    191.                 {
    192.                     cur_is_prime = false;
    193.                     break;
    194.                 }
    195.             }
    196.             if (cur_is_prime)
    197.                 primes.push_back (cur);
    198.         }
    199.        
    200.         counted_b = b;
    201.         pi = (T2) primes.size();
    202.  
    203.     }
    204.    
    205.     return primes;
    206.  
    207. }
    208.  
    209. //! Тривиальная проверка n на простоту, перебираются все делители до m. Результат: 1 - если n точно простое, p - его найденный делитель, 0 - если неизвестно, является ли n простым или нет
    210. template <class T, class T2>
    211. T2 prime_div_trivial (const T & n, T2 m)
    212. {
    213.    
    214.     // сначала проверяем тривиальные случаи
    215.     if (n == 2 || n == 3)
    216.         return 1;
    217.     if (n < 2)
    218.         return 0;
    219.     if (even (n))
    220.         return 2;
    221.  
    222.     // генерируем простые от 3 до m
    223.     T2 pi;
    224.     const vector<T2> & primes = get_primes (m, pi);
    225.  
    226.     // делим на все простые
    227.     for (std::vector<T2>::const_iterator iter=primes.begin(), end=primes.end();
    228.         iter!=end; ++iter)
    229.     {
    230.         const T2 & div = *iter;
    231.         if (div * div > n)
    232.             break;
    233.         else
    234.             if (n % div == 0)
    235.                 return div;
    236.     }
    237.    
    238.     if (n < m*m)
    239.         return 1;
    240.     return 0;
    241.  
    242. }
     
  2. UbIvItS

    UbIvItS Well-Known Member

    Публикаций:
    0
    Регистрация:
    5 янв 2007
    Сообщения:
    6.243
    maxdiver
    бери описание алгоса и смотри, если описание не кривое - найдёшь траблу у себя
     
  3. maxdiver

    maxdiver Max

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    308
    Адрес:
    Саратов
    UbIvItS
    В этом и проблема. Собственно описания я не нашел, "переводил" с одного C-шного исходника. Вроде как всё тыщу раз перепроверил. Но там две проблемы:
    1) используется либа GMP для длинной арифмы; боюсь, что я мог неправильно понять работу функций;
    2) откомпилить эту либу у меня не получается - ни под виндой, ни под линухом;

    В общем, если у кого-то есть работающий исходник, то там всего-то проверить, в каком месте функции и при каких значениях переменных происходит return true.

    P.S. Нашёл ещё одну прогу, реализующую BPSW. 5 часов трахался с ней, пытаясь откомпилить, но бросил, добравшись до уровня 500 ошибок (началось с нескольких тысяч) :'-)
     
  4. UbIvItS

    UbIvItS Well-Known Member

    Публикаций:
    0
    Регистрация:
    5 янв 2007
    Сообщения:
    6.243
    maxdiver
    а почему тебе тока этот тест нужен возьми какой - нить другой - без описания алгоса тебе ничего не светит: отбаживать чужой код самое неблагодарное дело.
     
  5. maxdiver

    maxdiver Max

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    308
    Адрес:
    Саратов
    UbIvItS
    А я думал, что это самый быстрый и надежный (хотя и недоказанный) алгоритм. Да я и не искал другие алгоритмы, хочется теперь "добить" этот метод, тем более, что осталось всего-то найти баг на нескольких числах.
    Ладно, смотрю, тут никто конкретно этим не занимался, буду дальше сам "бороться" с компиляторами ;)
    Когда-нибудь наступит светлый день, когда я устраню этот баг и перейду к устранению переполнения в int64 и написанию алгоритма Диксона, потом квадратичного решета... :)
     
  6. UbIvItS

    UbIvItS Well-Known Member

    Публикаций:
    0
    Регистрация:
    5 янв 2007
    Сообщения:
    6.243
    maxdiver
    если не секрет, в чём твоя цель с этими ситами??
    что он мат. необоснован??
     
  7. maxdiver

    maxdiver Max

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    308
    Адрес:
    Саратов
    UbIvItS
    "Реальной" цели типа "срубить бабло" нет :)
    Просто личная заинтересованность.
    Да. Он не доказан. Он лишь проверен для всех чисел до 10^16 или около того. Ни одного контрпримера к нему ещё не нашли, но тем не менее он не доказан.
     
  8. UbIvItS

    UbIvItS Well-Known Member

    Публикаций:
    0
    Регистрация:
    5 янв 2007
    Сообщения:
    6.243
    официально известных методик, на коих можно срубить бабло нема - усе они для рса являются хламом (мой дип в той же корзиночке:))):)), если усё будет ок, то в июле вернусь к етой теме - мож что с уравами типа px1+qx2 выгорит.
     
  9. maxdiver

    maxdiver Max

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    308
    Адрес:
    Саратов
    UbIvItS
    ИМХО в области изобретения алгоритмов тяжело придется, если не изучить сначала существующие алгоритмы. Так что для меня цель сейчас - запрограммировать различные алгебраические алгоритмы и разобраться в их доказательствах. А потом уже (в каком-то весьма отдаленном будущем ;) ) перейти к изобретательству.
     
  10. UbIvItS

    UbIvItS Well-Known Member

    Публикаций:
    0
    Регистрация:
    5 янв 2007
    Сообщения:
    6.243
    maxdiver
    как говорит один мой знакомый: "А кто нам обещал лёгкой жисти??":)). для того, что бы сита что - то особо из себя представляли, нужно решить проблему матрицы - уж очень она здоровая, могет я ошибаюсь, но врятли из них что - то удастся выжать. вот для поиска новых метод затарился я ибуками, если доживу до светлых дней - займусь усем этим:))
     
  11. maxdiver

    maxdiver Max

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    308
    Адрес:
    Саратов
    UbIvItS
    Так для матриц уже придумали алгоритм. Алгоритм Ланцоша (block Lanczos algorithm) - для матриц в поле GF(2), т.е. все возможные значения чисел - 0 или 1. Работает, если не ошибаюсь, за O(n^2.9). Конечно, можно попытаться копать и в этом направлении - ускорении, поскольку это самое критичное место решета.

    Или ты имеешь в виду обычные матрицы? (правда тогда непонятно, какое отношение они имеют к ситу)
     
  12. UbIvItS

    UbIvItS Well-Known Member

    Публикаций:
    0
    Регистрация:
    5 янв 2007
    Сообщения:
    6.243
    maxdiver
    самое главная трабла - размер матрицы: где её хранить, да и времени на её генерацию куча уйдёт - вот я о чём
     
  13. maxdiver

    maxdiver Max

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    308
    Адрес:
    Саратов
    Йаду мне, йаду :)
    Я нашёл ошибку. Оказалось, там всего лишь был перепутан порядок нескольких строк:
    Код (Text):
    1.         T t1, t2;
    2.             t1 = u2m;
    3.             mulmod (t1, v, n);
    4.             t2 = v2m;
    5.             mulmod (t2, u, n);
    6.             u = t1 + t2;
    7.             if (!even (u))
    8.                 u += n;
    9.             bisect (u);
    10.             u %= n;
    11.            
    12.             T t3, t4;
    13.             t3 = v2m;
    14.             mulmod (t3, v, n);
    15.             t4 = u2m;
    16.             mulmod (t4, u, n);
    17.             mulmod (t4, (T)dd, n);
    18.             v = t3 + t4;
    19.             if (!even (v))
    20.                 v += n;
    21.             bisect (v);
    22.             v %= n;
    23.             mulmod (qkd, qm, n);
    заменить на:
    Код (Text):
    1.         T t1, t2;
    2.             t1 = u2m;
    3.             mulmod (t1, v, n);
    4.             t2 = v2m;
    5.             mulmod (t2, u, n);
    6.            
    7.             T t3, t4;
    8.             t3 = v2m;
    9.             mulmod (t3, v, n);
    10.             t4 = u2m;
    11.             mulmod (t4, u, n);
    12.             mulmod (t4, (T)dd, n);
    13.  
    14.             u = t1 + t2;
    15.             if (!even (u))
    16.                 u += n;
    17.             bisect (u);
    18.             u %= n;
    19.  
    20.             v = t3 + t4;
    21.             if (!even (v))
    22.                 v += n;
    23.             bisect (v);
    24.             v %= n;
    25.             mulmod (qkd, qm, n);
    Чтобы найти эту ошибку, мне пришлось откомпилировать и разобраться (как ни странно, самое сложное - откомпилировать чужую программу) в нескольких программах, на что я убил несколько дней непрерывной работы...
    Йаду мне, йаду :)
     
  14. maxdiver

    maxdiver Max

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    308
    Адрес:
    Саратов
    Вот окончательный отлаженный код, может кому пригодится:
    (там ещё одну помарку исправил и улучшил работу с большими числами - теперь код работает где-то до 10^16 - 10^17 при типе long long)
    P.S. Да, и весь код работает только в знаковых (signed) типах!

    Основной код:
    Код (Text):
    1. //! Усиленный алгоритм Миллера-Рабина проверки n на простоту по базису b
    2. template <class T, class T2>
    3. bool miller_rabin (T n, T2 b)
    4. {
    5.  
    6.     // сначала проверяем тривиальные случаи
    7.     if (n == 2)
    8.         return true;
    9.     if (n < 2 || even (n))
    10.         return false;
    11.  
    12.     // проверяем, что n и b взаимно просты (иначе это приведет к ошибке)
    13.     // если они не взаимно просты, то либо n не просто, либо нужно увеличить b
    14.     if (b < 2)
    15.         b = 2;
    16.     for (T g; (g = gcd (n, b)) != 1; ++b)
    17.         if (n > g)
    18.             return false;
    19.  
    20.     // разлагаем n-1 = q*2^p
    21.     T n_1 = n;
    22.     --n_1;
    23.     T p, q;
    24.     transform_num (n_1, p, q);
    25.  
    26.     // вычисляем b^q mod n, если оно равно 1 или n-1, то n, вероятно, простое
    27.     T rem = powmod (T(b), q, n);
    28.     if (rem == 1 || rem == n_1)
    29.         return true;
    30.  
    31.     // теперь вычисляем b^2q, b^4q, ... , b^((n-1)/2)
    32.     // если какое-либо из них равно n-1, то n, вероятно, простое
    33.     for (T i=1; i<p; i++)
    34.     {
    35.         mulmod (rem, rem, n);
    36.         if (rem == n_1)
    37.             return true;
    38.     }
    39.  
    40.     return false;
    41.  
    42. }
    43.  
    44. //! Усиленный алгоритм Лукаса-Селфриджа проверки n на простоту. Используется усиленный алгоритм Лукаса с параметрами Селфриджа. Работает только с знаковыми типами!!! Второй параметр unused не используется, он только дает тип
    45. template <class T, class T2>
    46. bool lucas_selfridge (const T & n, T2 unused)
    47. {
    48.  
    49.     // сначала проверяем тривиальные случаи
    50.     if (n == 2)
    51.         return true;
    52.     if (n < 2 || even (n))
    53.         return false;
    54.  
    55.     // проверяем, что n не является точным квадратом, иначе алгоритм даст ошибку
    56.     if (perfect_square (n))
    57.         return false;
    58.  
    59.     // алгоритм Селфриджа: находим первое число d такое, что:
    60.     // jacobi(d,n)=-1 и оно принадлежит ряду { 5,-7,9,-11,13,... }
    61.     T2 dd;
    62.     for (T2 d_abs = 5, d_sign = 1; ; d_sign = -d_sign, ++++d_abs)
    63.     {
    64.         dd = d_abs * d_sign;
    65.         T g = gcd (n, d_abs);
    66.         if (1 < g && g < n)
    67.             // нашли делитель - d_abs
    68.             return false;
    69.         if (jacobi (T(dd), n) == -1)
    70.             break;
    71.     }
    72.  
    73.     // параметры Селфриджа
    74.     T2
    75.         p = 1,
    76.         q = (p*p - dd) / 4;
    77.    
    78.     // разлагаем n+1 = d*2^s
    79.     T n_1 = n;
    80.     ++n_1;
    81.     T s, d;
    82.     transform_num (n_1, s, d);
    83.  
    84.     // алгоритм Лукаса
    85.     T
    86.         u = 1,
    87.         v = p,
    88.         u2m = 1,
    89.         v2m = p,
    90.         qm = q,
    91.         qm2 = q*2,
    92.         qkd = q;
    93.     for (unsigned bit = 1, bits = bits_in_number(d); bit < bits; bit++)
    94.     {
    95.         mulmod (u2m, v2m, n);
    96.         mulmod (v2m, v2m, n);
    97.         while (v2m < qm2)
    98.             v2m += n;
    99.         v2m -= qm2;
    100.         mulmod (qm, qm, n);
    101.         qm2 = qm;
    102.         redouble (qm2);
    103.         if (test_bit (d, bit))
    104.         {
    105.             T t1, t2;
    106.             t1 = u2m;
    107.             mulmod (t1, v, n);
    108.             t2 = v2m;
    109.             mulmod (t2, u, n);
    110.            
    111.             T t3, t4;
    112.             t3 = v2m;
    113.             mulmod (t3, v, n);
    114.             t4 = u2m;
    115.             mulmod (t4, u, n);
    116.             mulmod (t4, (T)dd, n);
    117.  
    118.             u = t1 + t2;
    119.             if (!even (u))
    120.                 u += n;
    121.             bisect (u);
    122.             u %= n;
    123.  
    124.             v = t3 + t4;
    125.             if (!even (v))
    126.                 v += n;
    127.             bisect (v);
    128.             v %= n;
    129.             mulmod (qkd, qm, n);
    130.         }
    131.     }
    132.  
    133.     // точно простое (или псевдо-простое)
    134.     if (u == 0 || v == 0)
    135.         return true;
    136.  
    137.     // дополнительные проверки, иначе некоторые составные числа "превратятся" в простые
    138.     T qkd2 = qkd;
    139.     redouble (qkd2);
    140.     for (T2 r = 1; r < s; ++r)
    141.     {
    142.         mulmod (v, v, n);
    143.         v -= qkd2;
    144.         if (v < 0) v += n;
    145.         if (v < 0) v += n;
    146.         if (v >= n) v -= n;
    147.         if (v >= n) v -= n;
    148.         if (v == 0)
    149.             return true;
    150.         if (r < s-1)
    151.         {
    152.             mulmod (qkd, qkd, n);
    153.             qkd2 = qkd;
    154.             redouble (qkd2);
    155.         }
    156.     }
    157.  
    158.     return false;
    159.  
    160. }
    161.  
    162. //! Алгоритм Бэйли-Померанс-Селфридж-Вагстафф (BPSW) проверки n на простоту
    163. template <class T>
    164. bool baillie_pomerance_selfridge_wagstaff (T n)
    165. {
    166.  
    167.     // сначала проверяем на тривиальные делители - до 29
    168.     int div = prime_div_trivial (n, 29);
    169.     if (div == 1)
    170.         return true;
    171.     if (div > 1)
    172.         return false;
    173.     // если div == 0, то на тривиальные делители n не делится
    174.  
    175.     // тест Миллера-Рабина по базису 2
    176.     if (!miller_rabin (n, 2))
    177.         return false;
    178.  
    179.     // усиленный тест Лукаса-Селфриджа
    180.     return lucas_selfridge (n, 0);
    181.  
    182. }
    183.  
    184. //! Алгоритм Бэйли-Померанс-Селфридж-Вагстафф (BPSW) проверки n на простоту. Работает только для знаковых типов!
    185. template <class T>
    186. bool isprime (T n)
    187. {
    188.     return baillie_pomerance_selfridge_wagstaff (n);
    189. }
    Понятно, что вызывать нужно функцию isprime().

    Вот вспомогательные функции:
    Код (Text):
    1. //! Модуль 64-битного числа
    2. long long abs (long long n)
    3. {
    4.     return n < 0 ? -n : n;
    5. }
    6.  
    7. unsigned long long abs (unsigned long long n)
    8. {
    9.     return n;
    10. }
    11.  
    12. //! Возвращает true, если n четное
    13. template <class T>
    14. bool even (const T & n)
    15. {
    16.     // return n % 2 == 0;
    17.     return (n & 1) == 0;
    18. }
    19.  
    20. //! Делит число на 2
    21. template <class T>
    22. void bisect (T & n)
    23. {
    24.     // n /= 2;
    25.     n >>= 1;
    26. }
    27.  
    28. //! Умножает число на 2
    29. template <class T>
    30. void redouble (T & n)
    31. {
    32.     // n *= 2;
    33.     n <<= 1;
    34. }
    35.  
    36. //! Возвращает true, если n - точный квадрат простого числа
    37. template <class T>
    38. bool perfect_square (const T & n)
    39. {
    40.     T sq = (T) ceil (sqrt ((double)n));
    41.     return sq*sq == n;
    42. }
    43.  
    44. //! Вычисляет корень из числа, округляя его вниз
    45. template <class T>
    46. T sq_root (const T & n)
    47. {
    48.     return (T) floor (sqrt ((double) n));
    49. }
    50.  
    51. //! Возвращает количество бит в числе (т.е. минимальное количество бит, которыми можно представить данное число)
    52. template <class T>
    53. unsigned bits_in_number (T n)
    54. {
    55.     if (n == 0)
    56.         return 1;
    57.     unsigned result = 0;
    58.     while (n)
    59.     {
    60.         bisect (n);
    61.         ++result;
    62.     }
    63.     return result;
    64. }
    65.  
    66. //! Возвращает значение k-го бита числа (биты нумеруются с нуля)
    67. template <class T>
    68. bool test_bit (const T & n, unsigned k)
    69. {
    70.     return (n & (T(1) << k)) != 0;
    71. }
    72.  
    73. //! Умножает a *= b (mod n)
    74. template <class T>
    75. void mulmod (T & a, T b, const T & n)
    76. {
    77.     // наивная версия, годится только для длинной арифметики
    78.     a *= b;
    79.     a %= n;
    80. }
    81.  
    82. template <>
    83. void mulmod (int & a, int b, const int & n)
    84. {
    85.     a = int( (((long long)a) * b) % n );
    86. }
    87.  
    88. template <>
    89. void mulmod (unsigned & a, unsigned b, const unsigned & n)
    90. {
    91.     a = unsigned( (((unsigned long long)a) * b) % n );
    92. }
    93.  
    94. template <>
    95. void mulmod (unsigned long long & a, unsigned long long b, const unsigned long long & n)
    96. {
    97.     // сложная версия, основанная на бинарном разложении произведения в сумму
    98.     if (a >= n)
    99.         a %= n;
    100.     if (b >= n)
    101.         b %= n;
    102.     unsigned long long res = 0;
    103.     while (b)
    104.         if (!even (b))
    105.         {
    106.             res += a;
    107.             while (res >= n)
    108.                 res -= n;
    109.             --b;
    110.         }
    111.         else
    112.         {
    113.             redouble (a);
    114.             while (a >= n)
    115.                 a -= n;
    116.             bisect (b);
    117.         }
    118.     a = res;
    119. }
    120.  
    121. template <>
    122. void mulmod (long long & a, long long b, const long long & n)
    123. {
    124.     bool neg = false;
    125.     if (a < 0)
    126.     {
    127.         neg = !neg;
    128.         a = -a;
    129.     }
    130.     if (b < 0)
    131.     {
    132.         neg = !neg;
    133.         b = -b;
    134.     }
    135.     unsigned long long aa = a;
    136.     mulmod<unsigned long long> (aa, (unsigned long long)b, (unsigned long long)n);
    137.     a = (long long)aa * (neg ? -1 : 1);
    138. }
    139.  
    140.  
    141. //! Вычисляет a^k (mod n). Использует бинарное возведение в степень
    142. template <class T, class T2>
    143. T powmod (T a, T2 k, const T & n)
    144. {
    145.     T res = 1;
    146.     while (k)
    147.         if (!even (k))
    148.         {
    149.             mulmod (res, a, n);
    150.             --k;
    151.         }
    152.         else
    153.         {
    154.             mulmod (a, a, n);
    155.             bisect (k);
    156.         }
    157.     return res;
    158. }
    159.  
    160. //! Переводит число n в форму q*2^p
    161. template <class T>
    162. void transform_num (T n, T & p, T & q)
    163. {
    164.     T p_res = 0;
    165.     while (even (n))
    166.     {
    167.         ++p_res;
    168.         bisect (n);
    169.     }
    170.     p = p_res;
    171.     q = n;
    172. }
    173.  
    174. //! Алгоритм Евклида
    175. template <class T, class T2>
    176. T gcd (const T & a, const T2 & b)
    177. {
    178.     return (a == 0) ? b : gcd (b % a, a);
    179. }
    180.  
    181. //! Вычисляет jacobi(a,b)
    182. template <class T>
    183. T jacobi (T a, T b)
    184. {
    185.  
    186. #pragma warning (push)
    187. #pragma warning (disable: 4146)
    188.  
    189.     if (a == 0)
    190.         return 0;
    191.     if (a == 1)
    192.         return 1;
    193.    
    194.     if (a < 0)
    195.         if ((b & 2) == 0)
    196.             return jacobi (-a, b);
    197.         else
    198.             return - jacobi (-a, b);
    199.    
    200.     T e, a1;
    201.     transform_num (a, e, a1);
    202.    
    203.     T s;
    204.     if (even (e) || (b & 7) == 1 || (b & 7) == 7)
    205.         s = 1;
    206.     else
    207.         s = -1;
    208.     if ((b & 3) == 3 && (a1 & 3) == 3)
    209.         s = -s;
    210.     if (a1 == 1)
    211.         return s;
    212.     return s * jacobi (b % a1, a1);
    213.  
    214. #pragma warning (pop)
    215.  
    216. }
    217.  
    218. //! Вычисляет pi(b) первых простых чисел. Возвращает ссылку на вектор с простыми (в векторе может оказаться больше простых, чем надо) и в pi - pi(b)
    219. template <class T, class T2>
    220. const std::vector<T> & get_primes (const T & b, T2 & pi)
    221. {
    222.  
    223.     static std::vector<T> primes;
    224.     static T counted_b;
    225.  
    226.     // если результат уже был вычислен ранее, возвращаем его, иначе довычисляем простые
    227.     if (counted_b >= b)
    228.         pi = T2 (std::upper_bound (primes.begin(), primes.end(), b) - primes.begin());
    229.     else
    230.     {
    231.    
    232.         // число 2 обрабатываем отдельно
    233.         if (counted_b == 0)
    234.         {
    235.             primes.push_back (2);
    236.             counted_b = 2;
    237.         }
    238.  
    239.         // теперь обрабатываем все нечётные, пока не наберём нужное количество простых
    240.         T first = counted_b == 2 ? 3 : primes.back()+2;
    241.         for (T cur=first; cur<=b; ++++cur)
    242.         {
    243.             bool cur_is_prime = true;
    244.             for (std::vector<T>::const_iterator iter = primes.begin(), end = primes.end();
    245.                 iter != end; ++iter)
    246.             {
    247.                 const T & div = *iter;
    248.                 if (div * div > cur)
    249.                     break;
    250.                 if (cur % div == 0)
    251.                 {
    252.                     cur_is_prime = false;
    253.                     break;
    254.                 }
    255.             }
    256.             if (cur_is_prime)
    257.                 primes.push_back (cur);
    258.         }
    259.        
    260.         counted_b = b;
    261.         pi = (T2) primes.size();
    262.  
    263.     }
    264.    
    265.     return primes;
    266.  
    267. }
    268.  
    269. //! Тривиальная проверка n на простоту, перебираются все делители до m. Результат: 1 - если n точно простое, p - его найденный делитель, 0 - если неизвестно, является ли n простым или нет
    270. template <class T, class T2>
    271. T2 prime_div_trivial (const T & n, T2 m)
    272. {
    273.    
    274.     // сначала проверяем тривиальные случаи
    275.     if (n == 2 || n == 3)
    276.         return 1;
    277.     if (n < 2)
    278.         return 0;
    279.     if (even (n))
    280.         return 2;
    281.  
    282.     // генерируем простые от 3 до m
    283.     T2 pi;
    284.     const vector<T2> & primes = get_primes (m, pi);
    285.  
    286.     // делим на все простые
    287.     for (std::vector<T2>::const_iterator iter=primes.begin(), end=primes.end();
    288.         iter!=end; ++iter)
    289.     {
    290.         const T2 & div = *iter;
    291.         if (div * div > n)
    292.             break;
    293.         else
    294.             if (n % div == 0)
    295.                 return div;
    296.     }
    297.    
    298.     if (n < m*m)
    299.         return 1;
    300.     return 0;
    301.  
    302. }
     
  15. maxdiver

    maxdiver Max

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    308
    Адрес:
    Саратов
    Вот, может кому-нибудь пригодится:
    http://maximal.hocomua.ru/bpsw.htm - моя статья про BPSW.
    Там описание алгоритма, некоторые доказательства, ссылки на книги. Оттуда же можно скачать и обновленные исходники алгоса (по сравнению с постом #14 исправлено несколько помарок).

    Надеюсь, кому-нибудь моя "статья" поможет, т.к. на русском по BPSW я вообще ничего не нашёл, да и на английском тоже немного инфы.
     
  16. UbIvItS

    UbIvItS Well-Known Member

    Публикаций:
    0
    Регистрация:
    5 янв 2007
    Сообщения:
    6.243
    maxdiver
    мне лично пока это не нужно, но всё равно большое тебе спасибо.
     
  17. Stiver

    Stiver Партизан дзена

    Публикаций:
    0
    Регистрация:
    18 дек 2004
    Сообщения:
    812
    Адрес:
    Germany
    maxdiver

    Хорошая статья, спасибо. P.Ribenboim "The Book of Prime Number Records" есть в колхозе или могу выслать.
     
  18. maxdiver

    maxdiver Max

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    308
    Адрес:
    Саратов
    UbIvItS
    Stiver
    Спасибо за отзывы.