简体   繁体   中英

Java: Summing all digits of 2^1000

I'm trying to solve Project Euler problem #16, where I need to sum all the digits of 2^1000. I've gotten stuck dealing with such a big number. My program worked for any number below 10^16, but failed afterwards. This told me that my logic was correct. I went ahead and converted all variables and methods to BigDecimal, but now the program does not run properly. It compiles as it is and there is no error; it just does not terminate. Does anyone have an idea on where I went wrong here?

import java.math.BigDecimal;
import java.math.RoundingMode;

public class Powerdigitsum {

    private static final BigDecimal one = new BigDecimal("1");
    private static final BigDecimal ten = new BigDecimal("10");

    private static BigDecimal sumofDigits(BigDecimal n){

        BigDecimal sum = new BigDecimal("0");

        while(n.compareTo(one) == 1 || n.compareTo(one) == 0){

            sum.add(n.remainder(ten));

            n.divide(ten);

            n = n.setScale(0, RoundingMode.FLOOR);

        }

    return sum;

    }

    public static void main(String[] args) {

        final double the_number = Math.pow(2,1000);

        final double test = 15;

        final BigDecimal two_to_the_thousandth_power = new BigDecimal(test);

        System.out.println(sumofDigits(two_to_the_thousandth_power));

    }

}

只需正确使用BigInteger

BigInteger a = new BigInteger("2").pow(1000);

The whole method is kinda wrong. See this:

private static BigInteger sumOfDigits(BigInteger n) {
    BigInteger sum = BigInteger.ZERO;
    while (n.compareTo(BigInteger.ZERO) == 1) {
        sum = sum.add(n.remainder(ten));
        n = n.divide(ten);
    }
    return sum;
}

You needed to compare to zero, not one. And you need to assign the values for BigIntegers and BigDecimals, their methods do nothing on their own, the instances of those classes are immutable.

For integers, it's generally better to use BigInteger . The decimal part (that gets there from dividing) is just thrown away.

final double the_number = Math.pow(2,1000);

This won't work because the_number is not large enought to take the result. You need to convert the pow call to BigInteger :

BigInteger result = new BigInteger("2").pow(1000);

But be aware.. this can take some time..

Don't use the BigDecimal(double) constructor: it is limited by the double primitive type, which cannot represent 2^1000.

You can use a BigInteger . Something along these lines should work (probably suboptimal, but...):

public static void main(final String... args)
{
    // 2^1000
    final BigInteger oneTo2000 = BigInteger.ONE.shiftLeft(1000);

    BigInteger digitSum = BigInteger.ZERO;

    // We don't want to split against the empty string, the first element would be ""
    for (final String digit: oneTo2000.toString().split("(?<=.)"))
        digitSum = digitSum.add(new BigInteger(digit));

    System.out.println(digitSum);
}
import java.math.BigInteger;

public class Problem16 {
public static void main(String[] args) {

   BigInteger number2 = new BigInteger("2");   
   BigInteger number3 = new  BigInteger("0");
   number3 =number2.pow(1000);

   String str = number3.toString();
BigInteger sum = new BigInteger("0");

 for(int i=0; i<str.length(); i++)
  {
    char c= str.charAt(i); 

    int value = Character.getNumericValue(c);
    BigInteger value2 = new BigInteger(Integer.toString(value));
     sum =sum.add(value2) ; 
  }
System.out.println(sum);

}

}

IF YOU THINK BIGINTEGER IS CHEATING AND/OR don't feel like using it/learning how to use it, this algorithm is the way to go.

Think about how you would calculate 2^1000 by hand. You'd start with 2^1 and multiply by two repeatedly. Now notice that the number of digits of powers of two increase by 1 for AT LEAST every 3 powers (could be after 4 powers like with 1024 to 8192). So make a jagged 2D array like this

int a[][]= new int[1000][];
for(int i=0;i<1000;i++)
{
    a[i]= new int[1+(i/3)];
}

Then initialize a[0][0] to 2. After this, you want to write a for loop such that each row is filled from the rightmost spot. So make two variables "digit" and "carry". Digit is the number that you will input into the row you're working on, and the carry is the one you're going to take to the next calculation and add to the product of 2 and whatever digit you're multiplying it with. Be careful with the order you update digit and carry and reinitialize them to zero after every calculation. I think the hardest part is coming up with the limits for the for loop, so that it fits with the every 3 powers thing. You can make this simpler by just making a triangular jagged array that increments by one every row. I did it like this though. Here's my whole code.

import java.util.*;
public class ProjectEuler16 
{
    public static void main(String[] args) 
    {
        long t1=System.currentTimeMillis();
        ProjectEuler16 obj = new ProjectEuler16();
        System.out.println(obj.bigNumHandler());
        long t2= System.currentTimeMillis();
        System.out.println(t2-t1);
    }
    int bigNumHandler()
    {
        int a[][] = new int[1000][];
        for(int i=0;i<1000;i++)
        {
            a[i]= new int[1+(i/3)];
        }
        a[0][0]=2;
        for(int i=1;i<1000;i++)
        {   
            int carry=0;
            int digit=0;
            int f=0;
            if(i%3==0)
            {
                f=1;
            }
            for(int j=a[i-1].length-1+f;j>=0;j--)
            {
                if(j==0&f==1)
                {
                    a[i][0]=carry;
                }
                else
                {
                     digit=((2*a[i-1][j-f])+carry)%10;
                     carry=((2*a[i-1][j-f])+carry)/10;
                     a[i][j]=digit;
                }
            }

        }
        int sum=0;
        for(int k=0;k<a[999].length;k++)
        {
           sum=sum+a[999][k];
        }
        return sum;
   }
}

Note that the last row lists the digits for 2^1000.I think you can figure out how to sum the digits. The program took about 5 seconds to come up with the answer.

solution::::

import java.math.BigInteger;

public class PR9 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        BigInteger zero=BigInteger.valueOf(0);
        BigInteger ten=BigInteger.valueOf(10);
        BigInteger sum=zero;
        BigInteger a = new BigInteger("2").pow(1000);

        while(a.compareTo(zero)>0){
            sum=sum.add(a.mod(ten));
            a=a.divide(ten);
        }
        System.out.println(sum);


       }
    }

output:::::
1366

import java.math.BigInteger;

public class P16 {

    public static BigInteger digitSum(int n) {
        BigInteger sum = BigInteger.ZERO;
        BigInteger number = new BigInteger("2").pow(n);

        while (number.compareTo(BigInteger.ZERO) == 1) {
            BigInteger remainder = number.remainder(BigInteger.TEN);
            sum = sum.add(remainder);
            number = number.divide(BigInteger.TEN);
        }

        return sum;
    }

    public static void main(String[] args) {
        final double START = System.nanoTime();
        System.out.println(digitSum(Integer.parseInt(args[0])));
        final double DURATION = System.nanoTime() - START;
        System.out.println("Duration: " + DURATION / 1000000 + "ms.");
    }
}

While there maybe a way of solving this problem without the use of BigIntegers, it is clear that they make the code run way faster. Mine only took about 4ms to find an answer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM