Какова сумма цифр числа 2 ^ 1000?

Это problem из Project Euler, и этот вопрос включает в себя некоторый исходный код, поэтому рассмотрите это предупреждение вашего спойлера, если вы заинтересованы в его решении самостоятельно. Не рекомендуется распространять решения проблем, и это не то, что я хочу. Я просто нуждаюсь в небольшом подтасовке и руководстве в правильном направлении, добросовестно.

Проблема гласит:

2 ^ 15 = 32768, а сумма его цифр равна 3 + 2 + 7 + 6 + 8 = 26.

Какова сумма цифр числа 2 ^ 1000?

Я понимаю предпосылку и математику проблемы, но я только начал практиковать С# неделю назад, поэтому мое программирование в лучшем случае шатко.

Я знаю, что int, long и double безнадежно неадекватны для того, чтобы точно удерживать 300 + (базовые 10) цифры 2 ^ 1000, поэтому необходима какая-то стратегия. Моя стратегия заключалась в том, чтобы установить вычисление, которое получает цифры один за другим, и надеемся, что компилятор сможет выяснить, как вычислить каждую цифру без некоторой ошибки, например, переполнения:

using System;
using System.IO;
using System.Windows.Forms;

namespace euler016
{
    class DigitSum
    {
        // sum all the (base 10) digits of 2^powerOfTwo
        [STAThread]
        static void Main(string[] args)
        {
            int powerOfTwo = 1000;
            int sum = 0;

            // iterate through each (base 10) digit of 2^powerOfTwo, from right to left
            for (int digit = 0; Math.Pow(10, digit) < Math.Pow(2, powerOfTwo); digit++)
            {
                // add next rightmost digit to sum
                sum += (int)((Math.Pow(2, powerOfTwo) / Math.Pow(10, digit) % 10));
            }
            // write output to console, and save solution to clipboard
            Console.Write("Power of two: {0} Sum of digits: {1}\n", powerOfTwo, sum);
            Clipboard.SetText(sum.ToString());
            Console.WriteLine("Answer copied to clipboard. Press any key to exit.");
            Console.ReadKey();
        }
    }
}

Кажется, что отлично работает для powerOfTwo < 34. В моем калькуляторе не было значительных цифр выше, поэтому я не мог проверить более высокие полномочия. Но, отслеживая программу, похоже, что переполнения не происходит: количество вычисляемых цифр постепенно увеличивается с увеличением мощностиOFTwo = 1000, а сумма цифр также (в среднем) увеличивается с увеличением мощностиOfTwo.

Для фактического расчета, который я должен выполнить, я получаю вывод:

Мощность двух: 1000 Сумма цифр: 1189

Но 1189 - неправильный ответ. Что не так с моей программой? Я открыт для любой конструктивной критики.

Ответ 1

Обычный int не может помочь вам с таким большим количеством. Даже long. Они никогда не предназначены для обработки таких огромных чисел. int может хранить около 10 цифр (точный максимум: 2,147,483,647) и long примерно для 19 цифр (точный максимум: 9,223,372,036,854,775,807). Тем не менее, быстрый расчет из встроенного калькулятора Windows говорит мне, что 2^1000 - это число более 300 цифр.

(боковое примечание: точное значение может быть получено из int.MAX_VALUE и long.MAX_VALUE соответственно)

Как вы хотите точную сумму цифр, даже float или double типы won ' т, потому что они хранят только значимые цифры за несколько десятков цифр. (7 digit для float, 15-16 цифры для double). Читайте здесь для получения дополнительной информации о представлении с плавающей запятой, двойной точности

Однако С# обеспечивает встроенную арифметику BigInteger для произвольной точности, которая должна соответствовать вашим потребностям (тестированию). т.е. может выполнять арифметику в любом количестве цифр (теоретически, конечно, на практике она ограничена памятью вашей физической машины и требует слишком много времени в зависимости от мощности вашего процессора)


Возвращаясь к вашему коду, я думаю, что проблема здесь

Math.Pow(2, powerOfTwo)

Это переполняет расчет. Ну, не совсем, но точность double не точно отражает фактическое значение результата, как я уже сказал.

Ответ 2

Для вычисления значений таких больших чисел вам не только нужно быть хорошим программистом, но и хорошим математиком. Вот вам подсказка, есть знакомая формула a x= e x ln a или, если вы предпочитаете, x= 10 x log a.

