I was trying to solve a problem using C on project euler click here
Here is the code. It works fine for 10 values but for 1000 values it gives a wrong output. I noticed that it gives a right output till 32. I think I'm exceeding the memory or something. How do I allocate memory for such a large array?
#include <stdio.h>
int main() {
int a[10], i, sum=1, b=0;
for(i = 1; i < 10; i++) {
a[0] = 1;
a[i] = sum + a[i-1];
sum = sum + a[i-1];
}
for(int j = 1;j > 0; j++) {
b = b + sum%10;
if(sum<10)
break;
sum = sum/10;
}
printf("%d\n",b);
return 0;
}
You might try computing 21000 as an 80-bit long double, then using sprintf to convert it to a string, then summing the digits of that string.
Why this works:
Floating-point types store numbers as a mantissa times an exponent. The exponent is always a power of two, and the mantissa can be 1. For a long double, the exponent can be up to 216383. printf and friends, on modern implementations, will correctly print out the digits of a floating-point number.
Code:
int main() {
char buf[1024]; int ans = 0;
sprintf(buf, "%.0f", 0x1.0p1000);
for (int i = 0; buf[i]; i++) ans += buf[i] - '0';
printf("%i\n", ans);
}
I noticed that it gives a right output till 32
That is, because the integer type you're using has 32 bits. It simply can't hold larger numbers. You can't solve it the conventional way.
Here's what I'd suggest: First let's estimate how many digits that number will have. Every time a number gets 10-fold in decimal writing a new digit is required. So the number of digits for a number in decimal is given by ceil(log10(n)). So for 2^1000 you need ceil(log10(2^1000)) digits, but that is just ceil(1000*log10(2)) = 302, so you'll need 302 decimal digits to write it down.
This gives the next idea: Write down the number 1 in 302 digits, i.e. 301 times '0' and one '1' in a string. Then double the string 1000 times, by adding it to itself just like in elementary school, carrying the overflowing digits.
EDIT I think I should point out, that the problem encountered is the whole point of this Project Euler problem. Project Euler problems all have in common, that you can not solve them by using naive programming methods. You must get creative to solve them!
Related
So I have this factorial function written in C:
unsigned int factorial(unsigned int n){
int fn = 1;
if(n == 0 || n == 1){
return 1;
} else{
for(int i = 1; i <= n; i++){
fn *= i;
}
}
return fn;
}
I tested it out with smaller numbers like 5 and it worked. Then I put it into this loop:
for(int i = 0; i < 100; i++){
printf("\n%d! = %d", i, factorial(i));
}
When i reaches 17, the factorial is apparently -288522240 which is obviously wrong. These kinds of answers continue until i reaches 34 and it says that the factorial is 0. It then does this for the rest of the numbers.
I don't understand what's wrong with my code. I see no reason for the number to become negative or 0. What's happened here?
100! or 9.3326...E+157 or
9332621544394415268169923885626670049071596826438162146859296389521759999322991560894146397615651828625369792082722375825118521091686400000000000000000000000, a 525 bit number, is outside the range of int - likely 32-bit [-2147483648 ... 2147483647]
Signed integer math that overflows is undefined behavior (UB). In OP's case, it appears that the lower 32-bits of the product fn * i, as 2's complement, was the result. Eventually enough multiplication of even numbers kept shifting the non-zero portion of the product "to the left" and resulted in that lower 32 bits becoming 0.
To calculate large factorials one needs another approach. Example
I have a small code which does some number transformations. I want to turn a number from double to long and then using right bit shift to cast it to short. But it gives me different results and I don't know why.
I have 3 numbers in an array and I make the sum of them using a for loop and every time I am gonna cast the result to short.
There is a number with .000000007 more exactly 63897600.000000007. Adding this to the total and then subtracting it gives me different results.
I can't figure out why does this occur and how can I manage this particular case.
Here is my code:
#include <stdio.h>
#define DOUBLETOLONG(number) (long)(number)
#define NEAREST(number) ((short)((number + 32768) >> 16))
#define LONGTOSHORT(number) NEAREST(DOUBLETOLONG(number))
int main() {
int k = 0;
double array[3] ={ 41451520.000000, 63897600.000000007, -63897600.000000007 };
double total_x = array[0];
short j = LONGTOSHORT(total_x);
printf("j = %d\n", j);
for (k = 1; k < 3; k++) {
total_x = total_x+array[k];
j = LONGTOSHORT(total_x);
printf("j = %d\n", j);
}
return 0;
}
This are the results:
j = 633
j = 1608
j = 632
41451520 + 63897600 = 105349120
In a double this integer can still be accurately represented. However, we didn't account for the fractional part 0.000000007. Let's check what the next biggest double is:
#include <stdio.h>
#include <math.h>
int main(int argc, char** argv) {
printf("%.23f\n", nextafter(105349120.0, INFINITY));
return 0;
}
Turns out, it's 105349120.000000014901.... Let's put those next to eachother:
105349120.000000014901...
0.000000007
This means that 105349120.000000007 is closer to 105349120 than the next bigger double, so it correctly gets rounded down to 105349120.
However, when we subtract again, 105349120 - 63897600.000000007 gets rounded down, because the next smaller double than 41451520 is (nextafter(41451520.0, 0)) 41451519.999999992549.... Put them next to eachother:
41451519.999999992549...
41451519.999999993
Yep, closer to the first double below 41451520 than 41451520 itself. So it correctly gets rounded down to 41451519.999999992549....
When you convert 41451519.999999992549... to an integer it floors the number, resulting in one less than what you expect.
Floating point math is full of surprises. You should read What Every Computer Scientist Should Know About Floating-Point Arithmetic, but perhaps it's still too advanced for now. But it's important to be aware that yes, floating point is full of surprises, but no it isn't magic, and you can learn the pitfalls.
I am new to C (and programming in general, minus a few weeks with Python). I am interested in learning how information is handled on a machine level, therefore I moved to C. Currently, I am working through some simple coding challenges and am having trouble finding information to resolve my current issue.
The challenge is to take N large integers into an array from input and print the sum of the numbers. The transition from Python to C has actually been more difficult than I expected due to the simplified nature of Python code.
Example input for the code below:
5
1000000001 1000000002 1000000003 1000000004 1000000005
Expected output:
5000000015
Code:
int main() {
long long unsigned int sum = 0;
int nums[200], n, i;
scanf("%i", &n);
for (i = 0; i =! n; i++) {
scanf("%i", &nums[i]);
sum = sum + nums[i];
}
printf("%llu", sum);
return 0;
}
The program seems to accept input for N, but it stops there.
One last question, in simple terms, what is the difference between a signed and unsigned variable?
Change your for loop like this
for (i = 0; i != n; i++) {
scanf("%i", &nums[i]);
sum = sum + nums[i];
}
if you say i =! n that is the same as i = !n. What that does is to assign the negated value of n to i. Since you gave a non-zero value to n the result is zero and the loop terminates.
Welcome to C!
Regarding the signed vs unsigned question. signed types can have negative values and unsigned can't. But they both take up the same space (number of bits) in memory. For instance, assuming twos' complement representation and a 32 bit integer, the range of values is
singed : -2^31 to 2^31 - 1 or –2147483648 to 2147483647
unsigned : 0 to 2^32 - 1 or 0 to 4294967295
Optimized way to handle the value of n^n (1 ≤ n ≤ 10^9)
I used long long int but it's not good enough as the value might be (1000^1000)
Searched and found the GMP library http://gmplib.org/ and BigInt class but don't wanna use them. I am looking for some numerical method to handle this.
I need to print the first and last k (1 ≤ k ≤ 9) digits of n^n
For the first k digits I am getting it like shown below (it's bit ugly way of doing it)
num = pow(n,n);
while(num){
arr[i++] = num%10;
num /= 10;
digit++;
}
while(digit > 0){
j=digit;
j--;
if(count<k){
printf("%lld",arr[j]);
count++;
}
digit--;
}
and for last k digits am using num % 10^k like below.
findk=pow(10,k);
lastDigits = num % findk;
enter code here
maximum value of k is 9. so i need only 18 digits at max.
I am think of getting those 18 digits without really solving the complete n^n expression.
Any idea/suggestion??
// note: Scope of use is limited.
#include <stdio.h>
long long powerMod(long long a, long long d, long long n){
// a ^ d mod n
long long result = 1;
while(d > 0){
if(d & 1)
result = result * a % n;
a = (a * a) % n;
d >>=1;
}
return result;
}
int main(void){
long long result = powerMod(999, 999, 1000000000);//999^999 mod 10^9
printf("%lld\n", result);//499998999
return 0;
}
Finding the Least Significant Digits (last k digits) are easy because of the property of modular arithmetic, which says: (n*n)%m == (n%m * n%m)%m, so the code shown by BLUEPIXY which followed exponentiation by squaring method will work well for finding k LSDs.
Now, Most Significant Digits (1st k digits) of N^N can be found in this way:
We know,
N^N = 10^(N log N)
So if you calculate N log (N) you will get a number of this format xxxx.yyyy, now we have to use this number as a power of 10, it is easily understandable that xxxx or integer part of the number will add xxxx zeros after 10, which is not important for you! That means, if you calculate 10^0.yyyy, you will get those significants digits you are looking for.
So the solution will be something like this:
double R = N * log10 (N);
R = R - (long long) R; //so taking only the fractional part
double V = pow(10, R);
int powerK = 1;
for (int i=0; i<k; i++) powerK *=10;
V *= powerK;
//Now Print the 1st K digits from V
Why don't you want to use bigint libraries?
bignum arithmetic is very hard to do right and efficiently. You could still get a PhD by working on that subject.
Fist, bigint arithmetic have non-trivial algorithmics
Then, bigint implementations usually need some machine instructions (like add with carry) which are not easily accessible in plain C.
For your specific problem (first and last few digits of NN) you'll better also reason on paper (using arithmetic theorems) to lower the complexity. I am not an expert, but I guess that still remains intractable, perhaps with a complexity worse than O(N)
I started working on Project Euler problems today to keep myself busy over break. One of the problems asks for the sum of all prime numbers below 2 million, so I threw together a Sieve of Eratosthenes to find all those numbers.
unsigned long i, j, sum = 0, limit = 2000000;
// Allocate an array to store the state of numbers (1 is prime, 0 is not).
int* primes = malloc(limit * sizeof(int));
// Initialize every number as prime.
for (i = 0; i < limit; i++)
primes[i] = 1;
// Use the sieve to check off values that are not prime.
for (i = 2; i*i < limit; i++)
if (primes[i] != 0)
for (j = 2; i*j < limit; j++)
primes[i*j] = 0;
// Get the sum of all numbers still marked prime.
for (i = 2; i < limit; i++)
if (primes[i] != 0)
sum += i;
printf("%d", sum);
This works perfectly up to limit around half a million. After this, it returns random values (for example, 1000000 returns -1104303641). I've tried declaring all the unsigned long variables as unsigned long long to no avail. The error seems to be happening in the last 4 lines, because primes[] contains nothing but 1's and 0's at that point. I figure this has something to do with the size of the values being worked with, can anyone offer any guidance?
Wolfram Alpha tells me that the sum of the primes less than 500000 is 9914236195.
That number doesn't fit in a 32 bit integer, so you're overflowing an int during your sum loop. You could try to use a uint64_t, but that problem will eventually occur again with a high enough limit (although I suspect that a limit of 2000000 will fit).
Change the %d to %ld and you should get:
142913828922
which seems like it should be (close to or) the right answer.
..assuming your longs aren't 32-bit.
If you're on a 32-bit platform, you're going to need some sort of third-party big int library.
BigInteger in C?
recommends: http://gmplib.org/