Why does this factorial function break after a certain point? - c

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

Related

Why I get wrong answers from function that should calculate X in power of N?

I had to make a recursive function that use only multiplication operation to get the answer of X in power of N.
I wrote this:
#include <stdio.h>
int power(int x, int n);
int main()
{
int x, n;
printf("Enter base and exponent:\n");
scanf("%d%d", &x, &n);
printf("%d\n", power(x, n));
return 0;
}
int power(int x, int n)
{
if (n==0) return 1;
return x*power(x, n*0.5);
}
So its works good for small number, like if the input x=3, n=2 the output will be 9 which is good. But when I input bigger numbers, for example: x=362, n=123 the output will be -79249792 which its wrong.
Can someone help me understand what's wrong?
(Im using Online C Compliler {OnlineGBD})
First, the recursion you implemented shouldn't work for small numbers too, since as others have pointed out, x^n = (x^(n/2))^2 and not x*(x^(n/2)), and for odd values of n, n/2 will get truncated since the function takes integer arguments. Try 2^3, your code gives answer 4. A simple way to fix this is via using the following recursion : x^n = x*(x^(n-1)), or if you want to make the code more efficient, use this algorithm.
But this still doesn't address negative numbers showing up. The problem is max size of int is 2^31-1 = 2,14,74,83,647. This is due the way it is stored in memory, occupying 32 bits. What happens when you cross this limit? It overflows, and becomes -2^31. So you won't be able to get correct answers for big numbers. Generally this is handled by calculating the answer modulo some prime number, or creating arbitrary precision data structures. Check out this and this.
First of all, please remove this:
printf("Enter base and exponent:\n");
scanf("%d%d", &x, &n);
printf("%d\n", power(x, n));
and write a simple, easy to run test harness that doesn't involve thinking and typing input into the console, with clear output of expected/actual values on failure:
#include <math.h>
#include <stdio.h>
int power(int base, int exponent) {
return 1;
}
int main(void) {
for (int base = 0; base < 5; base++) {
for (int exponent = 0; exponent < 5; exponent++) {
int expected = (int)pow(base, exponent);
int actual = power(base, exponent);
if (expected != actual) {
printf("[FAIL] power(%d, %d) was: %d\n"
" expected: %d\n\n",
base, exponent, actual, expected);
}
}
}
return 0;
}
Notice the clearer parameter names on the power function and usage of the built-in pow to ensure correct logic.
Now let's test your algorithm:
[FAIL] power(2, 3) was: 4
expected: 8
[FAIL] power(2, 4) was: 8
expected: 16
[FAIL] power(3, 3) was: 9
expected: 27
[FAIL] power(3, 4) was: 27
expected: 81
[FAIL] power(4, 3) was: 16
expected: 64
[FAIL] power(4, 4) was: 64
expected: 256
It appears that n*0.5 isn't giving the correct reduction factor.
Taking a step back, exponentiation by multiplication is done by repeatedly multiplying base by itself exponent times and accumulating onto a result initialized to 1:
int power(int base, int exponent) {
int result = 1;
for (int i = 0; i < exponent; i++) {
result *= base;
}
return result;
}
Since we're forced to use recursion, the problem reduces to simulating the classic counting loop above with recursion.
This can be done by subtracting 1 from the exponent per call until we reach 0 (<= 0 is a safer base case than == 0, avoiding blowing the stack on negative input).
As for the return value, you're correct in returning 1 for n == 0 and multiplying base on each frame by the child's value, which is the same as the *= operation in the iterative version.
Here's the fixed code:
int power(int base, int exponent) {
if (exponent <= 0) {
return 1;
}
return base * power(base, exponent - 1);
}
Finally, x=362, n=123 fails because of integer overflow. 362**123 has 315 digits, but 4 byte numbers like int only hold 10-ish. You'll need a big integer library to handle that massive an input.
Note that I haven't attempted to handle negative numbers here. I assume that's out of scope. Making the parameters unsigned would help enforce this contract.

Why doesn't this code work for a[100] and above? (project euler 2 in C)

Here is my code:
I don't understand why it gives me the wrong answer above 50.
#include<stdio.h>
int main()
{
long long int i, sum=0;
long long int a[50];
a[0] = 1;
a[1] = 1;
for(i=2;i<50;i++)
{
a[i] = a[i-1] + a[i-2];
if(a[i]%2==0 && a[i]<4000000)
sum = sum + a[i];
}
printf("%lld", sum);
return 0;
}
Your first mistake was not breaking out of the loop when a term
exceeded 4,000,000. You don’t need to consider terms beyond that for the
stated problem; you don’t need to deal with integer overflow if you stop
there; and you don’t need anywhere near 50 terms to get that far.
Nor, for that matter, do you need to store all of the terms, unless you
want to look at them to check correctness (and simply printing them
would work just as well for that).
You have an integer overflow. Fibonacci numbers get really big. Around F(94) things get out of the range of 64 bit integers (like long long).
F(90) = 2880067194370816120 >= 2^61
F(91) = 4660046610375530309 >= 2^62
F(92) = 7540113804746346429 >= 2^62
F(93) = 12200160415121876738 >= 2^63
F(94) = 19740274219868223167 >= 2^64
F(95) = 31940434634990099905 >= 2^64
F(96) = 51680708854858323072 >= 2^65
When the overflow happens, you will get smaller, or even negative numbers in a instead of the real fibonacci numbers. You need to workaround this overflow.

Adding Big Ints from Array in C Results in No Output

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

Program crashes when `if (variable % 2 == 0)`

I'm writing a program that finds perfect numbers. Having read about these perfect numbers I came across a list of them: List of perfect numbers. At the moment the output is:
28 // perfect
496 // perfect
8128 // perfect
130816 // not perfect
2096128 // not perfect
33550336 // perfect
I decided to create array and put it with numbers, which divide the number wholly (without the rest). So I will be able to verify if it is a perfect number or not by adding all elements of the array. But app crashes and I cannot understand why:
#include <stdio.h>
#include <stdlib.h>
int main()
{
unsigned long number;
unsigned long arr2[100] = {0};
int k = 0;
for ( number = 0; number <= 130816; number++ )
if ( 130816 % number == 0 )
arr2[k++] = number;
for ( k = 0; k < 100; k++ )
printf("%lu", arr2[k]);
return 0;
}
You are doing modulus zero here:
if ( 130816 % number == 0 )
which is undefined behavior. If you start your for loop at 1 instead it should fix that issue. However, since N % 1 == 0 for all N, you probably need to start at 2.
From the C99 standard, 6.5.5 /5 (unchanged in C11):
The result of the / operator is the quotient from the division of the first operand by the
second; the result of the % operator is the remainder. In both operations, if the value of
the second operand is zero, the behavior is undefined.
You are dividing by zero when number=0;
138816 % number involves division and a remainder.

Allocating large memory in C (Project Euler Prob)

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!

Resources