Более конкретно для вашей проблемы 2 1000 Найдите общий (базовый 10) лог 2 и умножьте его на 1000; это сила 10. Если вы получите что-то вроде 10 53.142 (53.142 = log 2 значение * 1000), что, скорее всего, будет - тогда это 10 53 x 10 0,142; просто оцените 10 0,142 и вы получите число от 1 до 10; и умножим это на 10 53. Но этот 10 53 не будет полезен, поскольку 53 нулевая сумма будет равна нулю.

Для вычисления журнала в С#

Math.Log(num, base);

Для большей точности вы можете использовать функцию Log и Pow Big Integer.

Теперь помощь в программировании для отдыха, я считаю, что у вас есть с вашей стороны.

Ответ 3

Решение, не использующее класс BigInteger, состоит в том, чтобы хранить каждую цифру в своем собственном int, а затем выполнять умножение вручную.

static void Problem16()
{
    int[] digits = new int[350];

    //we're doing multiplication so start with a value of 1
    digits[0] = 1;
    //2^1000 so we'll be multiplying 1000 times
    for (int i = 0; i < 1000; i++)
    {
        //run down the entire array multiplying each digit by 2
        for (int j = digits.Length - 2; j >= 0; j--)
        {
            //multiply
            digits[j] *= 2;
            //carry
            digits[j + 1] += digits[j] / 10;
            //reduce
            digits[j] %= 10;
        }
    }

    //now just collect the result
    long result = 0;
    for (int i = 0; i < digits.Length; i++)
    {
        result += digits[i];
    }

    Console.WriteLine(result);
    Console.ReadKey();
}

Ответ 4

Я использовал побитовое смещение влево. Затем преобразование в массив и суммирование его элементов. Мой конечный результат - 1366, Не забудьте добавить ссылку на System.Numerics;

BigInteger i = 1;
         i = i << 1000;
        char[] myBigInt = i.ToString().ToCharArray();
        long sum = long.Parse(myBigInt[0].ToString());
        for (int a = 0; a < myBigInt.Length - 1; a++)
        {
            sum += long.Parse(myBigInt[a + 1].ToString());
        }
        Console.WriteLine(sum);

Ответ 5

так как вопрос С#, специфический с использованием bigInt, может выполнять задание. в java и python тоже работает, но в таких языках, как c и С++, где средство недоступно, вам нужно взять массив и сделать размножение. возьмите большую цифру в массиве и умножьте ее на 2. Это будет просто и поможет в улучшении вашего логического навыка. и приход к проекту Эйлера. есть проблема, в которой вам нужно найти 100! вы можете захотеть применить к нему ту же логику.

Ответ 6

Попробуйте использовать BigInteger type, 2 ^ 100 закончится до очень большого числа, даже для двукратного обращения.

Ответ 7

BigInteger bi= new BigInteger("2"); 
bi=bi.pow(1000); 
// System.out.println("Val:"+bi.toString()); 
String stringArr[]=bi.toString().split(""); 
int sum=0; 
for (String string : stringArr) 
{ if(!string.isEmpty()) sum+=Integer.parseInt(string); } 
System.out.println("Sum:"+sum);
------------------------------------------------------------------------
output :=> Sum:1366

Ответ 8

Это не серьезный ответ - просто наблюдение.

Несмотря на то, что это хороший вызов, чтобы попытаться победить Project Euler, используя только один язык программирования, я считаю, что сайт нацелен на то, чтобы продвигать горизонты всех программистов, которые его пытаются. Другими словами, рассмотрите использование другого языка программирования.

Общее Lisp решение может быть прост как

(defun sum_digits (x)
    (if (= x 0)
        0
        (+ (mod x 10) (sum_digits (truncate (/ x 10))))))

(print (sum_digits (expt 2 1000)))

Ответ 9

 main()
 {
   char c[60];
  int k=0;
     while(k<=59)
      {
    c[k]='0';
   k++;

    }
       c[59]='2';
       int n=1;
     while(n<=999)
       {
       k=0;
     while(k<=59)
      {
        c[k]=(c[k]*2)-48;
        k++;
      } 
    k=0;
     while(k<=59)
        {
        if(c[k]>57){ c[k-1]+=1;c[k]-=10;   }
       k++;
         }
       if(c[0]>57)
        {
         k=0;
         while(k<=59)
           {
         c[k]=c[k]/2;
          k++;
           }
           printf("%s",c);
             exit(0);
           }

            n++;
            }
          printf("%s",c);
              } 

Ответ 10

Python очень просто вычислить это с помощью oneliner:

print sum(int(digit) for digit in str(2**1000))

или, альтернативно, с картой:

print sum(map(int,str(2**1000)))