简体   繁体   English

数字 2^1000 的数字之和是多少?

[英]What is the sum of the digits of the number 2^1000?

This is a problem from Project Euler , and this question includes some source code, so consider this your spoiler alert, in case you are interested in solving it yourself.这是来自Project Euler 的一个问题,这个问题包括一些源代码,所以如果你有兴趣自己解决它,请考虑这是你的剧透警报。 It is discouraged to distribute solutions to the problems, and that isn't what I want.不鼓励分发问题的解决方案,这不是我想要的。 I just need a little nudge and guidance in the right direction, in good faith.我只需要一点点的推动和正确方向的指导,真诚地。

The problem reads as follows:问题如下:

2^15 = 32768 and the sum of its digits is 3 + 2 + 7 + 6 + 8 = 26. 2^15 = 32768,其数字之和为 3 + 2 + 7 + 6 + 8 = 26。

What is the sum of the digits of the number 2^1000?数字 2^1000 的数字之和是多少?

I understand the premise and math of the problem, but I've only started practicing C# a week ago, so my programming is shaky at best.我了解问题的前提和数学,但我一周前才开始练习 C#,所以我的编程充其量是不稳定的。

I know that int, long and double are hopelessly inadequate for holding the 300+ (base 10) digits of 2^1000 precisely, so some strategy is needed.我知道 int、long 和 double 完全不足以精确保存 2^1000 的 300+(基数 10)数字,因此需要一些策略。 My strategy was to set a calculation which gets the digits one by one, and hope that the compiler could figure out how to calculate each digit without some error like overflow:我的策略是设置一个一个一个地得到数字的计算,并希望编译器能够弄清楚如何计算每个数字而不会出现溢出等错误:

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();
        }
    }
}

It seems to work perfectly for powerOfTwo < 34. My calculator ran out of significant digits above that, so I couldn't test higher powers.它似乎适用于 powerOfTwo < 34。我的计算器用完了高于此值的有效数字,因此我无法测试更高的幂。 But tracing the program, it looks like no overflow is occurring: the number of digits calculated gradually increases as powerOfTwo = 1000 increases, and the sum of digits also (on average) increases with increasing powerOfTwo.但是跟踪程序,看起来没有发生溢出:计算的位数随着 powerOfTwo = 1000 的增加而逐渐增加,并且位数的总和(平均而言)也随着 powerOfTwo 的增加而增加。

For the actual calculation I am supposed to perform, I get the output:对于我应该执行的实际计算,我得到输出:

Power of two: 1000 Sum of digits: 1189二的幂:1000 数字和:1189

But 1189 isn't the right answer.但是 1189 不是正确的答案。 What is wrong with my program?我的程序有什么问题? I am open to any and all constructive criticisms.我对任何和所有建设性的批评持开放态度。

For calculating the values of such big numbers you not only need to be a good programmer but also a good mathematician.要计算如此大的数字的值,您不仅需要成为一名优秀的程序员,而且还需要成为一名优秀的数学家。 Here is a hint for you, there's familiar formula a x = e x ln a , or if you prefer, a x = 10 x log a .这是给您的提示,有一个熟悉的公式 a x = e x ln a ,或者如果您愿意,可以使用 a x = 10 x log a

More specific to your problem 2 1000 Find the common (base 10) log of 2, and multiply it by 1000;更具体到您的问题 2 1000找到 2 的公共(以 10 为底)对数,然后乘以 1000; this is the power of 10. If you get something like 10 53.142 (53.142 = log 2 value * 1000) - which you most likely will - then that is 10 53 x 10 0.142 ;这是 10 的幂。如果你得到类似 10 53.142 (53.142 = log 2 value * 1000) 的结果——你很可能会得到——那么就是 10 53 x 10 0.142 just evaluate 10 0.142 and you will get a number between 1 and 10;只需评估 10 0.142 ,您就会得到一个介于 1 和 10 之间的数字; and multiply that by 10 53 , But this 10 53 will not be useful as 53 zero sum will be zero only.并将其乘以 10 53 ,但是这个 10 53将没有用,因为 53 零和只会为零。

For log calculation in C#用于 C# 中的日志计算

Math.Log(num, base);

For more accuracy you can use, Log and Pow function of Big Integer.为了更准确,您可以使用 Big Integer 的 Log 和 Pow 函数。

Now rest programming help I believe you can have from your side.现在休息编程的帮助我相信你可以从你身边得到。

