找到最狡猾的素数


9

介绍

考虑以下过程:在某个底数b中取某个正整数n,并用右边数字底数中的表示替换每个数字。

  • 如果右边的数字为0,请使用base b
  • 如果右边的数字是1,请使用带有0的一元符号作为计数标记。
  • 如果右边没有数字(即您在那个位置),请循环到最高有效数字。

例如,让n = 160和b =10。运行该过程如下所示:

The first digit is 1, the digit to the right is 6, 1 in base 6 is 1.
The next digit is 6, the digit to the right is 0, 0 is not a base so use b, 6 in base b is 6.
The last digit is 0, the digit to the right (looping around) is 1, 0 in base 1 is the empty string (but that's ok).

Concatenating '1', '6', and '' together gives 16, which is read in the original base b = 10.

也可以执行完全相同的过程,但向左移动而不是向右移动

The first digit is 1, the digit to the left (looping around) is 0, 0 is not a base so use b, 1 in base b is 1.
The next digit is 6, the digit to the left is 1, 6 in base 1 is 000000.
The last digit is 0, the digit to the left is 6, 0 in base 6 is 0.

Concatenating '1', '000000', and '0' together gives 10000000, which is read in the original base b = 10.

因此,我们制作了两个与160相关的数字(对于b = 10):16和10000000。

如果将在此过程中生成的两个数字中的至少一个平均分为2个或更多部分,则将n定义为狡猾的数字

在此示例中,n之所以狡猾是因为160将10000000精确地除以62500次。

203并非很狡猾,因为得出的数字是2011和203本身,而203不能平均分配2次或多次。

挑战

(对于其余问题,我们将仅考虑b =10。)

面临的挑战是编写一个程序,该程序可以找到同样也是质数最高的狡猾数字。

前七个狡猾的素数(以及到目前为止我发现的所有素数)是:

2
5
3449
6287
7589
9397
93557 <-- highest so far (I've searched to 100,000,000+)

我官方不确定是否还会存在,但我希望它们确实存在。如果您能证明确实有(或没有)很多,我会给您+200赏金代表。

赢家将是能够提供最高技巧的人,只要他们显然一直在积极搜寻并且不故意从他人身上夺取荣耀。

规则

  • 您可以使用任何所需的主要发现工具。
  • 您可以使用概率质数测试仪。
  • 您可以按署名重用其他人的代码。这是一项共同努力。绝不容忍残酷的战术。
  • 您的程序必须积极搜索素数。您可以从已知的最高狡猾的质素开始搜索。
  • 您的程序应该能够在Amazon EC2 t2.medium实例的四个小时内(一次四个或一个四个小时,或者介于两个小时之间)计算所有已知的狡猾素数。我实际上不会在它们上进行测试,您当然不需要。这只是一个基准。

这是我用于生成上表的Python 3代码:(在一两秒钟内运行)

import pyprimes

def toBase(base, digit):
    a = [
            ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
            ['', '0', '00', '000', '0000', '00000', '000000', '0000000', '00000000', '000000000' ],
            ['0', '1', '10', '11', '100', '101', '110', '111', '1000', '1001'],
            ['0', '1', '2', '10', '11', '12', '20', '21', '22', '100'],
            ['0', '1', '2', '3', '10', '11', '12', '13', '20', '21'],
            ['0', '1', '2', '3', '4', '10', '11', '12', '13', '14'],
            ['0', '1', '2', '3', '4', '5', '10', '11', '12', '13'],
            ['0', '1', '2', '3', '4', '5', '6', '10', '11', '12'],
            ['0', '1', '2', '3', '4', '5', '6', '7', '10', '11'],
            ['0', '1', '2', '3', '4', '5', '6', '7', '8', '10']
        ]
    return a[base][digit]

def getCrafty(start=1, stop=100000):
    for p in pyprimes.primes_above(start):
        s = str(p)
        left = right = ''
        for i in range(len(s)):
            digit = int(s[i])
            left += toBase(int(s[i - 1]), digit)
            right += toBase(int(s[0 if i + 1 == len(s) else i + 1]), digit)
        left = int(left)
        right = int(right)
        if (left % p == 0 and left // p >= 2) or (right % p == 0 and right // p >= 2):
            print(p, left, right)
        if p >= stop:
            break
    print('DONE')

getCrafty()

我认为在任何基数x中将0设为空字符串将更加数学。另外,我敢肯定,证明或反证该版本会更容易
骄傲的haskeller 2014年

Answers:


7

Mathematica,在0.3s内发现93,557(没有2 * 10 10以下的进一步的素数)

这只是对所有质数的幼稚详尽搜索。首先,它每55秒检查大约1,000,000个素数(随着素数变大,注定会变慢)。

我正在使用很多辅助函数:

lookup = {
  {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
  {{}, 0, {0, 0}, {0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, 
   {0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}},
  {0, 1, {1, 0}, {1, 1}, {1, 0, 0}, {1, 0, 1}, {1, 1, 0}, {1, 1, 1}, {1, 0, 0, 0}, 
   {1, 0, 0, 1}},
  {0, 1, 2, {1, 0}, {1, 1}, {1, 2}, {2, 0}, {2, 1}, {2, 2}, {1, 0, 0}},
  {0, 1, 2, 3, {1, 0}, {1, 1}, {1, 2}, {1, 3}, {2, 0}, {2, 1}},
  {0, 1, 2, 3, 4, {1, 0}, {1, 1}, {1, 2}, {1, 3}, {1, 4}},
  {0, 1, 2, 3, 4, 5, {1, 0}, {1, 1}, {1, 2}, {1, 3}},
  {0, 1, 2, 3, 4, 5, 6, {1, 0}, {1, 1}, {1, 2}},
  {0, 1, 2, 3, 4, 5, 6, 7, {1, 0}, {1, 1}},
  {0, 1, 2, 3, 4, 5, 6, 7, 8, {1, 0}}
};
convertBase[d_, b_] := lookup[[b + 1, d + 1]];
related[n_] := (
   d = IntegerDigits[n];
   {FromDigits[Flatten[convertBase @@@ Transpose[{d, RotateRight@d}]]],
    FromDigits[Flatten[convertBase @@@ Transpose[{d, RotateLeft@d}]]]}
);
crafty[n_] := (
   {ql, qr} = related[n]/n;
   IntegerQ[ql] && ql > 1 || IntegerQ[qr] && qr > 1
);

然后,此循环执行实际搜索:

p = 2;
start = TimeUsed[];
i = 1;
While[True,
 If[crafty[p], Print@{"CRAFTY PRIME:", p, TimeUsed[] - start}];
 p = NextPrime@p;
 If[Mod[++i, 1000000] == 0, 
  Print[{"Last prime checked:", p, TimeUsed[] - start}]
 ]
]

如果发现任何素数或可以想到的优化,我将继续更新该帖子。

目前,它会在约5.5分钟内检查所有最大为100,000,000的素数。

编辑:我决定遵循OP的示例,并切换到用于基本转换的查找表。这使速度提高了大约30%。

一般的狡猾数字

我现在要停止搜索狡猾的素数,因为我需要几天时间才能赶上Perl答案的出路。相反,我开始搜索所有狡猾的号码。也许它们的分布有助于找到证明狡猾素数是有限还是无限的证明。

我定义了右手数字,这些数字将通过将右边的数字解释为新的底数而获得的相关数字进行划分,并相应地左手数字。单独解决这些问题可能会有所帮助。

以下是所有高达22.10亿的左手数字:

{2, 5, 16, 28, 68, 160, 222, 280, 555, 680, 777, 1600, 2605, 2800, 
 6800, 7589, 7689, 9397, 9777, 16000, 16064, 16122, 22222, 24682, 
 26050, 28000, 55555, 68000, 75890, 76890, 93557, 160000, 160640, 
 161220, 247522, 254408, 260500, 280000, 680000, 758900, 768900, 
 949395, 1600000, 1606400, 1612200, 2222222, 2544080, 2605000, 
 2709661, 2710271, 2717529, 2800000, 3517736, 5555555, 6800000, 
 7589000, 7689000, 9754696, 11350875, 16000000, 16064000, 16122000,
 25440800, 26050000, 27175290, 28000000, 28028028, 35177360, 52623721, 
 68000000, 68654516, 75890000, 76890000, 113508750, 129129129, 160000000,
 160640000, 161220000, 222222222, 254408000, 260500000, 271752900,
 275836752, 280000000, 280280280, 333018547, 351773600, 370938016, 
 555555555, 680000000, 758900000, 768900000, 777777777, 877827179, 
 1135087500, 1291291290, 1600000000, 1606400000, 1612200000, 1944919449}

这是该范围内的所有狡猾数字:

{2, 5, 16, 28, 68, 125, 128, 175, 222, 284, 555, 777, 1575, 1625, 
 1875, 3449, 5217, 6287, 9375, 14625, 16736, 19968, 22222, 52990, 
 53145, 55555, 58750, 93750, 127625, 152628, 293750, 529900, 587500, 
 593750, 683860, 937500, 1034375, 1340625, 1488736, 2158750, 2222222, 
 2863740, 2937500, 5299000, 5555555, 5875000, 5937500, 6838600, 
 7577355, 9375000, 12071125, 19325648, 21587500, 28637400, 29375000, 
 29811250, 42107160, 44888540, 52990000, 58750000, 59375000, 68386000, 
 71461386, 74709375, 75773550, 93750000, 100540625, 116382104,
 164371875, 197313776, 207144127, 215875000, 222222222, 226071269,
 227896480, 274106547, 284284284, 286374000, 287222080, 293750000, 
 298112500, 421071600, 448885400, 529900000, 555555555, 587500000, 
 593750000, 600481125, 683860000, 714613860, 747093750, 757735500, 
 769456199, 777777777, 853796995, 937500000, 1371513715, 1512715127, 
 1656354715, 1728817288, 1944919449, 2158750000}

请注意,存在无限数量的左手数和右手数,因为有几种方法可以从现有数中生成它们:

  • 一个人可以将0s 的任意数附加到其最低有效位数大于其最高有效位数的任何左手位数上,以获得另一个左手位数。
  • 同样,可以将任意数量的0s 附加到其最低有效位数小于其最高有效位数的任何右手技巧数字中。之所以如此(以及之前的声明),是因为0将会被附加到狡猾的数字及其相关数字上,从而将两者有效地乘以10。
  • 2s或5s的每个奇数都是狡猾的。
  • 777s的每个奇数都是狡猾的。
  • 似乎有个奇数个280s 联接,就像28028028总是左撇子一样。

其他注意事项:

  • 至少有四个10位数字,其中包括两个重复的五位数字(它们本身并不狡猾,但是无论如何这里可能会有某种模式)。
  • 有许多乘以右上角的数字125。可能值得调查那些以找到另一条生产规则。
  • 我没有找到以4开头或以3结尾的左手数字。
  • 右手数字可以以任何数字开头,但我还没有找到以1或3结尾的右手数字。

我想如果我省略那些因较小的狡猾人数而隐含存在的人,尤其是因为到目前为止所发现的构造规则都不是质数的话,此列表将更为有趣。因此,这是所有无法用上述规则之一构造的素数:

Left-crafty:
{16, 68, 2605, 7589, 7689, 9397, 9777, 16064, 16122, 24682, 
 93557, 247522, 254408, 949395, 2709661, 2710271, 2717529, 3517736,
 9754696, 11350875, 52623721, 68654516, 129129129, 275836752, 
 333018547, 370938016, 877827179, 1944919449}

Right-crafty:
{16, 28, 68, 125, 128, 175, 284, 1575, 1625, 1875, 3449, 5217, 
 6287, 9375, 14625, 16736, 19968, 52990, 53145, 58750, 127625, 
 152628, 293750, 593750, 683860, 1034375, 1340625, 1488736, 2158750,
 2863740, 7577355, 12071125, 19325648, 29811250, 42107160, 44888540,
 71461386, 74709375, 100540625, 116382104, 164371875, 197313776,
 207144127, 226071269, 227896480, 274106547, 284284284, 287222080, 
 600481125, 769456199, 853796995, 1371513715, 1512715127, 1656354715, 
 1728817288, 1944919449}

还要注意,存在一些双重的数字(出现在两个列表中,因此将两个相关的数字相除):

{2, 5, 16, 28, 68, 222, 555, 777, 22222, 55555, 2222222, 5555555, 1944919449}

这些也无限地存在。但正如你所看到的,只是162868这些都仅由一个单一的(重复)的数字。证明是否有任何较大的数字是否可以具有双重欺骗性也很有趣,但是,这可能只是作为单个欺骗性数字证明的必然结果而消失。找到了反例1944919449


您是否有任何理由要100540625, 100540625列入列表?
isaacg

1
@isaacg是的。因为我无法复制和粘贴。
马丁·恩德

因为没有人发现93,557以上的狡猾素数,所以接受了这一点。这是第一个答案,票数最高,而且涉及最深。
加尔文的爱好2014年

6

Perl(0.03s中为1e5,21s中为1e8)。最多93557至1e11。

与原始版本非常相似。更改包括:

  • 转置基本查找。依赖于语言的少量节省。
  • mod递增的右移,而不是if。与语言有关的微选项。
  • 使用Math :: GMPz,因为Perl 5没有像Python和Perl 6这样的自动魔术bigint。
  • 使用2s <= left而不是int(left / s)> =2。本机整数移位与bigint除法。

在我的快速计算机上,第一个1e8会在21秒内启动,在1e9上会启动3.5分钟,在1e10上会启动34分钟。令我有些惊讶的是它的速度比Python输入小得多。我们可以并行化(Pari / GP的新版本parforprime对此很好)。既然是搜索,我想forprimes可以手动并行化(可以接受两个参数)。 forprimes基本上就像Pari / GP一样forprime-它会在内部对筛网进行分段,并使用每个结果调用该块。这很方便,但是对于这个问题,我认为这不是性能领域。

#!/usr/bin/env perl
use warnings;
use strict;
use Math::Prime::Util qw/forprimes/;
use Math::GMPz;

my @rbase = (
  [   0,"",       0,   0,  0, 0, 0, 0, 0, 0],
  [qw/1 0         1    1   1  1  1  1  1  1/],
  [qw/2 00        10   2   2  2  2  2  2  2/],
  [qw/3 000       11   10  3  3  3  3  3  3/],
  [qw/4 0000      100  11  10 4  4  4  4  4/],
  [qw/5 00000     101  12  11 10 5  5  5  5/],
  [qw/6 000000    110  20  12 11 10 6  6  6/],
  [qw/7 0000000   111  21  13 12 11 10 7  7/],
  [qw/8 00000000  1000 22  20 13 12 11 10 8/],
  [qw/9 000000000 1001 100 21 14 13 12 11 10/],
);

my($s,$left,$right,$slen,$i,$barray);
forprimes {
  ($s,$slen,$left,$right) = ($_,length($_),'','');
  foreach $i (0 .. $slen-1) {
    $barray = $rbase[substr($s,$i,1)];
    $left  .= $barray->[substr($s,$i-1,1)];
    $right .= $barray->[substr($s,($i+1) % $slen,1)];
  }
  $left = Math::GMPz::Rmpz_init_set_str($left,10) if length($left) >= 20;
  $right = Math::GMPz::Rmpz_init_set_str($right,10) if length($right) >= 20;
  print "$s      $left $right\n" if (($s<<1) <= $left && $left % $s == 0)
                                 || (($s<<1) <= $right && $right % $s == 0);
} 1e9;

5

具有线程和GMP的C ++ 11

计时(在MacBook Air上):

  • 4个线程
    • 10 ^ 8在2.18986s
    • 21.3829秒中的10 ^ 9
    • 10 ^ 10 in 421.392s
    • 10557年11月2557.22秒
  • 1个线程
    • 3.95095s中的10 ^ 8
    • 10 ^ 9在37.7009s

要求:

#include <vector>
#include <iostream>
#include <chrono>
#include <cmath>
#include <future>
#include <mutex>
#include <atomic>
#include "primesieve.hpp"
#include "gmpxx.h"

using namespace std;

using ull = unsigned long long;

mutex cout_mtx;
atomic<ull> prime_counter;


string ppnum(ull number) {
    if (number == 0) {
        return "0 * 10^0";
    }
    else {
        int l = floor(log10(number));
        return to_string(number / pow(10, l)) + " * 10^" + to_string(int(l));
    }
}


inline void bases(int& base, int& digit, mpz_class& sofar) {
    switch (base) {
        case 0:
            sofar *= 10;
            sofar += digit;
            break;
        case 1:
            sofar *= pow(10, digit);
            break;
        case 2:
            switch (digit) {
                case 0: sofar *= 10; break;
                case 1: sofar *= 10; sofar += 1; break;
                case 2: sofar *= 100; sofar += 10; break;
                case 3: sofar *= 100; sofar += 11; break;
                case 4: sofar *= 1000; sofar += 100; break;
                case 5: sofar *= 1000; sofar += 101; break;
                case 6: sofar *= 1000; sofar += 110; break;
                case 7: sofar *= 1000; sofar += 111; break;
                case 8: sofar *= 10000; sofar += 1000; break;
                case 9: sofar *= 10000; sofar += 1001; break;
            }
            break;
        case 3:
            switch (digit) {
                case 0: sofar *= 10; break;
                case 1: sofar *= 10; sofar += 1; break;
                case 2: sofar *= 10; sofar += 2; break;
                case 3: sofar *= 100; sofar += 10; break;
                case 4: sofar *= 100; sofar += 11; break;
                case 5: sofar *= 100; sofar += 12; break;
                case 6: sofar *= 100; sofar += 20; break;
                case 7: sofar *= 100; sofar += 21; break;
                case 8: sofar *= 100; sofar += 22; break;
                case 9: sofar *= 1000; sofar += 100; break;
            }
            break;
        case 4:
            switch (digit) {
                case 0: sofar *= 10; break;
                case 1: sofar *= 10; sofar += 1; break;
                case 2: sofar *= 10; sofar += 2; break;
                case 3: sofar *= 10; sofar += 3; break;
                case 4: sofar *= 100; sofar += 10; break;
                case 5: sofar *= 100; sofar += 11; break;
                case 6: sofar *= 100; sofar += 12; break;
                case 7: sofar *= 100; sofar += 13; break;
                case 8: sofar *= 100; sofar += 20; break;
                case 9: sofar *= 100; sofar += 21; break;
            }
            break;
        case 5:
            switch (digit) {
                case 0: sofar *= 10; break;
                case 1: sofar *= 10; sofar += 1; break;
                case 2: sofar *= 10; sofar += 2; break;
                case 3: sofar *= 10; sofar += 3; break;
                case 4: sofar *= 10; sofar += 4; break;
                case 5: sofar *= 100; sofar += 10; break;
                case 6: sofar *= 100; sofar += 11; break;
                case 7: sofar *= 100; sofar += 12; break;
                case 8: sofar *= 100; sofar += 13; break;
                case 9: sofar *= 100; sofar += 14; break;
            }
            break;
        case 6:
            switch (digit) {
                case 0: sofar *= 10; break;
                case 1: sofar *= 10; sofar += 1; break;
                case 2: sofar *= 10; sofar += 2; break;
                case 3: sofar *= 10; sofar += 3; break;
                case 4: sofar *= 10; sofar += 4; break;
                case 5: sofar *= 10; sofar += 5; break;
                case 6: sofar *= 100; sofar += 10; break;
                case 7: sofar *= 100; sofar += 11; break;
                case 8: sofar *= 100; sofar += 12; break;
                case 9: sofar *= 100; sofar += 13; break;
            }
            break;
        case 7:
            switch (digit) {
                case 0: sofar *= 10; break;
                case 1: sofar *= 10; sofar += 1; break;
                case 2: sofar *= 10; sofar += 2; break;
                case 3: sofar *= 10; sofar += 3; break;
                case 4: sofar *= 10; sofar += 4; break;
                case 5: sofar *= 10; sofar += 5; break;
                case 6: sofar *= 10; sofar += 6; break;
                case 7: sofar *= 100; sofar += 10; break;
                case 8: sofar *= 100; sofar += 11; break;
                case 9: sofar *= 100; sofar += 12; break;
            }
            break;
        case 8:
            switch (digit) {
                case 0: sofar *= 10; break;
                case 1: sofar *= 10; sofar += 1; break;
                case 2: sofar *= 10; sofar += 2; break;
                case 3: sofar *= 10; sofar += 3; break;
                case 4: sofar *= 10; sofar += 4; break;
                case 5: sofar *= 10; sofar += 5; break;
                case 6: sofar *= 10; sofar += 6; break;
                case 7: sofar *= 10; sofar += 7; break;
                case 8: sofar *= 100; sofar += 10; break;
                case 9: sofar *= 100; sofar += 11; break;
            }
            break;
        case 9:
            switch (digit) {
                case 0: sofar *= 10; break;
                case 1: sofar *= 10; sofar += 1; break;
                case 2: sofar *= 10; sofar += 2; break;
                case 3: sofar *= 10; sofar += 3; break;
                case 4: sofar *= 10; sofar += 4; break;
                case 5: sofar *= 10; sofar += 5; break;
                case 6: sofar *= 10; sofar += 6; break;
                case 7: sofar *= 10; sofar += 7; break;
                case 8: sofar *= 10; sofar += 8; break;
                case 9: sofar *= 100; sofar += 10; break;
            }
            break;
    };
}

vector<ull> crafty(ull start, ull stop) {
    cout_mtx.lock();
    cout << "Thread scanning from " << start << " to " << stop << endl;
    cout_mtx.unlock();
    vector<ull> res;

    auto prime_iter = primesieve::iterator(start);
    ull num;
    int prev, curr, next, fprev;
    int i, size;
    mpz_class left, right;
    unsigned long num_cpy;
    unsigned long* num_ptr;
    mpz_class num_mpz;


    while ((num = prime_iter.next_prime()) && num < stop) {
        ++prime_counter;
        left = 0;
        right = 0;
        size = floor(log10(num));
        i = pow(10, size);
        prev = num % 10;
        fprev = curr = num / i;
        if (i != 1) {
            i /= 10;
            next = (num / i) % 10;
        }
        else {
            next = prev;
        }
        for (size += 1; size; --size) {
            bases(prev, curr, left);
            bases(next, curr, right);
            prev = curr;
            curr = next;
            if (i > 1) {
                i /= 10;
                next = (num / i) % 10;
            }
            else {
                next = fprev;
            }
        }
        num_cpy = num;

        if (num != num_cpy) {
            num_ptr = (unsigned long *) &num;
            num_mpz = *num_ptr;
            num_mpz << sizeof(unsigned long) * 8;
            num_mpz += *(num_ptr + 1);
        }
        else {
            num_mpz = num_cpy;
        }
        if ((left % num_mpz == 0 && left / num_mpz >= 2) || (right % num_mpz == 0 && right / num_mpz >= 2)) {
            res.push_back(num);
        }
    }
    cout_mtx.lock();
    cout << "Thread scanning from " << start << " to " << stop << " is done." << endl;;
    cout << "Found " << res.size() << " crafty primes." << endl;
    cout_mtx.unlock();
    return res;
}

int main(int argc, char *argv[]) {
    ull start = 0, stop = 1000000000;
    int number_of_threads = 4;

    if (argc > 1) {
        start = atoll(argv[1]);
    }
    if (argc > 2) {
        stop = atoll(argv[2]);
    }
    if (argc > 3) {
        number_of_threads = atoi(argv[3]);
    }
    ull gap = stop - start;

    cout << "Start: " << ppnum(start) << ", stop: " << ppnum(stop) << endl;
    cout << "Scanning " << ppnum(gap) << " numbers" << endl;
    cout << "Number of threads: " << number_of_threads << endl;

    chrono::time_point<chrono::system_clock> tstart, tend;
    tstart = chrono::system_clock::now();

    cout << "Checking primes..." << endl;

    using ptask = packaged_task<decltype(crafty)>;
    using fur = future<vector<ull>>;

    vector<thread> threads;
    vector<fur> futures;
    for (int i = 0; i < number_of_threads; ++i) {
        auto p = ptask(crafty);
        futures.push_back(move(p.get_future()));
        auto tstop = (i + 1 == number_of_threads) ? (stop) : (start + gap / number_of_threads * (i + 1));
        threads.push_back(thread(move(p), start + gap / number_of_threads * i, tstop));
    }

    vector<ull> res;

    for (auto& thread : threads) {
        thread.join();
    }

    for (auto& fut : futures) {
        auto v = fut.get();
        res.insert(res.end(), v.begin(), v.end());
    }

    cout << "Finished checking primes..." << endl;

    tend = chrono::system_clock::now();
    chrono::duration<double> elapsed_seconds = tend - tstart;

    cout << "Number of tested primes: " << ppnum(prime_counter) << endl;
    cout << "Number of found crafty primes: " << res.size() << endl;
    cout << "Crafty primes are: ";
    for (auto iter = res.begin(); iter != res.end(); ++iter) {
        if (iter != res.begin())
            cout << ", ";
        cout << *iter;
    }
    cout << endl;
    cout << "Time taken: " << elapsed_seconds.count() << endl;
}

输出:

Start: 0 * 10^0, stop: 1.000000 * 10^11
Scanning 1.000000 * 10^11 numbers
Number of threads: 4
Checking primes...
Thread scanning from 25000000000 to 50000000000
Thread scanning from 0 to 25000000000
Thread scanning from 50000000000 to 75000000000
Thread scanning from 75000000000 to 100000000000
Thread scanning from 75000000000 to 100000000000 is done.
Found 0 crafty primes.
Thread scanning from 50000000000 to 75000000000 is done.
Found 0 crafty primes.
Thread scanning from 25000000000 to 50000000000 is done.
Found 0 crafty primes.
Thread scanning from 0 to 25000000000 is done.
Found 7 crafty primes.
Finished checking primes...
Number of tested primes: 4.118055 * 10^9
Number of found crafty primes: 7
Crafty primes are: 2, 5, 3449, 6287, 7589, 9397, 93557
Time taken: 2557.22

在num = 12919处,right应该是120000000001000000000。这溢出了64位int,并且在您的程序中r =9223372036854775807。我认为您将需要使用GMP或类似的东西。
DanaJ

非常好。具有12个线程的3930K的时间是421s中1e10和1e11的54s。
DanaJ

尝试并发C ++ 11功能是一个很好的借口
matsjoyce 2014年

1

C,带GMP,多线程(1线程在17秒内为1e8)

在概念上与其余类似,可能在各处进行了一些优化。

编译: gcc -I/usr/local/include -Ofast crafty.c -pthread -L/usr/local/lib -lgmp && ./a.out

请捐赠您的CPU电源。我没有一台快速的电脑。
我的Macbook air上有1个线程,在17秒内完成1e8。

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <gmp.h>
#include <pthread.h>
#include <string.h>

#define THREAD_COUNT 1           // Number of threads
#define MAX_DIGITS   32768       // Maximum digits allocated for the string... some c stuff
#define MAX_NUMBER   "100000000" // Number in string format
#define START_INDEX  1           // Must be an odd number >= 1
#define GET_WRAP_INDEX(index, stringLength) index<0?stringLength+index:index>=stringLength?index-stringLength:index

static void huntCraftyPrime(int startIndex) {

    char lCS [MAX_DIGITS];
    char rCS [MAX_DIGITS];
    char tPS [MAX_DIGITS];

    mpz_t tP, lC, rC, max;
    mpz_init_set_ui(tP, startIndex);
    mpz_init(lC);
    mpz_init(rC);
    mpz_init_set_str(max, MAX_NUMBER, 10);

    int increment = THREAD_COUNT*2;

    if (START_INDEX < 9 && startIndex == START_INDEX) {
        printf("10 10 2\n\n");
        printf("10 10 5\n\n");
    }

    while (mpz_cmp(max, tP) > 0) {
        mpz_get_str(tPS, 10, tP);
        int tPSLength = strlen(tPS);
        int l = 0, r = 0, p = 0;
        while (p < tPSLength) {
            char lD = tPS[GET_WRAP_INDEX(p-1, tPSLength)];
            char d  = tPS[GET_WRAP_INDEX(p  , tPSLength)];
            char rD = tPS[GET_WRAP_INDEX(p+1, tPSLength)];
            if (d == '0') {
                if (lD != '1') lCS[l++] = '0';
                if (rD != '1') rCS[r++] = '0';
            } else if (d == '1') {
                lCS[l++] = (lD != '1') ? '1' : '0';
                rCS[r++] = (rD != '1') ? '1' : '0';
            } else if (d == '2') {
                if (lD == '1') {
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                } else if (lD == '2') {
                    lCS[l++] = '1';
                    lCS[l++] = '0';
                } else {
                    lCS[l++] = '2';
                }
                if (rD == '1') {
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                } else if (rD == '2') {
                    rCS[r++] = '1';
                    rCS[r++] = '0';
                } else {
                    rCS[r++] = '2';
                }
            } else if (d == '3') {
                if (lD == '1') {
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                } else if (lD == '2') {
                    lCS[l++] = '1';
                    lCS[l++] = '1';
                } else if (lD == '3') {
                    lCS[l++] = '1';
                    lCS[l++] = '0';
                } else {
                    lCS[l++] = '3';
                }
                if (rD == '1') {
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                } else if (rD == '2') {
                    rCS[r++] = '1';
                    rCS[r++] = '1';
                } else if (rD == '3') {
                    rCS[r++] = '1';
                    rCS[r++] = '0';
                } else {
                    rCS[r++] = '3';
                }
            } else if (d == '4') {
                if (lD == '1') {
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                } else if (lD == '2') {
                    lCS[l++] = '1';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                } else if (lD == '3') {
                    lCS[l++] = '1';
                    lCS[l++] = '1';
                } else if (lD == '4') {
                    lCS[l++] = '1';
                    lCS[l++] = '0';
                } else {
                    lCS[l++] = '4';
                }
                if (rD == '1') {
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                } else if (rD == '2') {
                    rCS[r++] = '1';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                } else if (rD == '3') {
                    rCS[r++] = '1';
                    rCS[r++] = '1';
                } else if (rD == '4') {
                    rCS[r++] = '1';
                    rCS[r++] = '0';
                } else {
                    rCS[r++] = '4';
                }
            } else if (d == '5') {
                if (lD == '1') {
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                } else if (lD == '2') {
                    lCS[l++] = '1';
                    lCS[l++] = '0';
                    lCS[l++] = '1';
                } else if (lD == '3') {
                    lCS[l++] = '1';
                    lCS[l++] = '2';
                } else if (lD == '4') {
                    lCS[l++] = '1';
                    lCS[l++] = '1';
                } else if (lD == '5') {
                    lCS[l++] = '1';
                    lCS[l++] = '0';
                } else {
                    lCS[l++] = '5';
                }
                if (rD == '1') {
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                } else if (rD == '2') {
                    rCS[r++] = '1';
                    rCS[r++] = '0';
                    rCS[r++] = '1';
                } else if (rD == '3') {
                    rCS[r++] = '1';
                    rCS[r++] = '2';
                } else if (rD == '4') {
                    rCS[r++] = '1';
                    rCS[r++] = '1';
                } else if (rD == '5') {
                    rCS[r++] = '1';
                    rCS[r++] = '0';
                } else {
                    rCS[r++] = '5';
                }
            } else if (d == '6') {
                if (lD == '1') {
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                } else if (lD == '2') {
                    lCS[l++] = '1';
                    lCS[l++] = '1';
                    lCS[l++] = '0';
                } else if (lD == '3') {
                    lCS[l++] = '2';
                    lCS[l++] = '0';
                } else if (lD == '4') {
                    lCS[l++] = '1';
                    lCS[l++] = '2';
                } else if (lD == '5') {
                    lCS[l++] = '1';
                    lCS[l++] = '1';
                } else if (lD == '6') {
                    lCS[l++] = '1';
                    lCS[l++] = '0';
                } else {
                    lCS[l++] = '6';
                }
                if (rD == '1') {
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                } else if (rD == '2') {
                    rCS[r++] = '1';
                    rCS[r++] = '1';
                    rCS[r++] = '0';
                } else if (rD == '3') {
                    rCS[r++] = '2';
                    rCS[r++] = '0';
                } else if (rD == '4') {
                    rCS[r++] = '1';
                    rCS[r++] = '2';
                } else if (rD == '5') {
                    rCS[r++] = '1';
                    rCS[r++] = '1';
                } else if (rD == '6') {
                    rCS[r++] = '1';
                    rCS[r++] = '0';
                } else {
                    rCS[r++] = '6';
                }
            } else if (d == '7') {
                if (lD == '1') {
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                } else if (lD == '2') {
                    lCS[l++] = '1';
                    lCS[l++] = '1';
                    lCS[l++] = '1';
                } else if (lD == '3') {
                    lCS[l++] = '2';
                    lCS[l++] = '1';
                } else if (lD == '4') {
                    lCS[l++] = '1';
                    lCS[l++] = '3';
                } else if (lD == '5') {
                    lCS[l++] = '1';
                    lCS[l++] = '2';
                } else if (lD == '6') {
                    lCS[l++] = '1';
                    lCS[l++] = '1';
                } else if (lD == '7') {
                    lCS[l++] = '1';
                    lCS[l++] = '0';
                } else {
                    lCS[l++] = '7';
                }
                if (rD == '1') {
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                } else if (rD == '2') {
                    rCS[r++] = '1';
                    rCS[r++] = '1';
                    rCS[r++] = '1';
                } else if (rD == '3') {
                    rCS[r++] = '2';
                    rCS[r++] = '1';
                } else if (rD == '4') {
                    rCS[r++] = '1';
                    rCS[r++] = '3';
                } else if (rD == '5') {
                    rCS[r++] = '1';
                    rCS[r++] = '2';
                } else if (rD == '6') {
                    rCS[r++] = '1';
                    rCS[r++] = '1';
                } else if (rD == '7') {
                    rCS[r++] = '1';
                    rCS[r++] = '0';
                } else {
                    rCS[r++] = '7';
                }
            } else if (d == '8') {
                if (lD == '1') {
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                } else if (lD == '2') {
                    lCS[l++] = '1';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                } else if (lD == '3') {
                    lCS[l++] = '2';
                    lCS[l++] = '2';
                } else if (lD == '4') {
                    lCS[l++] = '2';
                    lCS[l++] = '0';
                } else if (lD == '5') {
                    lCS[l++] = '1';
                    lCS[l++] = '3';
                } else if (lD == '6') {
                    lCS[l++] = '1';
                    lCS[l++] = '2';
                } else if (lD == '7') {
                    lCS[l++] = '1';
                    lCS[l++] = '1';
                } else if (lD == '8') {
                    lCS[l++] = '1';
                    lCS[l++] = '0';
                } else {
                    lCS[l++] = '8';
                }
                if (rD == '1') {
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                } else if (rD == '2') {
                    rCS[r++] = '1';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                } else if (rD == '3') {
                    rCS[r++] = '2';
                    rCS[r++] = '2';
                } else if (rD == '4') {
                    rCS[r++] = '2';
                    rCS[r++] = '0';
                } else if (rD == '5') {
                    rCS[r++] = '1';
                    rCS[r++] = '3';
                } else if (rD == '6') {
                    rCS[r++] = '1';
                    rCS[r++] = '2';
                } else if (rD == '7') {
                    rCS[r++] = '1';
                    rCS[r++] = '1';
                } else if (rD == '8') {
                    rCS[r++] = '1';
                    rCS[r++] = '0';
                } else {
                    rCS[r++] = '8';
                }
            } else if (d == '9') {
                if (lD == '1') {
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                } else if (lD == '2') {
                    lCS[l++] = '1';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                    lCS[l++] = '1';
                } else if (lD == '3') {
                    lCS[l++] = '1';
                    lCS[l++] = '0';
                    lCS[l++] = '0';
                } else if (lD == '4') {
                    lCS[l++] = '2';
                    lCS[l++] = '1';
                } else if (lD == '5') {
                    lCS[l++] = '1';
                    lCS[l++] = '4';
                } else if (lD == '6') {
                    lCS[l++] = '1';
                    lCS[l++] = '3';
                } else if (lD == '7') {
                    lCS[l++] = '1';
                    lCS[l++] = '2';
                } else if (lD == '8') {
                    lCS[l++] = '1';
                    lCS[l++] = '1';
                } else if (lD == '9') {
                    lCS[l++] = '1';
                    lCS[l++] = '0';
                } else {
                    lCS[l++] = '9';
                }
                if (rD == '1') {
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                } else if (rD == '2') {
                    rCS[r++] = '1';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                    rCS[r++] = '1';
                } else if (rD == '3') {
                    rCS[r++] = '1';
                    rCS[r++] = '0';
                    rCS[r++] = '0';
                } else if (rD == '4') {
                    rCS[r++] = '2';
                    rCS[r++] = '1';
                } else if (rD == '5') {
                    rCS[r++] = '1';
                    rCS[r++] = '4';
                } else if (rD == '6') {
                    rCS[r++] = '1';
                    rCS[r++] = '3';
                } else if (rD == '7') {
                    rCS[r++] = '1';
                    rCS[r++] = '2';
                } else if (rD == '8') {
                    rCS[r++] = '1';
                    rCS[r++] = '1';
                } else if (rD == '9') {
                    rCS[r++] = '1';
                    rCS[r++] = '0';
                } else {
                    rCS[r++] = '9';
                }
            }
            ++p;
        }
        lCS[l] = '\0';
        rCS[r] = '\0';

        mpz_set_str(lC, lCS, 10);
        mpz_set_str(rC, rCS, 10);

        if ((mpz_divisible_p(lC, tP) && mpz_cmp(lC, tP) > 0) || (mpz_divisible_p(rC, tP) && mpz_cmp(rC, tP) > 0)){
            if (mpz_millerrabin(tP, 25)) {
                gmp_printf("%Zd %Zd %Zd\n\n", lC, rC, tP);
            }
        }
        mpz_add_ui(tP, tP, increment);
    }
}

static void *huntCraftyPrimeThread(void *p) {
    int* startIndex = (int*) p;
    huntCraftyPrime(*startIndex);
    pthread_exit(NULL);
}

int main(int argc, char *argv[]) {

    struct timeval time_started, time_now, time_diff;
    gettimeofday(&time_started, NULL);

    int  startIndexes[THREAD_COUNT];
    pthread_t threads[THREAD_COUNT];

    int startIndex = START_INDEX;
    for (int i = 0; i < THREAD_COUNT; ++i) {
        for (;startIndex % 2 == 0; ++startIndex);
        startIndexes[i] = startIndex;
        int rc = pthread_create(&threads[i], NULL, huntCraftyPrimeThread, (void*)&startIndexes[i]); 
        if (rc) { 
            printf("ERROR; return code from pthread_create() is %d\n", rc);
            exit(-1);
        }
        ++startIndex;
    }

    for (int i = 0; i < THREAD_COUNT; ++i) {
        void * status;
        int rc = pthread_join(threads[i], &status);
        if (rc) {
            printf("ERROR: return code from pthread_join() is %d\n", rc);
            exit(-1);
        }
    }

    gettimeofday(&time_now, NULL);
    timersub(&time_now, &time_started, &time_diff);
    printf("Time taken,%ld.%.6d s\n", time_diff.tv_sec, time_diff.tv_usec);

    pthread_exit(NULL);
    return 0;
}

0

Python,在0.28秒内发现93557

与OP的代码非常相似,因为它也使用pyprimes。我确实是通过xD自己写的

import pyprimes, time

d = time.clock()

def to_base(base, n):
    if base == 1:
        return '0'*n
    s = ""
    while n:
        s = str(n % base) + s
        n //= base
    return s

def crafty(n):
    digits = str(n)
    l, r = "", ""
    for i in range(len(digits)):
        t = int(digits[i])
        base = int(digits[i-1])
        l += to_base(base, t) if base else digits[i]
        base = int(digits[(i+1)%len(digits)])
        r += to_base(base, t) if base else digits[i]
    l, r = int(l) if l else 0, int(r) if r else 0
    if (l%n==0 and 2 <= l/n) or (r%n==0 and 2 <= r/n):
        print(n, l, r, time.clock()-d)

for i in pyprimes.primes_above(1):
    crafty(i)

它还会打印出自找到以来的时间。

输出:

2 10 10 3.156656792490237e-05
5 10 10 0.0006756015452219958
3449 3111021 3104100 0.012881854420378145
6287 6210007 11021111 0.022036544076745254
7589 751311 125812 0.026288406792971432
9397 1231007 1003127 0.03185028207808106
93557 123121012 10031057 0.27897531840850603

格式为number left right time。作为比较,OP的代码在中找到93557 0.37

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.