Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/spring-boot/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 给定素数N,计算下一个素数?_Algorithm_Math_Primes - Fatal编程技术网

Algorithm 给定素数N,计算下一个素数?

Algorithm 给定素数N,计算下一个素数?,algorithm,math,primes,Algorithm,Math,Primes,一位同事刚刚告诉我,C#字典集合按素数调整大小是因为与哈希有关的神秘原因。我的直接问题是,“它怎么知道下一个素数是什么?它们是在编写一个巨大的表还是在运行中进行计算?这是一个可怕的非确定性运行时,插入会导致调整大小” 所以我的问题是,给定N,这是一个素数,计算下一个素数的最有效方法是什么?已知的是,这个值非常小,素数370261的第一个间隔超过100。这意味着在大多数情况下,即使是一个简单的蛮力也足够快,平均取O(ln(p)*sqrt(p)) 对于p=10000,这是O(921)运算。请记住,每

一位同事刚刚告诉我,C#字典集合按素数调整大小是因为与哈希有关的神秘原因。我的直接问题是,“它怎么知道下一个素数是什么?它们是在编写一个巨大的表还是在运行中进行计算?这是一个可怕的非确定性运行时,插入会导致调整大小”

所以我的问题是,给定N,这是一个素数,计算下一个素数的最有效方法是什么?

已知的是,这个值非常小,素数370261的第一个间隔超过100。这意味着在大多数情况下,即使是一个简单的蛮力也足够快,平均取O(ln(p)*sqrt(p))

对于p=10000,这是O(921)运算。请记住,每插入一个O(ln(p))就执行一次(粗略地说),这完全符合大多数现代硬件上出现的毫秒级问题的限制。

没有函数f(n)来计算下一个素数。相反,必须测试数字的素性

在寻找第n个素数时,已经知道从第1个到(n-1)个的所有素数也是非常有用的,因为这些是唯一需要作为因子进行测试的数


由于这些原因,如果存在一组预先计算的大素数,我不会感到惊讶。如果某些素数需要重复计算,这对我来说真的没有意义。

以防万一有人好奇:


通过使用reflector,我确定.Net使用了一个静态类,该类包含一个硬编码列表,其中约72个素数的范围为7199369,该列表扫描至少两倍于当前大小的最小素数,对于大于当前大小的素数,它通过将所有奇数试除到潜在数的sqrt来计算下一个素数。此类是不可变且线程安全的(即,不会存储较大的素数以供将来使用)。

正如其他人已经指出的那样,还没有找到根据当前素数查找下一个素数的方法。因此,大多数算法更注重使用快速检查方法,因为必须检查已知素数和下一个素数之间的n/2


根据应用程序的不同,您也可以只对查找表进行硬编码,正如所述。

据我所知,它在当前大小的两倍旁边使用素数。它不计算素数——在这个表中,预加载的数字达到某个大值(不确切地说,大约10000000)。当达到这个数字时,它使用一些简单的算法来获得下一个数字(如curNum=curNum+1),并使用以下方法对其进行验证:

为了纯粹的新颖性,总是有这种方法:

#!/usr/bin/perl
for $p ( 2 .. 200  ) {
      next if (1x$p) =~ /^(11+)\1+$/;
      for ($n=1x(1+$p); $n =~ /^(11+)\1+$/; $n.=1) { }
      printf "next prime after %d is %d\n", $p, length($n);
}
这当然会产生

next prime after 2 is 3
next prime after 3 is 5
next prime after 5 is 7
next prime after 7 is 11
next prime after 11 is 13
next prime after 13 is 17
next prime after 17 is 19
next prime after 19 is 23
next prime after 23 is 29
next prime after 29 is 31
next prime after 31 is 37
next prime after 37 is 41
next prime after 41 is 43
next prime after 43 is 47
next prime after 47 is 53
next prime after 53 is 59
next prime after 59 is 61
next prime after 61 is 67
next prime after 67 is 71
next prime after 71 is 73
next prime after 73 is 79
next prime after 79 is 83
next prime after 83 is 89
next prime after 89 is 97
next prime after 97 is 101
next prime after 101 is 103
next prime after 103 is 107
next prime after 107 is 109
next prime after 109 is 113
next prime after 113 is 127
next prime after 127 is 131
next prime after 131 is 137
next prime after 137 is 139
next prime after 139 is 149
next prime after 149 is 151
next prime after 151 is 157
next prime after 157 is 163
next prime after 163 is 167
next prime after 167 is 173
next prime after 173 is 179
next prime after 179 is 181
next prime after 181 is 191
next prime after 191 is 193
next prime after 193 is 197
next prime after 197 is 199
next prime after 199 is 211

