Why doesn't this factorial compute correctly? - c

I am trying to learn some C programming, and to test my basic skills, I am making a simple program that computes factorials. However, instead of giving the correct answer of 120 for the factorial of 5, it gives -1899959296. What's wrong? Here's my code below:
#include <stdio.h>
int factorial(int x)
{
int i;
for(i=1; i < x; i++)
x *= i;
return x;
}
int main()
{
int a = 5, b;
b = factorial(a);
printf("The factorial of %d is %d \n", a, b);
return 0;
}
Thanks in advance!

Your problem is that the function factorial() is continually modifying x. For any of x which is initially 3 or more, x will keep increasing, so the loop will keep running.
Consider if you call fact(3).
The function is called with x = 3. First iteration of the loop with i = 1 will multiply x by 1. So x will still have the value of 3. i i will be incremented to 2, which is less than 3, so the next iteration starts.
The second iteration of the loop will multiply x by 2, giving the result of 6. i is incremented to 3, which is less than 6, so the next iteration starts.
The third iteration will multiply x by 3, giving the result of 18. i is incremented to 4, which is less than 18, so the next iteration starts.
Notice the pattern in the above ..... the end condition is i < x. i is incremented in each iteration. x is multiplied by i. This means that x increases substantially faster than i does .... which means i < x is always true.
Well almost ..... eventually the logic breaks down.
Eventually x will overflow - the result of multiplying it by i will produce a result that exceeds what can be stored in an int. The result of overflowing an int is undefined ..... anything can happen at that point.
Compare the description above with what YOU would do if asked to compute the factorial of 3. Would you do similar steps? Probably not.

int factorial(int x)
{
int i;
int count =x;
for(i=1; i < count ; i++)
x *= i;
return x;
}
Modify like this. your issue is with the loop count.. Since value of x is changing the loop may become infinite..

C) You're using x as an upperbound for your for loop i < x
B) You're also increasing x nearly exponentially on every loop x *= i, your loop won't work.
You might have noticed that you get a negative number back. The reason the loop exits at all is that you've chosen to type x as a 32 bit signed integer (the default int)- The processor works in binary: so once you go higher than is actually possible with just 32 bits, it still tries to do math but it loses data and loops back around to negative numbers. So once x loops back around and becomes negative, then i > x and the loop exits.
Here: http://tpcg.io/8sX5ls

The error is in the for, the factorial of a number is n * n-1 * ... * n-(n-1), so to solve this, just start the index in x - 1 and decrement it until it turns 1, sorry for my bad English, I hope you understood what I said.
here is the answer:
for ( i = x - 1; i > 1; --i )
x *= i;
Just to explain why the negative number, first we must understand what happens in the for which it was declared.
for(i=1; i < x; i++)
x *= i;
As we can see the condition for it to continue in the loop is i < x, but within it is assigned to x the value of x * i (x * = i or x = x * i), so x has no constant value and is always increasing, the i increases at a velocity smaller than that of x because the i is always added to 1 (i ++, i + = 1 or i = i + 1), which causes the x to be unreachable , then the for will be in an infinite loop.
But every type has its range, and int is 4 bytes, therefore 32 bit, what happens is that there comes a time when x exceeds this range having the famous integer overflow, this is why its value is negative, then the condition of the for becomes false and then the for stop.
We have to remember that a number is represented in memory in binary form, and the last binary number is what represents whether the number is positive or negative, 0 is positive, 1 is negative, when integer overflow happens the last number changes to 1 , making it so negative.
To better understand this here are some links that can help:
https://en.wikipedia.org/wiki/Two%27s_complement
https://en.wikipedia.org/wiki/Integer_overflow.

Related

How can I concatenate an integer with desired times in C?

