Java:请为我详细解释这段代码。

时间:2016-03-07 02:11:05

标签: java arrays

此问题与此帖有关:https://stackoverflow.com/a/35810542/5888956

基本上,我必须编写一个从键盘读取整数的程序,它必须能够显示50!仅使用数组。 (不能使用Biginteger或任何东西) 到目前为止,我得到了这个,感谢前一篇文章的帮助。

import java.util.Scanner;
class Factorial
{
    public static void main(String[] args)
    {
        int n;

        Scanner kb = new Scanner(System.in);
        System.out.println("Enter n");
        n = kb.nextInt();
        int [] result = fact(n);

        int i = result.length-1;
        while (i > 0 && result[i] == 0)
        {
            i--; 
        }

        System.out.print(n + "! = ");
        while (i >= 0)
        {
            System.out.print(result[i--]);
        }

        System.out.println();
    }

    public static int[] fact(int n)
    {

        int[] a = new int[100];
        a[0] = 1;



        for (int i = 1; i <= n; i++)
        {
            int carry = 0;
            for(int j = 0; j < a.length; j++)
            {
                int x = a[j] * i + carry;
                a[j] = x % 10;
                carry = x / 10;             
            }

        }

        return a;
    }
}

但我仍然无法理解这里背后的逻辑。 特别是这部分,

for (int i = 1; i <= n; i++)
{
      int carry = 0;
      for(int j = 0; j < a.length; j++)
      {
           int x = a[j] * i + carry;
           a[j] = x % 10;
           carry = x / 10;             
      }
}

我试图用笔和纸来解决这个问题,这样我才能完全理解它。 (当然还有像4这样的小号!) 所以如果我输入4代表n,4!是24(4 * 3 * 2 * 1)。 在我的逻辑中,当i 1 a[0]1因为我在上面初始化时,但在for循环结束一次后,它是否变为0

i = 1, j = 0
x = a[0] * 1 + 0 = 1
a[0] = 0
carry = 1
// ------repeat the loop
i = 2, j = 0
x = a[0] * 1 + 1 = 1
a[0] = 0
carry = 1

因此,我认为这显然不是正确的逻辑。 请有人请帮我理解这个吗?

1 个答案:

答案 0 :(得分:1)

阶乘操作只是意味着将一大堆数字相乘,所以从概念上讲,实现起来并不困难。它在代码中实现时很快成为问题的原因是它产生了大量数字,实际上太大而无法保存在一个int(4个字节)或甚至long(8个字节)中变量(12!是您在int中可以容纳的最大值。否则,我们会做类似的事情:

int fact = 1;
for(int i = 2 ; i <= n ; i++) {
    fact *= i;
}

因此,处理此问题的一种方法是将数字视为&#34;数字&#34;,在基数10中。例如,数字2016可以被视为此数组:{ {1}},这只是说int[] digits = {2, 0, 1, 6}的另一种方式。

现在让我们假设我们有8位计算机,而且我们无法表示大于2016 = 2*1000 + 0*100 + 1*10 + 6*1(或255)的数字。我们不能直接做pow(2,8)-1,但是,因为乘法是分配的2016*2,我们可以分解&#34;大&#34;的乘法。将a(b+c) = ab+ac编号为较小的乘法,如下所示:
2016
2016 → {2, 0, 1, 6} → 2*1000 + 0*100 + 1*10 + 6

现在我们可以像手工一​​样进行这些小的乘法:
2016 * 2 = (2*1000 + 0 + 1*10 + 6) * 2 = (2*2)*1000 + (2*0) + (2*1)*10 + (2*6)

我们得到2016 * 2 → {2, 0, 1, 6} * 2 → {2*2, 0*2, 1*2, 6*2} → {4, 0, 2, 12}的第一个数字,所以我们需要结转12
1

这正是您的代码所做的:

{4, 0, 2, 12} → {4, 0, 2+1, 2} → {4, 0, 3, 2} = 4032

它需要您的号码或&#34;数字数组&#34; a[0] = 1; for (int i = 1; i <= n; i++) { int carry = 0; for(int j = 0; j < a.length; j++) { int x = a[j] * i + carry; a[j] = x % 10; carry = x / 10; } } ,并将数字a分别乘以a[j]i。如果它大于9,请将额外费用带到下一个数字→x = a[j] * i,然后将剩余的数字作为数字→carry = x / 10的值。