Normal int can't help you with such a large number.这么大的数字,普通的int帮不了你。 Not even long .甚至不long They are never designed to handle numbers such huge.它们从来没有被设计用来处理如此庞大的数字。 int can store around 10 digits (exact max: 2,147,483,647 ) and long for around 19 digits (exact max: 9,223,372,036,854,775,807 ). int可以存储大约10个数字(确切的最大值: 2,147,483,647 ),并long为各地的19位(具体最高: 9,223,372,036,854,775,807 )。 However, A quick calculation from built-in Windows calculator tells me 2^1000 is a number of more than 300 digits.但是,内置 Windows 计算器的快速计算告诉我2^1000是一个超过 300 位的数字。

(side note: the exact value can be obtained from int.MAX_VALUE and long.MAX_VALUE respectively) (旁注:确切值可以分别从int.MAX_VALUElong.MAX_VALUE获得)

As you want precise sum of digits, even float or double types won't work because they only store significant digits for few to some tens of digits.由于您想要精确的数字总和,即使是floatdouble类型也不起作用,因为它们只存储少数到几十位的有效数字。 ( 7 digit for float, 15-16 digits for double). (浮点数为7位数,双精度数为15-16位数)。 Read here for more information about floating point representation, double precision阅读此处了解有关浮点表示、双精度的更多信息

However, C# provides a built-in arithmetic BigInteger for arbitrary precision, which should suit your (testing) needs.但是,C# 为任意精度提供了内置算术BigInteger ,它应该适合您的(测试)需要。 ie can do arithmetic in any number of digits (Theoretically of course. In practice it is limited by memory of your physical machine really, and takes time too depending on your CPU power)即可以进行任意位数的算术运算(理论上当然可以。实际上它确实受物理机内存的限制,并且也需要时间,具体取决于您的 CPU 能力)


Back to your code, I think the problem is here回到你的代码,我认为问题出在这里

Math.Pow(2, powerOfTwo)

This overflows the calculation.这会使计算溢出。 Well, not really, but it is the double precision is not precisely representing the actual value of the result, as I said.嗯,不是真的,但正如我所说, double精度不能精确表示结果的实际值。

A solution without using the BigInteger class is to store each digit in it's own int and then do the multiplication manually.不使用 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();
}

I used bitwise shifting to left.我使用按位向左移位。 Then converting to array and summing its elements.然后转换为数组并对其元素求和。 My end result is 1366, Do not forget to add reference to System.Numerics;我的最终结果是 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);

since the question is c# specific using a bigInt might do the job.因为问题是特定于 c# 的,使用 bigInt 可能会完成这项工作。 in java and python too it works but in languages like c and c++ where the facility is not available you have to take a array and do multiplication.在 java 和 python 中它也可以工作,但是在像 c 和 c++ 这样的语言中,该功能不可用,您必须采用数组并进行乘法。 take a big digit in array and multiply it with 2. that would be simple and will help in improving your logical skill.在数组中取一个大数字并将其乘以 2。这很简单,有助于提高您的逻辑技能。 and coming to project Euler.并来到欧拉项目。 there is a problem in which you have to find 100!有一个问题,你必须找到 100! you might want to apply the same logic for that too.您可能也想为此应用相同的逻辑。

尝试使用 BigInteger type , 2^100 最终会成为一个非常大的数字,即使是 double 也可以处理。

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

Here's my solution in JavaScript这是我在JavaScript 中的解决方案

 (function (exponent) { const num = BigInt(Math.pow(2, exponent)) let arr = num.toString().split('') arr.slice(arr.length - 1) const result = arr.reduce((r,c)=> parseInt(r)+parseInt(c)) console.log(result) })(1000)

This is not a serious answer—just an observation.这不是一个严肃的答案——只是一个观察。

Although it is a good challenge to try to beat Project Euler using only one programming language, I believe the site aims to further the horizons of all programmers who attempt it.尽管尝试仅使用一种编程语言击败 Project Euler 是一个很好的挑战,但我相信该站点旨在进一步扩大所有尝试它的程序员的视野。 In other words, consider using a different programming language.换句话说,请考虑使用不同的编程语言。

A Common Lisp solution to the problem could be as simple as这个问题的 Common Lisp解决方案可能很简单

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

(print (sum_digits (expt 2 1000)))
 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);
              } 

Python makes it very simple to compute this with an oneliner: Python 使得使用 oneliner 计算它变得非常简单:

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

or alternatively with map:或者使用地图:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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