简体   繁体   中英

Summing up digits of a very long binary number?

I was asked by a friend :

If 2^10 = 1024 , we can take 1024 and break and summarize its digits :

1+0+2+4 = 7.

This is easy.

However When the input is 2^30000 ( the input actually is a long string "1000..." ) --there is no .net type which can hold this value .

So there must be a trick to sum its digits (digits of the decimal value)....

Edited :

Related trick ( for finding 10^20 - 16 )

100 = 10^2 (one and two zeros)

10^20 = (one and 20 zeros)

hence:

10^20 - 16 = 18 nines, an eight and four.

18*9+8+4 = 174

But I haven't succeeded converting this solution to my problem.( I tried quite a lot).

*Im tagging this question as .net because I can use string functions , math functions from .net library.*

Question

Is there any trick here which can allow me to sum many many numbers which is the result of x^n ?

What is the trick here ?

Edited #2 : Added the .net2 tag (where biginteger is unavailable) - I'm wondering how I could do it without biginteger.(i'm looking for the hidden trick)

You can leverage the BigInteger structure to do this. As it's written in MSDN

The BigInteger type is an immutable type that represents an arbitrarily large integer whose value in theory has no upper or lower bounds.

Basically after creating BigInteger instance and evaluating exponent you can translate it to a string. After that you will iterate over each character of that string and convert each char to int number. Add all those int numbers up and you'll get your answer.

BigInteger bi = new BigInteger(2);
var bi2 = BigInteger.Pow(bi, 30000);
BigInteger sum = new BigInteger();
foreach(var ch in bi2.ToString())
    sum = BigInteger.Add(sum, new BigInteger(int.Parse(ch.ToString())));
MessageBox.Show(bi2.ToString() + " - " + sum.ToString());

There is no general trick I'm aware of for finding the base 10 digit sum of a number.

However, there is an easy trick for finding the base 10 digit root of a number.

The digit sum is, as you say, simply the sum of all the digits. The base 10 digit sum of 1024 is 1 + 2 + 4 = 7. The base 10 digit sum of 65536 is 6 + 5 + 5 + 3 + 6 = 25.

The digit root is what you get when you repeat the digit sum until there's only one digit. The digit sum of 65536 is 25, so the digit root is 2 + 5 = 7.

The trick is: If you have Z = X * Y then DigitRoot(Z) = DigitRoot(DigitRoot(X) * DigitRoot(Y)). (Exercise to the reader: prove it! Hint: start by proving the same identity for addition.)

If you have an easily-factored number - and the easiest number to factor is 2 n -- then it is easy to figure out the digit root recursively: 2 16 = 2 8 * 2 8 , so DigitRoot(2 16 ) = DigitRoot(DigitRoot(2 8 ) * DigitRoot(2 8 )) -- We just made the problem much smaller. Now we don't have to calculate 2 16 , we only have to calculate 2 8 . You can of course use this trick with 2 30000 -- break it down to DigitRoot(DigitRoot(2 15000 * DigitRoot(2 15000 )). If 2 15000 is too big, break it down further; keep breaking it down until you have a problem small enough to solve.

Make sense?

I'm not convinced there can be a trick here. The latter trick you show works because both the number, and the result are both decimal numbers.

For example:
1267 = 1*10^3 + 2*10^2 + 6*10^1 + 7*10^0

So you there is a clear correlation between the power and the sum. But unfortunately if you want to convert binary numbers, or powers of 2, into decimal numbers, that's not going to work. Best effort would be reducing the power to increase the base number.

2^3000 = 4^1500 = 16^750 = 256^375

But as you see, the series jump over base 10. Which sadly means you need to calculate the end result as a decimal number before you can convert it into powers of 10. Making the trick not work.

From http://blog.singhanuvrat.com/problems/sum-of-digits-in-ab :

public class Problem_16 {
    public long sumOfDigits(int base, int exp) {
        int numberOfDigits = (int) Math.ceil(exp * Math.log10(base));
        int[] digits = new int[numberOfDigits];
        digits[0] = base;
        int currentExp = 1;

        while (currentExp < exp) {
            currentExp++;
            int carry = 0;
            for (int i = 0; i < digits.length; i++) {
                int num = base * digits[i] + carry;
                digits[i] = num % 10;
                carry = num / 10;
            }
        }

        long sum = 0;
        for (int digit : digits)
            sum += digit;

        return sum;
    }

    public static void main(String[] args) {
        int base = 2;
        int exp = 3000;
        System.out.println(new Problem_16().sumOfDigits(base, exp));
    }
}

c#

public class Problem_16 {
    public long sumOfDigits(int base1, int exp) {
        int numberOfDigits = (int) Math.Ceiling(exp * Math.Log10(base1));
        int[] digits = new int[numberOfDigits];
        digits[0] = base1;
        int currentExp = 1;

        while (currentExp < exp) {
            currentExp++;
            int carry = 0;
            for (int i = 0; i < digits.Length; i++) {
                int num = base1 * digits[i] + carry;
                digits[i] = num % 10;
                carry = num / 10;
            }
        }

        long sum = 0;
        foreach (int digit in  digits)
            sum += digit;

        return sum;
    }
}


void Main()
{
     int base1 = 2;
        int exp = 3000000;
        Console.WriteLine (new Problem_16().sumOfDigits(base1, exp));

}

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