I want to write a function like this:
int number_maker(int n, int k)
{
if(k==1)
return n;
else
{
int x = 10;
while(n >= x)
x *= 10;
return (n*x) + number_maker(n,k-1) ;
}
}
For an example, let's say my number is 350. I want to make it based on
a repeated parameter. I can make it 350350 but when it comes to more repetitions like 3 or 4 times, it goes wrong.
I can't use standard C functions.
Your program is trying to store a number greater than INT_MAX in an int, which results in an overflow during conversion. Even if you modify your function to have a size_t return type, that will only get you so far. The only way to be sure that your program produces accurate output is to store the concatenated integer as a char* and return that, instead.
While it is possible to repeat any three digit repetition in a 32-bit int, three times, it is not possible to fit four repetitions as only all 9 digit decimal integers can be represented.
Your problem with three repetitions is because on each recursion x is always 1000 (for a three digit n), whereas you actually need it to be 1000000 on the second recursion. Solving that is somewhat cumbersome, but you need to pass x into the number_maker thus:
int number_maker(int n, int k, int x) // <<< additional parameter
{
if(k==1)
return n;
else
{
int xx = x ; // <<< added
while(n * xx >= x) // <<< modified
x *= 10;
return (n*x) + number_maker(n,k-1, x) ;
}
}
Then a call such as:
printf("%d", number_maker( 350, 3, 1 ) );
will work. It is cumbersome because you have to pass an initial x value, and that can only be 1. In C++ you could use an default argument to hide that.
It will not work however for 4 repetitions or a three digit decimal integer.
That said:
printf("%d", number_maker( 1, 9, 1 ) );
printf("%d", number_maker( 9, 9, 1 ) );
work ok. You can get away with 10 repetitions only for n==1.
printf("%d", number_maker( 1, 10, 1 ) );
Essentially it works for all 9 digit results and (less usefully) some 10 digit results.
Using unsigned integers would increase the number of 10 digit results that could be represented, but that is not particularly useful perhaps.

Optimizing loop by using floating point value as loop counter

I need to execute a loop
while (X) do Y
for a N times, which is a large number. While Y, the loop body, is rather quick, the test X takes up about 70% of the runtime.
I can calculate the number of loop iterations N beforehand so instead of using X as the condition, a simple For-Loop would be possible.
for (i=1 to N) do Y
However, N might exceed the maximum value an integer can store on the machine, so this is not an option. As an alternative, I proposed to use a floating point variable F instead. As N is large, it is likely that F cannot be exactly equal to N. Thus, I calculate F to be the largest floating point number smaller than N. This allows me to run
for (i=1 to F) do Y
while (X) do Y
Most of the iterations will not need to test X everytime, only the last N-F do.
The question is: How would I implement a for-Loop from 1 to F? Simply increasing a counter or decreasing F by 1 in each step would not work, as the numerical error would grow too large. My current solution is:
for (while F > MAXINT)
for (i=1 to MAXINT)
do Y
F -= MAXINT
while (X) do Y
Is there a better way to solve this problem?
What do you mean by numerical error? Floating point counting is exact within its precision.
Here are the maximum values representable by integers exactly using the following data types:
uint32max = 4294967295
uint64max = 18446744073709551615
float32intmax = 16777216
float64intmax = 9007199254740992
Every integer from 0 to the max is exactly representable without numerical error.
As you can see, the largest count is available with uint64. Next comes float64, then uint32 and finally float32.
What happens when you increment uint32=4294967295 ? 0.
What happens when you increment float32=16777216 ? 16777216.
Which is the better behavior?
Have you thought about using a 2-dimensional loop? If N ism the maximum count for a 1-dimensional loop, then N x N is the maximum for a 2-dimensional loop, etc. so that if you maximum count is less than MAXUINT x MAXUINT, then decompose you number N such that:
N == M * MAXUINT + R;
where
M = N / MAXUINT;
R = N - M * MAXUINT;
then
for (i = M; i--;) for (j = MAXUINT; j--;) DoStuff();
for (i = R; i--;) DoStuff();
If MAXUINT*MAXUINT is not a large enough count for you, you can add 3-, 4-, ... -dimensional loops.

How would I format a while(loop)?

I'm having trouble understanding the format a while(loop) uses.
How would I go about making one for example one that computes the sum of all multiples of 5 and 9 between a set range of numbers?
while STATEMENT:
CODE BLOCK
The basic format of any while loop is such that "CODE BLOCK" is executed as long as "STATEMENT" holds true.
For example:
x = 6
while (x > 5) and (x < 20):
x = x + 1
As long as x is greater than 5 and less than 20 x will be incremented by one. The loop will terminate when x is equal to twenty. If I had initialized x to 0, the loop would never enter the block and x will remain zero.
Hopefully that helps