抛开所有的乐趣和游戏不谈,众所周知,最佳哈希表大小严格证明为
4N形式的素数−1
。所以仅仅找到下一个素数是不够的。你还必须做另一项检查。

一个好办法是使用部分筛子。例如,N=2534536543556之后的下一个素数是什么

根据小素数列表检查N的模数。因此

mod(2534536543556,[3 5 7 11 13 17 19 23 29 31 37])
ans =
     2     1     3     6     4     1     3     4    22    16    25
我们知道N后面的下一个素数必须是奇数,我们可以立即丢弃这个小素数列表的所有奇数倍数。这些模量允许我们筛选出这些小素数的倍数。如果我们使用小素数到200,我们可以使用这个方案立即丢弃大多数大于N的潜在素数,除了一个小列表

更确切地说,如果我们寻找超过2534536543556的素数,它不能被2整除,所以我们只需要考虑超过该值的奇数。上面的模表明,2534536543556与2模3是全等的,因此2534536543556+1与0模3是全等的,正如必须是2534536543556+7、2534536543556+13等。我们可以有效地筛选出许多数字,而无需测试它们的素性,也无需进行任何尝试划分

同样,事实上

mod(2534536543556,7) = 3
告诉我们2534536543556+4与0 mod 7全等。当然,这个数字是偶数,所以我们可以忽略它。但是2534536543556+11是一个奇数,可以被7整除,就像2534536543556+25一样。同样,我们可以排除这些数字,因为它们是复合数(因为它们可以被7整除),所以不是素数

仅使用最高达37个素数的小列表,我们可以排除紧跟在我们的起始点2534536543556之后的大多数数字,只有少数例外:

{2534536543573 , 2534536543579 , 2534536543597}
在这些数字中,它们是素数吗

2534536543573 = 1430239 * 1772107
2534536543579 = 99833 * 25387763
我已经尽力提供了列表中前两个数字的素因子分解。请注意,它们是复合的,但主要因素很大。当然,这是有道理的,因为我们已经确保了剩下的任何数字都不能有小的素数因子。我们的短列表中的第三个(2534536543597)实际上是N以外的第一个素数。我描述的筛选方案将倾向于产生素数,或者由通常较大的素数因子组成的数。因此,在找到下一个素数之前,我们实际上需要对几个数应用一个明确的素数测试

类似的方案很快会产生下一个超过N=10000000000000000000的素数,即10000000000000000103。

只需对素数间距离进行一些实验。
这是对其他答案的补充

我得到了从第100.000次(=1299709)到第200.000次(=2750159)的素数

一些数据:

Maximum interprime distance = 148

Mean interprime distance = 15  
互质距离频率图:

质间距离与质数


只是想看看它是“随机的”

大约一年前,我在实施 C++11的无序(散列)容器。我想我会分享的 我在这里的经历。这种经验支持f
int main()
{
    typedef std::chrono::high_resolution_clock Clock;
    typedef std::chrono::duration<double, std::milli> ms;
    Clock::time_point t0 = Clock::now();

    std::size_t n = 100000000;
    std::size_t e = 100000;
    for (std::size_t i = 0; i < e; ++i)
        n = next_prime(n+1);

    Clock::time_point t1 = Clock::now();
    std::cout << e/ms(t1-t0).count() << " primes/millisecond\n";
    return n;
}
// Overflow checking not shown for clarity purposes
n = next_prime(2*n + 1);
clang++ -stdlib=libc++ -O3 main.cpp
bool
is_prime(std::size_t x)
{
    if (x < 2)
        return false;
    for (std::size_t i = 2; i < x; ++i)
    {
        if (x % i == 0)
            return false;
    }
    return true;
}

std::size_t
next_prime(std::size_t x)
{
    for (; !is_prime(x); ++x)
        ;
    return x;
}
0.0015282 primes/millisecond
bool
is_prime(std::size_t x)
{
    if (x < 2)
        return false;
    for (std::size_t i = 2; true; ++i)
    {
        std::size_t q = x / i;
        if (q < i)
            return true;
        if (x % i == 0)
            return false;
    }
    return true;
}

