Я ищу способ найти самое близкое простое число. Большее или меньшее, это не имеет значения, просто самое близкое (без переполнения, желательно.) Что касается скорости, то если он может вычислить его примерно через 50 миллисекунд на машине с частотой 1 ГГц (в программном обеспечении, работающем внутри Linux), я бы быть в восторге.Способ нахождения ближайшего простого числа беззнакового длинного целого (32 бита в ширину) в C?
ответ
ОБНОВЛЕНИЕ 2: Исправлено (в тяжелой форме) некоторые ошибки, которые вызвали неправильные ответы для небольших n. Спасибо Бретту Хейлу за то, что он заметил! Также добавлены некоторые утверждения для документирования некоторых допущений.
UPDATE: Я закодированы это и кажется достаточно быстр для ваших требований (решается 1000 случайных экземпляров из [2^29, 2^32-1] в < 100мс, на 2.2GHz машине - не строгое испытание, но тем не менее убедительное).
Это написано на C++, так как это мой ситовый код (который я адаптировал), но преобразование в C должно быть простым. Использование памяти также (относительно) маленькое, которое вы можете увидеть путем проверки.
Вы можете видеть, что из-за того, как вызвана функция, возвращаемое число является ближайшим числом, которое соответствует 32 битам, но на самом деле это то же самое, поскольку простые числа вокруг 2^32 равны 4294967291 и 4294967311.
Я попытался удостовериться, что ошибок из-за переполнения целого числа не будет (поскольку мы имеем дело с числами вплоть до UINT_MAX); надеюсь, я не ошибся там. Код может быть упрощен, если вы хотите использовать 64-битные типы (или вы знали, что ваши номера будут меньше, чем 2^32-256), так как вам не придется беспокоиться об обертывании в условиях цикла. Также эта идея масштабируется для больших чисел, если вы готовы вычислить/хранить небольшие простые числа до необходимого предела.
Следует отметить также, что малые прорези очень быстро работают для этих чисел (от 4 до 5 мс от грубого измерения), поэтому, если вы особенно голодны в памяти, запускайте его каждый раз вместо хранения небольших простых чисел это выполнимо (вы, вероятно, хотите, чтобы сделать отметку [] массивы больше пространства эффективно в данном случае)
#include <iostream>
#include <cmath>
#include <climits>
#include <cassert>
using namespace std;
typedef unsigned int UI;
const UI MAX_SM_PRIME = 1 << 16;
const UI MAX_N_SM_PRIMES = 7000;
const UI WINDOW = 256;
void getSMPrimes(UI primes[]) {
UI pos = 0;
primes[pos++] = 2;
bool mark[MAX_SM_PRIME/2] = {false};
UI V_SM_LIM = UI(sqrt(MAX_SM_PRIME/2));
for (UI i = 0, p = 3; i < MAX_SM_PRIME/2; ++i, p += 2)
if (!mark[i]) {
primes[pos++] = p;
if (i < V_SM_LIM)
for (UI j = p*i + p + i; j < MAX_SM_PRIME/2; j += p)
mark[j] = true;
}
}
UI primeNear(UI n, UI min, UI max, const UI primes[]) {
bool mark[2*WINDOW + 1] = {false};
if (min == 0) mark[0] = true;
if (min <= 1) mark[1-min] = true;
assert(min <= n);
assert(n <= max);
assert(max-min <= 2*WINDOW);
UI maxP = UI(sqrt(max));
for (int i = 0; primes[i] <= maxP; ++i) {
UI p = primes[i], k = min/p;
if (k < p) k = p;
UI mult = p*k;
if (min <= mult)
mark[mult-min] = true;
while (mult <= max-p) {
mult += p;
mark[mult-min] = true;
}
}
for (UI s = 0; (s <= n-min) || (s <= max-n); ++s)
if ((s <= n-min) && !mark[n-s-min])
return n-s;
else if ((s <= max-n) && !mark[n+s-min])
return n+s;
return 0;
}
int main() {
UI primes[MAX_N_SM_PRIMES];
getSMPrimes(primes);
UI n;
while (cin >> n) {
UI win_min = (n >= WINDOW) ? (n-WINDOW) : 0;
UI win_max = (n <= UINT_MAX-WINDOW) ? (n+WINDOW) : UINT_MAX;
if (!win_min)
win_max = 2*WINDOW;
else if (win_max == UINT_MAX)
win_min = win_max-2*WINDOW;
UI p = primeNear(n, win_min, win_max, primes);
cout << "found nearby prime " << p << " from window " << win_min << ' ' << win_max << '\n';
}
}
вы можете просеять интервалы в этом диапазоне, если вы знаете простых чисел до 2^16 (там всего лишь 6542 < = 2^16, вы должны пойти немного выше, если само начало может быть больше 2^32 - 1). Не обязательно самый быстрый способ, но очень простой, и более простые методы тестирования действительно подходят для гораздо больших диапазонов.
В основном, сделайте обычное сито Эратосфена, чтобы получить «маленькие» простые числа (скажем, первые 7000). Очевидно, вам нужно только сделать это один раз в начале программы, но это должно быть очень быстро.
Тогда, предположив, что ваше «целевое» число «a», рассмотрим интервал [a-n/2, a + n/2) для некоторого значения n. Вероятно, n = 128 - это разумное место для начала; вам может понадобиться попробовать соседние интервалы, если числа в первом из них являются составными.
Для каждого «малого» простого числа p вычеркните его кратность в диапазоне, используя деление, чтобы найти, с чего начать. Одна из оптимизаций заключается в том, что вам нужно только начинать сбрасывать кратность, начиная с p * p (это означает, что вы можете прекратить рассматривать простые числа, если p * p превышает интервал).
Большинство простых чисел, кроме первых, будут иметь один или нулевой кратный интервал; Чтобы воспользоваться этим, вы можете предварительно игнорировать кратность первых нескольких простых чисел. Самое простое - игнорировать все четные числа, но нередко игнорировать кратные 2, 3 и 5; это оставляет целые числа, совпадающие с 1, 7, 11, 13, 17, 19, 23 и 29 mod 30 (их восемь, которые хорошо сопоставляются с битами байта при просеивании большого диапазона).
... Вид оттуда по касательной; в любом случае, как только вы обработали все мелкие простые числа (вплоть до p * p> a + n/2), вы просто смотрите в интервале для чисел, которые вы не вычеркнули; так как вы хотите, чтобы ближайший к нему начал смотреть и искать в обоих направлениях.
Если Бретт Хейл прав в отношении наибольшего зазора, то ваш 'n' должен быть 335 или, может быть, более крупным. –
Также я бы прекомпретировал простые числа ниже 2^16 в статическую таблицу и использовал двоичный поиск, когда 'a' достаточно мало. –
Бинарный поиск - хорошая идея (я не сказал «статическая таблица», но это действительно то, что я имел в виду).Я не знаю, насколько распространен наибольший разрыв, поэтому в среднем случае может быть лучше использовать n меньше 335, а затем проверить соседние интервалы, если это необходимо (хотя, возможно, разница между n = 128 и n = 512 была бы незначительной , Я использовал этот тип конструкции для создания общего сегментированного сита и нашел интервалы размером ~ 20000, чтобы быть довольно работоспособным) –
largest prime gap в диапазоне до (2^32 - 1) есть (335). Имеются (6542) простые числа меньше (2^16), которые могут быть сведены в таблицу и использованы для сита последовательных нечетных значений после одноразовой настройки. Очевидно, что только простые числа < = floor (sqrt (кандидат)) нуждаются в проверке на конкретное значение кандидата.
В качестве альтернативы:deterministic variant of the Miller-Rabin test с SpRp основаниями: {2, 7, 61} достаточно доказать для простоты 32-битное значение. Из-за сложности теста (требует возведения в степень и т. Д.), Я сомневаюсь, что это будет так быстро для таких маленьких кандидатов.
Редактировать: Фактически, если умножить/уменьшить можно сохранить до 32-бит в экспонировании (возможно, потребуется 64-разрядная поддержка), тест M-R может быть лучше. Обычно пробелы будут значительно меньше, что делает установку сита чрезмерной. Без больших таблиц поиска и т. Д. Вы также можете повысить уровень лучшей локализации кэша.
Кроме того: Продукт простых чисел {2, 3, 5, 7, 11, 13, 17, 19, 23} = (223092870). Явно проверить любого кандидата в [2, 23]. Вычислить наибольший общий делитель: g = gcd(u, 223092870UL)
. Если (g != 1)
, кандидат является составным. Если (g == 1 && u < (29 * 29))
, кандидат (u > 23
) определенно премьер. В противном случае перейдите к более дорогим испытаниям. Один тест gcd с использованием 32-разрядной арифметики очень дешев, и согласно теореме Мертенса (?) Это обнаружит ~ 68,4% от всех нечетных составных чисел.
- 1. Сдвиг 32-битного целого числа на 32 бита
- 2. Побитовый сдвиг для беззнакового длинного длинного типа
- 3. Каков размер длинного целого числа в 32-разрядном компьютере
- 4. Быстрый алгоритм для нахождения ближайшего меньшего простого числа
- 5. unsigned int (32 бит) до беззнакового длинного длинного (64 бит)
- 6. Копировать наименьшие байты беззнакового длинного длинного массива в C
- 7. JavaScript: получите 90% целого числа, до ближайшего целого числа?
- 8. Получение битов из 32-битного беззнакового целого числа с использованием бит-сдвига в go lang
- 9. Преобразование числа в 32 бита в python
- 10. ближайшего простого числа к заданному целому числу
- 11. Вычесть Целое число от беззнакового целого числа
- 12. Округление до ближайшего целого числа
- 13. Самый эффективный способ нахождения отсутствующего целого числа в массиве
- 14. Qt: от беззнакового длинного длинного до QJsonObject
- 15. Наиболее эффективный способ поиска ближайшего целого числа в MySQL?
- 16. Округление двойного числа до ближайшего целого числа
- 17. JavaScript - Формирование длинного целого числа
- 18. Преобразование длинного целого числа Python в массив символов C
- 19. магазин целые числа (32 бита) в массиве (тип?) C программирования
- 20. Округление поплавка до ближайшего целого числа в C
- 21. Как округлить двойное значение до ближайшего целого числа в C#
- 22. C# - Округление до ближайшего целого
- 23. Печать длинного целого числа при использовании функции питания в C++
- 24. uint64_t имеет ширину всего 32 бита?
- 25. Сравнивая Long простого целого числа в Java
- 26. Радиус действия до ближайшего нечетного целого числа в SQL
- 27. Передача целого числа в качестве аргумента и интерпретация целого числа как бита в методе в java
- 28. Размер целого числа в C
- 29. модульное дополнение для беззнакового числа в c
- 30. Ищете эффективный алгоритм для нахождения ближайшего целого числа в списке целых чисел
Как получить массив из целых чисел целых чисел? – MByD
Ну, в зависимости от количества простых чисел от 0x0 до 0xFFFFFFFF, я думаю, что это был бы наиболее подходящий способ сделать это. – Erkling
Вот алгоритм поиска простых чисел, он строит от 2 до, http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes. – twain249