c语言寻找素数的一个生成元(本原元、本原根)

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

long long s, t;

long long llabs(long long x)
{
    return x < 0 ? -x : x;
}

long long multiply(long long a, long long b, long long mod)
{
    if (llabs(a) > mod / 2)
    {
        a = a < 0 ? a + mod : a - mod;
    }
    long long x = llabs(a), y = llabs(b);
    int a_0 = x % 2;
    long long result = a_0 * y % mod;
    x = x / 2;
    while (x > 0)
    {
        y = (y % mod * 2) % mod;
        if (x % 2 == 1)
        {
            result = (result + y) % mod;
        }
        x = x / 2;
    }
    if (a < 0)
    {
        result = -result;
    }
    if (b < 0)
    {
        result = -result;
    }

    if (llabs(result) > mod / 2)
    {
        result = result < 0 ? result + mod : result - mod;
    }
    return result;
}

long long power(int *flag, long long b, long long n, long long mod) // 这里n>=1,是奇数
{
    long long A = 1;
    int i;
    while (n > 1)
    {
        if (n % 2 == 1)
        {
            A = multiply(A, b, mod);
        }
        if (A == -1 || A == 1)
        {
            *flag = 0;
            return 0;
        }
        b = multiply(b, b, mod);
        if (b == -1 || b == 1)
        {
            *flag = 0;
            return 0;
        }
        n = n / 2;
    }
    A = multiply(A, b, mod);
    if (A == 1)
    {
        *flag = 0;
        return 0;
    }
    return A;
}

long long gcd(long long a, long long b)
{
    if (b == 0)
        return a;
    return gcd(b, a % b);
}

long long pollard_rho(long long n)
{
    if (n % 2 == 0)
        return 2;
    long long x = rand() % (n - 3) + 2;
    long long y = x;
    long long c = rand() % (n - 1) + 1;
    long long d = 1;
    while (d == 1)
    {
        x = (x * x + c) % n;
        y = (y * y + c) % n;
        y = (y * y + c) % n;
        d = gcd(abs(x - y), n);
    }
    return d;
}

int factorize(long long t, long long A2, long long p)
{
    int flag = 1;
    long long A3, A4, m, n, r1, r2;
    if (t > 7)
    {
        long long factor = pollard_rho(t);
        if (factor != t)
        {
            m = t / factor;
            n = factor;
            if (m < n) // 保证m>=n
            {
                long long temp = m;
                m = n;
                n = temp;
            }
            A3 = power(&flag, A2, n, p);
            if (A3 == -1)
            {
                return 0;
            }
            if (m == n)
            {
                A4 = A3;
            }
            else
            {
                r1 = m / n;
                r2 = m % n;
                A4 = power(&flag, A3, r1, p);
                if (r1 % 2 == 0)
                {
                    A4 = multiply(A4, power(&flag, A2, r2, p), p);
                }
                else if (r2 % 2 == 0 && r2 > 0)
                {
                    A4 = multiply(multiply(A4, power(&flag, A2, r2 - 1, p), p), A2, p);
                }
            }
            if (A4 == -1)
            {
                return 0;
            }
            factorize(gcd(m, n), A2, p);
        }
    }
    return 1;
}

long long findGenerator(long long p) // p是素数
{
    if (p == 2)
    {
        return 1;
    }
    if (p == 3 || p == 5 || p == 11)
    {
        return 2;
    }
    if (p == 7)
    {
        return 3;
    }
    s = 0;
    t = p - 1;
    while (t % 2 == 0)
    {
        t = t / 2;
        s++;
    } // 易知s>=1,t>=1
    long long bound;
    // s>1且t>1时phi(2^s*t)/2>=(2^(s-1)-2^(s-2))*(t-1)/2;
    // s=1时,t一定大于等于3,phi(2^s*t)/2>=(t-1)/2
    // t=1时,s一定大于2,phi(2^s*t)/2>=2^(s-1)-2^(s-2),
    long long r1 = (p - 1) / (4 * t), r2 = (t - 1) / 2;
    if (s > 1 && t > 1)
    {
        bound = r1 * r2;
    }
    else if (s == 1)
    {
        bound = r2;
    }
    else if (t == 1)
    {
        bound = r1;
    }
    bound = (p - 1) / 2 + 1 - bound; // 可以证明bound>=6
    long long A, i, f, g;
    int flag;
    long long sqrtbound = floor(sqrt(bound)); // 下取整
    long long begin, end = 0;
    long long Max;
    long long sqrtT = floor(sqrt(t));
    if (sqrtbound * sqrtbound == bound)
    {
        Max = sqrtbound;
    }
    else
    {
        Max = sqrtbound + 1;
    }
    for (f = 2; f <= Max; f++)
    {
        begin = end + 2;
        if (f == sqrtbound + 1)
        {
            end = bound;
        }
        else
        {
            end = begin + 2 * f - 3;
        }
        for (g = begin; g <= end; g++)
        {
            // printf("g=%lld\n", g);
            if (g == 2 && llabs(4 - (p % 8)) == 3)
            {
                continue;
            }
            if (g == 3 && llabs(6 - (p % 12)) == 5)
            {
                continue;
            }
            flag = 1;
            A = power(&flag, g, t, p);
            if (flag == 0)
            {

                continue;
            }
            for (i = 0; i < s; i++)
            {
                if (A == -1)
                {
                    if (i == s - 1)
                    {
                        if (t > 1)
                        {
                            long long A2 = g, A3, A4, j, k;
                            for (j = 0; j < s - 1; j++)
                            {
                                A2 = multiply(A2, A2, p);
                            }
                            if (A2 == -1)
                            {
                                goto sign;
                            }
                            if (!factorize(t, A2, p)) // 最占用运行时间的函数
                            {
                                goto sign;
                            }
                        }
                        return g;
                    }
                    else
                    {
                    sign:
                        break;
                    }
                }
                if (i < s - 1)
                {
                    A = multiply(A, A, p);
                }
            }
        }
    }
    return -1;
}

int main()
{
    long long p = 66666666666666601; // p不能超过2^64严格的说是10进制不要超过9223372036854775807,否则会溢出
    double dur;
    clock_t start, end;
    start = clock(); // 统计运行时间
    long long g = findGenerator(p);
    end = clock();
    dur = (double)(end - start) / CLOCKS_PER_SEC * 1000;
    printf("Use Time:%f ms\n", dur);
    printf("The generator of %lld(2^%lld*%lld+1) is %lld\n", p, s, t, g);
}

时间复杂度O(p(logp)^2),空间复杂度O(1),如有疑问,请私信我!

  • 11
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦想花终开

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值