std::size_t
next_prime(std::size_t x)
{
    for (; !is_prime(x); ++x)
        ;
    return x;
}
5.98576 primes/millisecond
bool
is_prime(std::size_t x)
{
    if (x < 2)
        return false;
    for (std::size_t i = 2; true; ++i)
    {
        std::size_t q = x / i;
        if (q < i)
            return true;
        if (x == q * i)
            return false;
    }
    return true;
}

std::size_t
next_prime(std::size_t x)
{
    for (; !is_prime(x); ++x)
        ;
    return x;
}

11.0512 primes/millisecond
bool
is_prime(std::size_t x)
{
    for (std::size_t i = 3; true; i += 2)
    {
        std::size_t q = x / i;
        if (q < i)
            return true;
        if (x == q * i)
            return false;
    }
    return true;
}

std::size_t
next_prime(std::size_t x)
{
    if (x <= 2)
        return 2;
    if (!(x & 1))
        ++x;
    for (; !is_prime(x); x += 2)
        ;
    return x;
}

21.9846 primes/millisecond
6 * k + {1, 5}
bool
is_prime(std::size_t x)
{
    std::size_t o = 4;
    for (std::size_t i = 5; true; i += o)
    {
        std::size_t q = x / i;
        if (q < i)
            return true;
        if (x == q * i)
            return false;
        o ^= 6;
    }
    return true;
}

std::size_t
next_prime(std::size_t x)
{
    switch (x)
    {
    case 0:
    case 1:
    case 2:
        return 2;
    case 3:
        return 3;
    case 4:
    case 5:
        return 5;
    }
    std::size_t k = x / 6;
    std::size_t i = x - 6 * k;
    std::size_t o = i < 2 ? 1 : 5;
    x = 6 * k + o;
    for (i = (3 + o) / 2; !is_prime(x); x += i)
        i ^= 6;
    return x;
}
32.6167 primes/millisecond
30 * k + {1, 7, 11, 13, 17, 19, 23, 29}
static const std::size_t small_primes[] =
{
    2,
    3,
    5,
    7,
    11,
    13,
    17,
    19,
    23,
    29
};

static const std::size_t indices[] =
{
    1,
    7,
    11,
    13,
    17,
    19,
    23,
    29
};

bool
is_prime(std::size_t x)
{
    const size_t N = sizeof(small_primes) / sizeof(small_primes[0]);
    for (std::size_t i = 3; i < N; ++i)
    {
        const std::size_t p = small_primes[i];
        const std::size_t q = x / p;
        if (q < p)
            return true;
        if (x == q * p)
            return false;
    }
    for (std::size_t i = 31; true;)
    {
        std::size_t q = x / i;
        if (q < i)
            return true;
        if (x == q * i)
            return false;
        i += 6;

        q = x / i;
        if (q < i)
            return true;
        if (x == q * i)
            return false;
        i += 4;

        q = x / i;
        if (q < i)
            return true;
        if (x == q * i)
            return false;
        i += 2;

        q = x / i;
        if (q < i)
            return true;
        if (x == q * i)
            return false;
        i += 4;

        q = x / i;
        if (q < i)
            return true;
        if (x == q * i)
            return false;
        i += 2;

        q = x / i;
        if (q < i)
            return true;
        if (x == q * i)
            return false;
        i += 4;

        q = x / i;
        if (q < i)
            return true;
        if (x == q * i)
            return false;
        i += 6;

        q = x / i;
        if (q < i)
            return true;
        if (x == q * i)
            return false;
        i += 2;
    }
    return true;
}

std::size_t
next_prime(std::size_t n)
{
    const size_t L = 30;
    const size_t N = sizeof(small_primes) / sizeof(small_primes[0]);
    // If n is small enough, search in small_primes
    if (n <= small_primes[N-1])
        return *std::lower_bound(small_primes, small_primes + N, n);
    // Else n > largest small_primes
    // Start searching list of potential primes: L * k0 + indices[in]
    const size_t M = sizeof(indices) / sizeof(indices[0]);
    // Select first potential prime >= n
    //   Known a-priori n >= L
    size_t k0 = n / L;
    size_t in = std::lower_bound(indices, indices + M, n - k0 * L) - indices;
    n = L * k0 + indices[in];
    while (!is_prime(n))
    {
        if (++in == M)
        {
            ++k0;
            in = 0;
        }
        n = L * k0 + indices[in];
    }
    return n;
}
41.6026 primes/millisecond
210 * k + {1, 11, ...},
47.685 primes/millisecond