[英]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,这几乎没有那么有趣...... =)
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. 当您要计算它时。
n
overflows n
溢出,它才会溢出 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
log
, lg
, lb
... ? log
, lg
, lb
...? 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)的缩写。
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 >= 31
则t > 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.