Calculating sum of digits of 2^n in C - 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.
For example, for 2^10, we'd have 1+0+2+4, which is 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.
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 108 you mentioned. The number 2108 requires 108 + 1 (100,000,001) bits, or around 12 megabytes of memory, to store in binary. In decimal it has around 30 million digits.
Your int is 32 bits wide, which is why the signed int can't store 231 – the 32nd bit is the sign while 231 has a 1 followed by 31 zeros in binary, requiring 32 bits without the sign. So it overflows and is interpreted as a negative number. (Technically signed integer overflow is undefined behaviour in 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 2127 is still way less than 2100000000.
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). Alternatively, you can limit your solution to, say, uint64_t, but then you have n < 64, which is not nearly as interesting… =)

For signed int t = pow(2,n), if n >= 31 then t > INT_MAX.
You can use unsigned long long t = pow(2,n) instead.
This will allow you to go as up as n == 63.
Also, since you're using base 2, you can use (unsigned long long)1 << n instead of pow(2,n).

Related

I've made a program in C that takes two inputs, x and n, and raises x to the power of n. 10^10 doesn't work, what happened?

I've made a program in C that takes two inputs, x and n, and raises x to the power of n. 10^10 doesn't work, what happened?
#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
float isEven(int n)
{
return n % 2 == 0;
}
float isOdd(int n)
{
return !isEven(n);
}
float power(int x, int n)
{
// base case
if (n == 0)
{
return 1;
}
// recursive case: n is negative
else if (n < 0)
{
return (1 / power(x, -n));
}
// recursive case: n is odd
else if (isOdd(n))
{
return x * power(x, n-1);
}
// recursive case: n is positive and even
else if (isEven(n))
{
int y = power(x, n/2);
return y * y;
}
return true;
}
int displayPower(int x, int n)
{
printf("%d to the %d is %f", x, n, power(x, n));
return true;
}
int main(void)
{
int x = 0;
printf("What will be the base number?");
scanf("%d", &x);
int n = 0;
printf("What will be the exponent?");
scanf("%d", &n);
displayPower(x, n);
}
For example, here is a pair of inputs that works:
./exponentRecursion
What will be the base number?10
What will be the exponent?9
10 to the 9 is 1000000000.000000
But this is what I get for 10^10:
./exponentRecursion
What will be the base number?10
What will be the exponent?10
10 to the 10 is 1410065408.000000
Why does this write such a weird number?
BTW, 10^11 returns 14100654080.000000, exactly ten times the above.
Perhaps it may be that there is some "Limit" to the data type that I am using? I am not sure.
Your variable x is an int type. The most common internal representation of that is 32 bits. That a signed binary number, so only 31 bits are available for representing a magnitude, with the usual maximum positive int value being 2^31 - 1 = 2,147,483,647. Anything larger that that will overflow, giving a smaller magnitude and possibly a negative sign.
For a greater range, you can change the type of x to long long (usually 64 bits--about 18 digits) or double (usually 64 bits, with 51 bits of precision for about 15 digits).
(Warning: Many implementations use the same representation for int and long, so using long might not be an improvement.)
A float only has enough precision for about 7 decimal digits. Any number with more digits than that will only be an approximations.
If you switch to double you'll get about 16 digits of precision.
When you start handling large numbers with the basic data types in C, you can run into trouble.
Integral types have a limited range of values (such as 4x109 for a 32-bit unsigned integer). Floating point type haver a much larger range (though not infinite) but limited precision. For example, IEEE754 double precision can give you about 16 decimal digits of precision in the range +/-10308
To recover both of these aspects, you'll need to use a bignum library of some sort, such as MPIR.
If you are mixing different data types in a C program, there are several implicit casts done by the compiler. As there are strong rules how the compiler works one can exactly figure out, what happens to your program and why.
As I do not know all of this casting rules, I did the following: Estimating the maximum of precision needed for the biggest result. Then casting explicit every variable and funktion in the process to this precision, even if it is not necessary. Normally this will work like a workarount.

How to sum large numbers?

