简体   繁体   English

在 C 中计算 2^n 的数字和

[英]Calculating sum of digits of 2^n in C

I am new to C and trying to write a program that calculates the sum of the digits of 2^n, where n<10^8.我是 C 的新手,正在尝试编写一个程序来计算 2^n 的数字之和,其中n<10^8。

For example, for 2^10, we'd have 1+0+2+4, which is 7.例如,对于 2^10,我们有 1+0+2+4,即 7。

Here's what I came up with:这是我想出的:

#include <stdio.h>
#include <math.h>

int main()
{
   int n, t, sum = 0, remainder;

   printf("Enter an integer\n");
   scanf("%d", &n);

   t = pow(2, n);

   while (t != 0)
   {
      remainder = t % 10;
      sum       = sum + remainder;
      t         = t / 10;
   }

   printf("Sum of digits of 2 to the power of %d = %d\n", n, sum);

   return 0;
}

The problem is: the program works fine with numbers smaller than 30. Once I set n to a number higher than 30, the result is always -47 .问题是:程序在小于 30 的情况下工作正常。一旦我将 n 设置为大于 30 的数字,结果总是-47

I really do not understand this error and what causes it.我真的不明白这个错误以及导致它的原因。

An interesting problem to be sure, but I think the solution is way outside the scope of a simple answer if you wish to support large values of n , such as the 10 8 you mentioned.可以肯定这是一个有趣的问题,但我认为如果您希望支持较大的n值(例如您提到的 10 8 ),则解决方案超出了简单答案的范围。 The number 2 10 8 requires 10 8 + 1 (100,000,001) bits, or around 12 megabytes of memory, to store in binary .数字 2 10 8需要 10 8 + 1 (100,000,001) 位,或大约 12 兆字节的内存,才能以二进制形式存储。 In decimal it has around 30 million digits.在十进制中,它有大约 3000 万位数字。

Your int is 32 bits wide, which is why the signed int can't store 2 31 – the 32nd bit is the sign while 2 31 has a 1 followed by 31 zeros in binary, requiring 32 bits without the sign.您的int是 32 位宽,这就是带符号的int不能存储 2 31的原因——第 32 位是符号,而 2 31有一个 1 后跟 31 个二进制零,需要 32 位没有符号。 So it overflows and is interpreted as a negative number.所以它溢出并被解释为负数。 (Technically signed integer overflow is undefined behaviour in C.) (技术上有符号整数溢出在 C 语言中是未定义的行为。)

You can switch to an unsigned int to get rid of the sign and the undefined behaviour, in which case your new highest supported n will be 31. You almost certainly have 64-bit integers available, and perhaps even 128-bit, but 2 127 is still way less than 2 100000000 .您可以切换到unsigned int以摆脱符号和未定义的行为,在这种情况下,您支持的新的最高n将是 31。您几乎可以肯定有 64 位整数可用,甚至可能有 128 位整数,但 2 127仍然小于 2 100000000

So either you need to find an algorithm to compute the decimal digits of a power of 2 without actually storing them (and only store the sum), or forget about trying to use any scalar types in standard C and get (or implement) an arbitrary precision math library operating on arrays (of bits, decimal digits, or binary-coded decimal digits).因此,您要么需要找到一种算法来计算 2 的幂的十进制数字而不实际存储它们(并且只存储总和),要么忘记尝试在标准 C 中使用任何标量类型并获得(或实现)任意在数组(位、十进制数字或二进制编码的十进制数字)上运行的精密数学库。 Alternatively, you can limit your solution to, say, uint64_t , but then you have n < 64, which is not nearly as interesting… =)或者,您可以将您的解决方案限制为uint64_t ,但是您的n < 64,这几乎没有那么有趣...... =)

TL;TD TL; TD

sum=(int)(log10(2)*n)+1;

or 要么

double log10Of2=log10(2);

at the beginning and 在开始和

sum=(int)(log10Of2*n);

when you want to calculate it. 当您要计算它时。

Advantages 好处

  • It will not overflow until n overflows 直到n溢出,它才会溢出
  • It is fast (just a multiplication) 快速(只是乘法)
  • It is not much code 代码不多

long answer 长答案

You produce an overflow because the numbers are too big. 因为数字太大,您会产生溢出。 Because of that, they go into the negative section. 因此,它们进入否定部分。

The amount of digits a number has equals the logarithm of the number(decimal=10) to the base of the numeric system you use without the decimal digits(casting to an int). 一个数字所具有的位数等于该数字的对数(decimal = 10)为所使用的无十进制数字的数字系统的底数(强制转换为int)。

This would be 这将是

int(lg(2^n))

Because 因为

lg(x)=lb(x)/lb(10)

you can change it to 您可以将其更改为

int(lb(2^n)/lb(10))

lb and 2^ cancel out, so you just have lb和2 ^抵消了,所以您只有

int(n/lb(10))

Let's get to the implementation: 让我们开始实现:

lb(x) is the same as lg(x)/lg(2) lb(x)lg(x)/lg(2)

So, you have 所以你有了

int(n/lg(10)/lg(2))

lg(10) is 1 and if you dive something that is 1/something , it cancels out, so you have: lg(10)1 ,如果您潜水的东西是1/something ,它会抵消,所以您有:

int(lg(2)*n)

In c, that is 在c中,即

(int)(log10(2)*n)

This would start counting with 0, so you would have to add one if you just want to get the number: 这将从0开始计数,因此如果您只想获取数字,则必须添加1:

(int)(log10(2)*n)+1

What is log , lg , lb ... ? 什么是loglglb ...?

log means logarithm. log手段对数。 It is the opposite operation of power. 这是权力的相反运作。

log(n,x) = n^x

while log(n,x) can be written as log n (x). log(n,x)可以写为log n (x)。

log n (x) can be changed to log a (x)/log a (n) which makes it easier to calculate in some cases. 可以将log n (x)更改为log a (x)/ log a (n),这使得在某些情况下更易于计算。

lg(x) (decimal logarithm) is a short form of log 10 (x). lg(x) (十进制对数)是log 10 (x)的缩写。

lb(x) (binary logarithm) is a short form of log 2 (x). lb(x) (二进制对数)是log 2 (x)的缩写。

Disclaimer 免责声明

If I mady any mistakes, please point it out in the comments. 如果我有任何错误,请在评论中指出。

For signed int t = pow(2,n) , if n >= 31 then t > INT_MAX .对于signed int t = pow(2,n) ,如果n >= 31t > INT_MAX

You can use unsigned long long t = pow(2,n) instead.您可以改用unsigned long long t = pow(2,n)

This will allow you to go as up as n == 63 .这将允许您达到n == 63

Also, since you're using base 2 , you can use (unsigned long long)1 << n instead of pow(2,n) .此外,由于您使用的是基数2 ,因此可以使用(unsigned long long)1 << n而不是pow(2,n)

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

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