C Program to sum a simple series

I have a program here that is supposed to sum up the series
1+1/2+1/3+1/4... etc
The only user entry is to enter how many times you want this sum to run for.
However, I keep getting the sum one.
#include <stdio.h>
int main(void)
{
int b,x; /* b is number of times program runs and x is the count*/
float sum;
printf("Enter the number of times you want series to run.\n");
scanf("%d", &b);
printf("x sum\n");
for(x=1,sum=0;x<b+1;x++)
{
printf("%d %9.3f\n",x, (sum +=(float)(1/x)));
}
return 0;
}
I don't quite get why it isn't working. As you can see, I did tell it to print x and when it did, x was incrementing correctly.The sum just kept adding up to one.
You have misplaced parentheses so you're doing integer division for 1/x and getting 0 for any value of x > 1.
I suggest you change:
printf("%d %9.3f\n",x, (sum +=(float)(1/x)));
to:
printf("%d %9.3f\n",x, (sum += 1.0f/x));
Two problems: one dull, one interesting.
1) 1 / x will be imprecise since 1 and x are both integral types and so the computation will be done in integer arithmetic. All the cast does is convert the resultant integral type to floating point. To resolve this, write 1.0 / x. Then 'x' is promoted to floating point prior to the division.
2) You should reverse the order of the for loop:
sum = 0.0;
for(x = b; x >= 1; --x)
(I've also moved the initialisation or sum from the for loop as sum = 0 is an expression of type float but x = b is an expression of type int so you ought not use the comma operator as they have different data types.)
The reason is subtle: you should only add floating points of similar magnitude. Doing the loop my way means the smaller values are added first.
The effect will be noticeable for high values of b; try it. Your original way will always understate the sum.
The problem is integer division when you do 1/x, which always result in 0 as long as x is greater than 1. Even it you later convert this to a float, the "damage" is already done. An easy fix would be to change the division to 1.0f/x.
Since you have declared x as an int, (1/x) returns 1 when x is 1 and 0 for x>1. So, sum remains 1. So you get the same result.
So, change (1/x) to 1.0f/x, so that the result is returned as a float
Here you are computing 1/x in which the fractional value is truncated. Converting it into float after the original value has been truncated doesn't make sense.
So change this to:-
printf("%d %9.3f\n",x, (sum +=(float)(1/x)));
to
printf("%d %9.3f\n",x, (sum += 1.0f/x));
The expression (1/x) will always be integer division. For the first run this will be 1/1 giving you 1. However, next time round it will be 1/2 which is 0. Basically for 1/x where x>1 the answer will be zero.
To get around this write the expression as 1.0/x which will cause x to be promoted to a double, giving you double division.

Unclear about modulus function c language

Here is a C language function, which I am having a little trouble understanding. I need to show what values of r come out when I input values of 6 or 10 or 13 into the function:
int factor(int val){
int r=val-1;
while(val%r){
r--;
}
return r;
}
I'm not sure if I misunderstood the question but wouldn't the remainder always be true? Since 0 = false and the while statement never reaches 0 because r is always smaller than val and not equal to it, and each time r decreases the remainder just gets bigger?
Edit: Just realized i forgot to account that 6%3 = 0! thanks for the help people who helped!
Test for yourself: 4 % 2.
The result should be 0 as the % operator returns the remainder of a division.
while(x % y) {} translates in this context to something like: as long as x is not dividable by y, do something, whereby 'do something' is decrease y in your case.
Essentially, the function returns the largest factor of the number input to the method.
It translates to "while there is a remainder from division (r is NOT a factor of val), decrease r by 1 and check again. Once the clean factor is found (val % r is 0), return the factor (r).
Here's a JavaScript port with sample output:
http://jsfiddle.net/43HxX/2/
I rewrote it in JS and you can uncomment the alert(...) line to see the output for 6, 10, and 13

Resources