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

这是Project Euler的一个问题 ,这个问题包含一些源代码,所以请考虑这个扰流警报,以防您有兴趣自己解决它。 不鼓励为问题分发解决方案,这不是我想要的。 我真的需要在正确的方向上进行一点点推动和指导。

问题如下:

2 ^ 15 = 32768,其数字之和为3 + 2 + 7 + 6 + 8 = 26。

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

我理解问题的前提和数学,但我一周前才开始练习C#,所以我的编程充其量只是摇摇欲坠。

我知道int,long和double绝对不足以准确地保持2 ^ 1000的300+(基数10)数字,所以需要一些策略。 我的策略是设置一个逐个获取数字的计算,并希望编译器能够计算出如何计算每个数字而不会出现像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(); } } } 

它似乎完全适用于powerOfTwo <34。我的计算器超出了有效数字,所以我无法测试更高的功率。 但是跟踪程序,看起来没有发生溢出:随着powerOfTwo = 1000的增加,计算的位数逐渐增加,并且数字的总和也(平均)随着powerOfTwo的增加而增加。

对于我应该执行的实际计算,我得到输出:

2的幂:1000位数:1189

但1189不是正确的答案。 我的计划有什么问题? 我对所有建设性的批评持开放态度。

普通的int无法帮助你如此大的数字。 甚至不long 。 它们从未被设计用于处理如此巨大的数字。 int可存储大约10位数(最大值为2,147,483,647 ), long大约为19位(最大值为9,223,372,036,854,775,807 )。 但是,内置Windows计算器的快速计算告诉我2^1000是超过300位的数字。

(旁注:确切的值可以分别从int.MAX_VALUElong.MAX_VALUE获得)

由于你想要精确的数字总和,即使floatdouble精度数也不起作用,因为它们只存储几十到几十位的有效数字。 (浮点数为7位,双数位为15-16位)。 有关浮点表示,双精度的更多信息,请阅读此处

但是,C#提供了一个内置的算术BigInteger用于任意精度,这应该适合您的(测试)需求。 即可以任意数量的数字进行算术运算(理论上当然。实际上它实际上受到物理机器内存的限制,并且取决于你的CPU功率也需要时间)


回到你的代码,我认为问题出在这里

Math.Pow(2, powerOfTwo)

这溢出了计算。 嗯,不是真的,但正如我所说, double精度并不能准确地代表结果的实际价值。

为了计算这些大数字的值,你不仅需要成为一名优秀的程序员,还需要一名优秀的数学家。 这里有一个提示,有一个熟悉的公式a x = e x ln a ,或者如果你愿意, x = 10 x log a

更具体到您的问题2 1000找到2的公共(基数10)对数,并将其乘以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零和将仅为零。

用于C#中的日志计算

 Math.Log(num, base); 

为了更准确,您可以使用Big Integer的Log和Powfunction。

现在rest编程帮助我相信你可以从你身边。

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

我使用按位向左移位。 然后转换为数组并对其元素求和。 我的最终结果是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); 

因为问题是c#具体使用bigInt可能会完成这项工作。 在java和python中它也可以工作但是在c和c ++这样的语言中,设备不可用你必须采用数组并进行乘法。 取数组中的大数字并将其乘以2.这很简单,有助于提高你的逻辑技能。 并且来到项目欧拉。 有一个问题,你必须找到100! 您可能也想为此应用相同的逻辑。

尝试使用BigInteger type ,2 ^ 100将结束一个非常大的数字,甚至双倍处理。

 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 

这不是一个严肃的答案 – 只是一个观察。

虽然尝试使用一种编程语言来击败Project Euler是一个很好的挑战,但我相信该网站旨在进一步推动所有尝试它的程序员的视野。 换句话说,考虑使用不同的编程语言。

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使用oneliner计算它非常简单:

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

或者用地图:

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