在 C 中查找数字的无平方除数

Finding squarefree divisors of a number in C

要求列出所有不同于给定数字 1 的除数,这些除数本身不能被完全平方数整除。

到目前为止,这是我的代码:

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

int main() {
    int n, i, temp;
    scanf("%d", &n);

    for (i = 1; i <= n; ++i) {
        if (n % i == 0) {
            temp = sqrt(i);
            if (temp * temp != i)
                printf("%d ", i);
        }
    }
    return 0;
}

如果我输入 20,那么我得到 1 2 4 5 10 20。我已经消除了所有完全平方的数字,即:4.

现在,我 1 2 5 10 20。在这里我不必考虑 1 这意味着我将有 2 5 10 20.

现在,最后,我必须消除所有可以被完全平方数整除的数字,我该怎么做?

示例:20 将被淘汰,因为 4 x 5 = 20 而 4 是一个完美的正方形。

预期输出:2 5 10

你有一个明显的问题和另一个可能的问题。

显而易见的是

    temp = sqrt(i);
    if(temp*temp != i)

你(尝试)测试 i 是否是 一个完全正方形,而不是它是否可以被一个完全正方形整除。这就是为什么你的代码没有消除 20 的原因,它确实可以被 4 整除,但它本身并不是一个完美的正方形。

如果 sqrt returns 是一个双精度值,并且已知浮点数是 broken(或者更准确地说并不总是准确的...),则可能是这样。所以我不会对您的测试有时 returns 错误结果感到惊讶。

可以做什么:首先 round sqrt 的结果而不是(可能)截断它:temp = sqrt(i) + .5; 并测试 i 是否可以被一个完美的平方整除:

if (n%i == 0)
{
    int ok = 1;
    for (temp=2; temp < sqrt(i) + .5; temp++) {
        if (i % (temp * temp) == 0) {
            ok = 0;
            break;
        }
    }
    if (ok) printf("%d ",i);
}

当您找到 n 的除数 i 时,您应该从 n 中删除 i 的更高次幂,以防止 i 的次幂稍后在扫描中被发现:

#include <stdio.h>

int main() {
    int n, i;

    if (scanf("%i", &n) == 1) {
        for (i = 2; i <= n; ++i) {
            if (n % i == 0) {
                printf("%d ", i);
                while (n % (i * i) == 0)
                    n /= i;
            }
        }
        printf("\n");
    }
    return 0;
}

这个算法对于大素数还是很慢的。一种更快的方法是首先在 O(sqrt(N)) 中找到素因子并打印素因子的所有组合,但列表不一定按递增顺序生成。

考虑到这一点:

  • 一个 32 位数最多有 9 个不同的质因数:

    29!! = 2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23 * 29 = 6469693230

  • 2n - 1 种可能的 n 种组合。
  • 所有可能的素因子和无平方除数都可以收集在相当小的数组中,后者可以排序和打印。

这是一个更快的 32 位版本int

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

int sort_int(const void *p1, const void *p2) {
    int i1 = *(const int *)p1;
    int i2 = *(const int *)p2;
    return (i1 > i2) - (i1 < i2);
}

int main() {
    int primes[9], divs[1 << 9];
    int i, j, n, p, np, nd;

    if (scanf("%i", &n) == 1) {
        np = 0;
        for (p = 2; p <= n / p; p++) {
            if (n % p == 0) {
                primes[np++] = p;
                while (n % p == 0)
                    n /= p;
            }
        }
        if (n > 1) {
            primes[np++] = n;
        }
        nd = 1 << np;
        for (i = 1; i < nd; i++) {
            divs[i] = 1;
            for (j = 0; j < np; j++) {
                if (i & (1 << j))
                    divs[i] *= primes[j];
            }
        }
        qsort(divs, nd, sizeof(*divs), sort_int);
        for (i = 1; i < nd; i++) {
            printf("%d ", divs[i]);
        }
        printf("\n");
    }
    return 0;
}

64 位 int 可以支持最大数量的质因数 15 而不是 9,自动存储仍然可以接受。