【问题标题】:Prime factorization of a factorial阶乘的素数分解
【发布时间】:2014-02-07 10:15:59
【问题描述】:

我需要编写一个程序来输入一个数字并以如下形式输出其阶乘的素数分解:

4!=(2^3)*(3^1)

5!=(2^3)*(3^1)*(5^1)

问题是我仍然不知道如何得到这个结果。

显然,括号中的每个第一个数字都是升序质数,直到实际的阶乘。括号中的第二个数字是该数字在阶乘中出现的次数。

我想不通的是例如在5!=(2^3)*(3^1)*(5^1)中,2如何只出现3次,3只出现1次,5只出现120次(5!=120)。

感谢提供评论的乐于助人的人,我现在已经解决了这个问题,但我现在无法弄清楚如何在不实际计算阶乘的情况下获取一个数字并以这种格式获得阶乘。

【问题讨论】:

  • 您知道2*2*2 * 3 * 5 等于120,对吧?你对此有什么困惑?
  • 我只是混淆了这些数字的来源。我现在想通了。
  • 看看我的答案。它解释了如何在不实际计算阶乘的情况下获得阶乘的素数分解。基本上,您将构成阶乘的所有数字分解并添加相似基数的指数。

标签: primes factorial prime-factoring


【解决方案1】:

每个数字都可以由质数的唯一(直到重新排序)乘法表示,称为数字的质因数分解,因为您正在寻找可以唯一创建该数字的质因数。

2^3=8

3^1=3

5^1=5

8*3*5=120

但这也意味着:(2^3)*(3^1)*(5^1) = 120

这并不是说 2 作为数字 120 中的一个数字出现 3 次,显然它没有,而是说 2 乘以 2 乘以 2,总共 3 个二。同样对于 3 和 5,它们在 120 的素数分解中出现一次。您提到的表达式向您展示了数字 120 的这种独特的素数分解。这是在 Python 中获得数字的素数分解的一种方法:

def pf(number):
    factors=[]
    d=2
    while(number>1):
        while(number%d==0):
            factors.append(d)
            number=number/d
        d+=1
    return factors

运行它你会得到:

>>> pf(120)
[2, 2, 2, 3, 5]

如上所述,乘以 120。这里有一个小图可以更清楚地说明这一点:

【讨论】:

  • 感谢我的主要因素。
  • 我明白,虽然我不熟悉python。我的下一个问题是如何在不实际计算阶乘的情况下获取一个数字并以这种格式获得阶乘。
  • @Bradg89 你可以使用阶乘的定义。它是一堆因素(组件)的产物。这些因素(组件)中的每一个都可以分解为主要因素。因此,因子的乘积可以根据分量的已找到的素因子的乘积来重写 - 无需计算阶乘即可得到问题的答案。
【解决方案2】:

考虑例如33!。它是以下产品:

2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33

因素是:

2   2   2   2    2     2     2     2     2     2     2     2     2     2     2     2
    2       2          2           2           2           2           2           2
            2                      2                       2                       2
                                   2                                               2
                                                                                   2
  3     3     3        3        3        3        3        3        3        3        3
              3                          3                          3
                                                                    3
      5          5              5              5              5              5
                                                              5
          7                  7                    7                    7
                   11                               11                               11
                         13                                     13
                                     17
                                           19
                                                       23
                                                                         29    31

你看到模式了吗?

33! = 2^( 33 div 2 + 33 div 4 + 33 div 8 + 33 div 16 + 33 div 32) *
      3^( 33 div 3 + 33 div 9 + 33 div 27) *
      5^( 33 div 5 + 33 div 25) *
      ----
      7^( 33 div 7) * 11^( 33 div 11) * 13^( 33 div 13) *
      ----
      17 * 19 * 23 * 29 * 31

因此,要找到 n! 的素数分解而不做任何乘法或分解,我们只需要得到不大于 n 的素数的有序列表,我们分三个阶段处理(使用重复的整数除法和可能的求和) - 小于或等于 n 平方根的素数;这样小于或等于n/2;和其余的。

实际上,使用惰性求值甚至比这更简单。假设 primes 已经实现,按顺序返回素数流,在 Haskell 中,因式分解发现为

ff n = [(p, sum . takeWhile (> 0) . tail . iterate (`div` p) $ n) 
         | p <- takeWhile (<= n) primes]

-- Prelude> ff 33
-- [(2,31),(3,15),(5,7),(7,4),(11,3),(13,2),(17,1),(19,1),(23,1),(29,1),(31,1)]

因为33 div 4(33 div 2) div 2 等等。

