C# Miller-Rabin素性测试在大数情况下失败

C# Miller-Rabin素性测试在大数情况下失败,c#,primes,prime-factoring,C#,Primes,Prime Factoring,在研究了与Miller-Rabin素数测试相关的其他答案后,我用C#实现了一个版本,但它偶尔会在30亿左右的某个地方失败,当它达到40亿时,它就不再识别任何素数了。我怀疑我正在遭受溢流,但不知道在哪里。我的目标是使其适用于0=1范围内的任何值; } 随机r=新随机(); for(int i=0;i(a^2)^9*a->((a^2)^2)^4*(a^2))*a->(((a^2)^2)^2*(a^2))*a 如果(b==0L)返回1L; 如果(a==0L)返回0L; 如果(b==1L)返回%n; v

在研究了与Miller-Rabin素数测试相关的其他答案后,我用C#实现了一个版本,但它偶尔会在30亿左右的某个地方失败,当它达到40亿时,它就不再识别任何素数了。我怀疑我正在遭受溢流,但不知道在哪里。我的目标是使其适用于0=1范围内的任何值; } 随机r=新随机(); for(int i=0;i通常会溢出的简单计算 //例如:对于^19,有五个平方、两个乘法和七个模,而不是18个乘法和18个模 //a^19->(a^2)^9*a->((a^2)^2)^4*(a^2))*a->(((a^2)^2)^2*(a^2))*a 如果(b==0L)返回1L; 如果(a==0L)返回0L; 如果(b==1L)返回%n; var r=模功率(a,b>>1,n); r=俄罗斯的农民(r,r,n); 如果((b&1L)=1L) r=俄罗斯的农民(r,a,n); 返回r; } /// ///俄罗斯农民a*b模c的乘法,避免溢出。 /// ///第一被乘数。 ///第二被乘数。 ///模数。 ///a*b模式c 公共静态长RussianPeasant(长a、长b、长c) {
const long _2_32=1L终于找到了问题:RussianPeasant。我没有测试每个边缘情况。我的溢出限制应该是2^31,而不是2^32,以说明符号位。下面是更正的方法:

    public static long RussianPeasant(long a, long b, long c)
    {
        const long overflow_limit = 1L << 31;
        a = Math.Abs (a);
        b = Math.Abs (b);
        if (a < overflow_limit && b < overflow_limit)
            return (a * b % c); // No possibility of overflow.
        if (c < overflow_limit)
            return (a % c) * (b % c) % c;
        long ret = 0;
        while(b != 0) {
            if((b&1L) != 0L) {
                ret += a;
                ret %= c;
            }
            a *= 2;
            a %= c;
            b /= 2;
        }
        return ret;
    }
publicstaticlong-RussianPeasant(长a、长b、长c)
{

const long overflow_limit=1L“我怀疑我正在遭受溢出”——是的,这似乎很可能。“无法找出在哪里”--为什么不呢?你尝试了什么?你有没有在失败的情况下观察你的变量是否溢出?你有没有用检查过的算术编译你的程序,这样当溢出发生时它会抛出异常?堆栈溢出是一个很好的调试帮助的地方;不是一个让别人来调试的好地方为您。尝试了以下方法:为ModulePower编写单元测试(在我的代码示例中未显示)他们都通过了。为iPrime编写了许多单元测试——低数字通过,高数字失败。低数字测试一致成功的事实是我认为溢出是一个问题的线索。我不想让其他人帮我调试。经过两天大约十个小时的调试,阅读了许多SO帖子还有几篇C.S.和数学论文,我向你保证,你在不寻求帮助的情况下尽一切努力解决了我的问题。这就是我发现许多C#运算的定义与数学论文中引用的函数略有不同,例如mod vs%,GCD等。这项研究让我想到了俄罗斯农民和ModPower的想法,还有基础的“最佳”价值。正是这些边缘案例一直在折磨着我,因为我的直觉让我失望。
    public static long RussianPeasant(long a, long b, long c)
    {
        const long overflow_limit = 1L << 31;
        a = Math.Abs (a);
        b = Math.Abs (b);
        if (a < overflow_limit && b < overflow_limit)
            return (a * b % c); // No possibility of overflow.
        if (c < overflow_limit)
            return (a % c) * (b % c) % c;
        long ret = 0;
        while(b != 0) {
            if((b&1L) != 0L) {
                ret += a;
                ret %= c;
            }
            a *= 2;
            a %= c;
            b /= 2;
        }
        return ret;
    }