I am trying to calculate 1 + 1 * 2 + 1 * 2 * 3 + 1 * 2 * 3 * 4 + ... + 1 * 2 * ... * n where n is the user input.
It works for values of n up to 12. I want to calculate the sum for n = 13, n = 14 and n = 15. How do I do that in C89? As I know, I can use unsigned long long int only in C99 or C11.
Input 13, result 2455009817, expected 6749977113
Input 14, result 3733955097, expected 93928268313
Input 15, result 1443297817, expected 1401602636313
My code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
unsigned long int n;
unsigned long int P = 1;
int i;
unsigned long int sum = 0;
scanf("%lu", &n);
for(i = 1; i <= n; i++)
{
P *= i;
sum += P;
}
printf("%lu", sum);
return 0;
}
In practice, you want some arbitrary precision arithmetic (a.k.a. bigint or bignum) library. My recommendation is GMPlib but there are other ones.
Don't try to code your own bignum library. Efficient & clever algorithms exist, but they are unintuitive and difficult to grasp (you can find entire books devoted to that question). In addition, existing libraries like GMPlib are taking advantage of specific machine instructions (e.g. ADC -add with carry) that a standard C compiler won't emit (from pure C code).
If this is a homework and you are not allowed to use external code, consider for example representing a number in base or radix 1000000000 (one billion) and code yourself the operations in a very naive way, similar to what you have learned as a kid. But be aware that more efficient algorithms exist (and that real bignum libraries are using them).
A number could be represented in base 1000000000 by having an array of unsigned, each being a "digit" of base 1000000000. So you need to manage arrays (probably heap allocated, using malloc) and their length.
You could use a double, especially if your platform uses IEEE754.
Such a double gives you 53 bits of precision, which means integers are exact up to the 53rd power of 2. That's good enough for this case.
If your platform doesn't use IEEE754 then consult the documentation on the floating point scheme adopted. It might be adequate.
A simple approach when you're just over the limit of MaxInt, is to do the computations modulo 10^n for a suitable n and you do the same computation as floating point computation but where you divide everything by 10^r.The former result will give you the first n digits while the latter result will give you the last digits of the answer with the first r digits removed. Then the last few digits here will be inaccurate due to roundoff errors, so you should choose r a bit smaller than n. In this case taking n = 9 and r = 5 will work well.

Upper bound for number of digits of big integer in different base

I want to create a big integer from string representation and to do that efficiently I need an upper bound on the number of digits in the target base to avoid reallocating memory.
Example:
A 640 bit number has 640 digits in base 2, but only ten digits in base 2^64, so I will have to allocate ten 64 bit integers to hold the result.
The function I am currently using is:
int get_num_digits_in_different_base(int n_digits, double src_base, double dst_base){
return ceil(n_digits*log(src_base)/log(dst_base));
}
Where src_base is in {2, ..., 10 + 26} and dst_base is in {2^8, 2^16, 2^32, 2^64}.
I am not sure if the result will always be correctly rounded though. log2 would be easier to reason about, but I read that older versions of Microsoft Visual C++ do not support that function. It could be emulated like log2(x) = log(x)/log(2) but now I am back where I started.
GMP probably implements a function to do base conversion, but I may not read the source or else I might get GPL cancer so I can not do that.
I imagine speed is of some concern, or else you could just try the floating point-based estimate and adjust if it turned out to be too small. In that case, one can sacrifice tightness of the estimate for speed.
In the following, let dst_base be 2^w, src_base be b, and n_digits be n.
Let k(b,w)=max {j | b^j < 2^w}. This represents the largest power of b that is guaranteed to fit within a w-wide binary (non-negative) integer. Because of the relatively small number of source and destination bases, these values can be precomputed and looked-up in a table, but mathematically k(b,w)=[w log 2/log b] (where [.] denotes the integer part.)
For a given n let m=ceil( n / k(b,w) ). Then the maximum number of dst_base digits required to hold a number less than b^n is:
ceil(log (b^n-1)/log (2^w)) ≤ ceil(log (b^n) / log (2^w) )
≤ ceil( m . log (b^k(b,w)) / log (2^w) ) ≤ m.
In short, if you precalculate the k(b,w) values, you can quickly get an upper bound (which is not tight!) by dividing n by k, rounding up.
I'm not sure about float point rounding in this case, but it is relatively easy to implement this using only integers, as log2 is a classic bit manipulation pattern and integer division can be easily rounded up. The following code is equivalent to yours, but using integers:
// Returns log2(x) rounded up using bit manipulation (not most efficient way)
unsigned int log2(unsigned int x)
{
unsigned int y = 0;
--x;
while (x) {
y++;
x >>= 1;
}
return y;
}
// Returns ceil(a/b) using integer division
unsigned int roundup(unsigned int a, unsigned int b)
{
return (a + b - 1) / b;
}
unsigned int get_num_digits_in_different_base(unsigned int n_digits, unsigned int src_base, unsigned int log2_dst_base)
{
return roundup(n_digits * log2(src_base), log2_dst_base);
}
Please, note that:
This function return different results compared to yours! However, in every case I looked, both were still correct (the smaller value was more accurate, but your requirement is just an upper bound).
The integer version I wrote receives log2_dst_base instead of dst_base to avoid overflow for 2^64.
log2 can be made more efficient using lookup tables.
I've used unsigned int instead of int.

This program doesn't work properly for decimals more than 10 digits?