【讨论】:

    【解决方案3】:

    2^3 是 23 或 2 的三次方的另一种写法。 (2^3)(3^1)(5^1) = 23 × 3 × 5 = 120。

    (2^3)(3^1)(5^1) 只是以纯 ASCII 文本而不是漂亮的数学格式表示的 120 的质因数分解。您的作业需要以这种形式输出,因为它比您弄清楚如何输出格式化方程式更容易(并且可能因为它更容易处理以进行评分)。

    此处用于以纯文本形式表达方程式的约定非常标准,您可以直接将此文本输入 google.com 或 wolframalpha.com,它会为您计算结果为 120:(2^3)(3^1)(5^1) on wolframalpha.com / (2^3)(3^1)(5^1) on google.com


    WolframAlpha 还可以计算素数分解,您可以使用它来获取测试结果以与您的程序进行比较。例如:prime factorization of 1000!

    实际计算阶乘的简单解决方案只能处理最多 12 的数字(如果使用 32 位整数)。这是因为13!约为 62 亿,大于 32 位整数可以表示的最大数字。

    但是,如果您避免先计算阶乘,则可以处理更大的输入。我不会确切地告诉你如何做到这一点,因为要么弄清楚它是你任务的一部分,要么你可以问你的教授/助教。但以下是一些提示。

    ab × ac = ab+c


    方程 (a)      10 = 21 × 51
    方程 (b)      15 = 31 × 51
    10 × 15 = ? 用等式 (a) 和 (b) 的右手边来回答,而不是用数字 150。


    10 × 15 = (21 × 51) × (31 × 51) = 21 × 31 × (51 × 51) = 21 sup> × 31 × 52

    如您所见,无需将 10 乘以 15 即可计算 10 × 15 的素数分解;您可以改为计算各个项的素数分解,然后组合这些分解。

    【讨论】:

    • 谢谢你的假设是正确的。在看之前我会自己尝试。如果我依靠别人做困难的事情,我就找不到工作。
    【解决方案4】:

    如果你写出阶乘 5!:
    1 * 2 * 3 * 4 * 5,
    您会注意到有一个非质数:4。4 可以写成 2 * 2 或 2^2,这就是额外的 2 的来源。 将所有出现的次数相加(指数形式在括号中;为类似的基数添加指数):
    2 (2^1) * 3 (3^1) * 4 (2^2) * 5 (5^1),你会得到正确答案。

    【讨论】:

    • 读者请注意,这里的“2 (2^1) * 3 (3^1) * 4 (2^2) * 5 (5^1)”并不意味着“2 × 2¹ × 3 × 3¹ × 4 × 2² × 5 × 5¹",(计算结果为 120² 而不是 120)。在这种情况下,带括号的文本只是扩展了阶乘的相应项,而不是充当项本身。
    【解决方案5】:

    您可以使用O(n/2 log log n) 算法,只使用总和(不需要预先计算素数)。

    这是一个使用关系的筛子

    f = a * b  ~>  f^k = a^k * b^k
    

    然后,我们减少所有初始因子 1 * 2 * 3 * ... * nk 从大数字移动到小数字。

    使用阿特金筛法,Will Ness 算法对于 very big n 可能会更好,如果不是,我认为它可能会更好

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char **argv) {
      int n = atoi(argv[1]);
      int *p = (int *) malloc(sizeof(int) * (n + 1));
      int i, j, d;
      for(i = 0; i <= n; i++)
        p[i] = 1;
      for(i = n >> 1; i > 1; i--)
        if(p[i]) {
          for(j = i + i, d = 2; j <= n; j += i, d++) {
            if(p[j]) {
              p[i] += p[j];
              p[d] += p[j];
              p[j] = 0;
            }
          }
        }
      printf("1");
      for(i = 2; i <= n; i++)
        if(p[i])
          printf(" * %i^%i", i, p[i]);
      printf("\n");
      return 0;
    }
    

    【讨论】:

    • 据报道,阿特金筛很难有效实施。
    • 好点@WillNess,因此我认为你的方法更适合非常(非常)大的数字:) 另一方面,我想知道 Atkin 是否可以用作我的筛子以获得更好的算法。好问题!
    • 我认为对于非常大的数字N,输出将包含太多条目 - 其中about N / (log N - 1)(与N 下面的素数一样多)。对于 10^9,它是 50,701,542 个条目 (actually, 50,847,534)。我猜我们真的不需要那个。 :) 因此,我认为,无论是预先计算还是作为算法的一部分,SoE 的任何正常 impl 都可以。 :)
    • 你说服了我 :) XD XD
    【解决方案6】:

    您可以使用 Adrien-Marie Legendre 找到的身份。点击链接了解更多

    http://blog.janmr.com/2010/10/prime-factors-of-factorial-numbers.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-26
      相关资源
      最近更新 更多