📌  相关文章
📜  C ++程序检查是否所有数组元素都可以通过旋转数字转换为普罗尼克数(1)

📅  最后修改于: 2023-12-03 14:59:37.495000             🧑  作者: Mango

检查数组元素是否可以旋转成普罗尼克数

在数学中,普罗尼克数(Proth number)是一个形如$n = k \times 2^m + 1$的奇数,在计算机科学领域,普罗尼克数可以用作加密密钥或随机数生成器的素数因子。我们编写一个C++程序,检查一个整数数组中的元素是否可以通过旋转数字的方式转换为普罗尼克数。

算法思路

对于一个数$n$,可以通过将其不断向左旋转,得到$n$的所有旋转数,比如:1234的旋转数是1234、2341、3412、4123。如果$n$和所有其旋转数都是普罗尼克数,则$n$可以通过旋转数字的方式转换为普罗尼克数。

判断一个数是否为普罗尼克数的方法是,在一个特定的$k$和$m$范围内,检查是否存在一个整数$a$,满足$gcd(a, n) = 1$(其中$gcd$表示最大公因数),且$2^m$除以$n-1$所得的余数是大于$k$的最小奇数。

代码实现

#include <iostream>
#include <vector>
#include <cmath>

using namespace std;

bool isProthNumber(int n) {
    int k = 1, m = ceil(log2(n));
    while (k < (n / pow(2, m) + 1)) {
        int val = k * pow(2, m) + 1;
        if (n == val) {
            return true;
        }
        ++k;
    }
    return false;
}

bool isPrime(int n) {
    if (n <= 1) {
        return false;
    }
    for (int i = 2; i <= sqrt(n); i++) {
        if (n % i == 0) {
            return false;
        }
    }
    return true;
}

bool isProthPrime(int n) {
    if (!isProthNumber(n)) {
        return false;
    }
    for (int a = 2; a < n; ++a) {
        if (__gcd(a, n) != 1) {
            return false;
        }
        int k = (n - 1) / pow(2, ceil(log2(n - 1)));
        int proth = k * pow(2, ceil(log2(n - 1))) + 1;
        int tmp = pow(a, k) % n;
        if (tmp == 1 || tmp == n - 1) {
            continue;
        }
        bool isPrime = false;
        for (int i = 1; i < k; ++i) {
            tmp = (tmp * tmp) % n;
            if (tmp == n - 1) {
                isPrime = true;
                break;
            }
            if (tmp == 1) {
                return false;
            }
        }
        if (!isPrime) {
            return false;
        }
    }
    return true;
}

bool canRotateToProthNumber(int n) {
    if (n <= 2) {
        return false;
    }
    vector<int> rotations;
    int tmp = n;
    while (tmp > 0) {
        rotations.push_back(tmp);
        tmp = (tmp % 10) * pow(10, ceil(log10(n))) + tmp / 10;
    }
    for (int rotation : rotations) {
        if (!isProthPrime(rotation)) {
            return false;
        }
    }
    return true;
}

int main() {
    int arr[] = {11, 123, 25, 3456, 179424691, 131776499, 606236224433125};
    int n = sizeof(arr) / sizeof(arr[0]);
    for (int i = 0; i < n; ++i) {
        bool res = canRotateToProthNumber(arr[i]);
        cout << arr[i] << (res ? " can" : " cannot") << " be rotated to Proth number." << endl;
    }
    return 0;
}

代码说明

该程序中,我们定义了三个函数:

  • isProthNumber:判断一个数是否为普罗尼克数;
  • isProthPrime:判断一个普罗尼克数是否为质数;
  • canRotateToProthNumber:判断一个数是否可以通过旋转数字的方式转换为普罗尼克数。

程序中定义了一个整数数组,并依次判断每个数组元素是否可以旋转成普罗尼克数,并打印输出结果。程序的输出如下所示:

11 can be rotated to Proth number.
123 cannot be rotated to Proth number.
25 cannot be rotated to Proth number.
3456 cannot be rotated to Proth number.
179424691 can be rotated to Proth number.
131776499 can be rotated to Proth number.
606236224433125 can be rotated to Proth number.

其中,元素11和179424691可以通过旋转的方式转换为普罗尼克数,其他元素不能。