The below code is used to count number of digit in a given decimal. The problem is that it doesn't count digits more than 10.
int NumDigits(int n) {
int digits = 0;
if (n <= 0) {
n = -n;
++digits;
}
while (n) {
n /= 10;
++digits;
}
return digits;
}
It seems like your toolchain has a 32-bit int type. The maximum value representable in such a type is 231-1, or 2,147,483,647. As you can see, that's a 10-digit number. You'll need to use a different type that supports larger numbers if you want to use this kind of an algorithm.
That's a 32 bit integer, which has a maximum amount of 2,147,483,647. You might want to look into using 64 bit integers or other solutions.
Try long for the argument type.
As Jonathan already stated in his comment an int cannot contain a number with more than 10 digits.
The reason is that your parameter is of the type int, which is limited in size.
Most likely you have Int32 (you can find it out with sizeof(int) which gives you the size in byte) which goes up to 2147483647 and then overflows to the negative value -2147483648.
Example:
int i = 2147483647;
i = i+1;
printf("%d\n",i);
gives you the output: "-2147483648"

Is there a maximum length of integers I can enter for C?

for the b/m, I am trying to sum up the digits of an integer. eg. if I enter 1234, i get the answer 1 + 2 + 3 + 4 = 10.
this works for integers up to 10 digits long. after that, if i enter an integer with 11 digits like 12345678912, it returns me a negative answer.
Could anyone help to explain why this is so please? And if there's anyway I can get around it?
Thank you!
#include <stdio.h>
int main(void)
{
int number, single_digit, sum;
printf("What number would you like to sum:\n");
scanf("%i", &number);
sum = 0;
while(number != 0)
{
single_digit = number % 10;
sum += single_digit;
number = number / 10;
}
printf("The sum of the number is %i.\n", sum);
return 0;
}
Yes, the maximum value an integer can hold is INT_MAX (whose value depends on your platform).
An unsigned int can hold larger (positive) numbers, up to UINT_MAX.
You may be able to fit more in unsigned long or unsigned long long - again, the details are platform-specific. After that, you're looking for a bignum library.
NB. since you just want to sum the digits, using something like haccks' approach is much simpler, and less likely to overflow. It's still possible, though.
The maximum limit for an int is INT_MAX. You are getting -ve value because 12345678912 doesn't fit in the range of int and causes integer overflow.
Better to change your main's body to
sum = 0;
int ch;
printf("Enter the number would you like to sum:\n");
while((ch = getchar()) != '\n' && ch != EOF)
{
sum += ch - '0';
}
printf("The sum of the number is %i.\n", sum);
Since getchar reads single character at a time, you will get your desired output by adding these to sum.
This is happening because an int is only 4 bytes. What that means is any number larger than 2^31 will cause the buffer to overflow. A more detailed explanation can be found here: http://en.wikipedia.org/wiki/Integer_overflow. If you want to get around it, use an unsigned int instead, it will let you go up to 2^32 instead, but it will not let you have any negative numbers.
The int type is (usually) a signed 32-bit integer (you can see your size by printing sizeof(int)*8 to get the number of bits.
This means that the maximum value you can store in an int is 2^32 - 1, but, because int is signed, the range is actually half that.
In C a specific type of integer is stored in a fixed amount of memory. On all current architectures an int is stored in 32 bits. Since int carries a sign, the most significant bit is assigned to the sign. This means that the biggest integer you can store in an int is 2^31 - 1. You are seeing a negative number because the your int is overflowing into the sign bit and making it negative.
Number types in c are limited. You can find the max ints in limits.h
You should read the input as a string (char array) and process each character to allow arbitrary* lenght numbers.
*The sum still need to be less than max int. the input string must be big enough to contain what the user writes
An integer with 11 digits like 12345678912 if too large to fit in number which is an int on your platform.
In C, an int has of range of at least -32767 to 32767. On your platform it apparently has the range -2147483648 to +2147483647.
If code is to read the entire integer at once, the maximum number of digits is limited by the range of the various available integer types.
C provides an integer type called intmax_t and its unsigned partner uintmax_t which typically has the maximum range available on a given platform.
#include <inttypes.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
void MaximalSumOFDigits(void) {
uintmax_t number;
double widthf = log10(UINTMAX_MAX);
int widthi = ((int) floor(widthf)) - 1;
char buf[widthi + 2];
printf("What number would you like to sum: (up to %d digits)\n", widthi);
fgets(buf, sizeof buf, stdin);
char *endptr;
errno = 0;
number = strtoumax(buf, &endptr, 10);
if (*endptr != '\n')
Handle_UnexpectedInput();
if (errno) // This should not easily happen as buffer has limited length
Handle_TooBigANumber();
int sum = 0;
while (number > 0) { // avoiding ASCII dependence
sum += number % 10;
number /= 10;
}
printf("The sum of the number is %d.\n", sum);
}
With a 64-bit uintmax_t, allows numbers up to
18446744073709551615 (any 19 digit number and some 20 digit numbers)
The above suggests to the user input limit of limit of
_9999999999999999999 (any 19 digit number)

Resources