Is this factorial function from a C tutorial wrong? - c

I have a little programming experience in Python, and for the sake of curiosity I started to learn C, at least the very basics. In a tutorial, I found an example function for calculating a factorial, which is this:
int factorial(int x)
{
int i;
for(i=1; i < x; i++)
{
x *= i;
}
return x;
}
I also added these lines in order to see the output:
#include <stdio.h>
int main()
{
int val;
val = factorial(5);
printf("%d\n",val);
return 0;
}
Then I compiled the code with gcc factor.c -o factor.out, run and... ooops, the result is -1899959296, clearly there's something wrong.
After a couple of tries, using printf() to print both i and x, I figured out what went wrong (I think): since the condition of the for loop checks if the counter is less than x, and at each step x gets bigger and bigger, i is always less than x, so the loop keeps going on, presumably stopping when the value of x is too big (which should be related to int, I'm not very familiar yet with the various data types).
So, to "solve" the problem, I rewrote the function like this:
int factorial(int x)
{
int counter = x;
int number = x;
int i;
for (i=1; i < counter; i++)
{
number *= i;
}
return number;
}
I compiled the program, run, and the value printed is 120, which is correct.
I searched a little bit for examples of factorial functions in C, and found many solutions much better than mine, taking into account negative numbers and formats like long and whatnot, but all of them, in a way or another, seem to rely on two "main" variables, much like my solution.
So, the final question: is the example proposed wrong, or am I missing something? This really bothers me, because if such a simple example is blatantly wrong, I should question the credibility of the rest.

Yes, indeed. The original factorial function is wrong for exactly the reason you've identified. You can't use x as both the accumulator and loop limit.
In your version, one improvement I'd suggest is to get rid of counter. Since you're no longer modifying x, you don't need to save off a copy of it.
int factorial(int x)
{
int number = x;
int i;
for (i=1; i < x; i++)
{
number *= i;
}
return number;
}
You could do this without additional variables if you reverse the loop.
int factorial(int x)
{
int i;
for (i = x - 1; i > 1; i--)
{
x *= i;
}
return x;
}
I wouldn't write it this way, though. Modifying an input parameter is poor style.

I think by putting loop condition i<=x and using another variable to store factorial will correct it.
Here is the example:
int factorial(int x)
{
int i;
int fact = 1; //store factorial
for (i = 1; i <= x; i++)
{
fact *= i;
}
return fact;
}
Or you can use recursive function
int factorial(int x) {
if (x == 1)
return 1;
else
return x * factorial(x - 1);
}

Related

How can I deal with compiler error c2660 in recursive function and iterative function?

#include <stdio.h>
double recursive(int n);
double iterative(int n);
int n;
double ans1, ans2;
int main(int n) {
do {
printf("input:");
scanf("%d", &n);
ans1 = recursive(n);
ans2 = iterative(n);
printf("%f", ans1);
printf("%f", ans2);
} while (n != 0);
return 0;
}
double recursive(int n) {
double result = 0.0;
result += (1 / n);
return recursive(n);
}
double iterative(int n) {
int i;
double result = 0.0;
for (i = 0; i < n; i++) {
result += (1 / n);
}
return result;
}
Visual studio says that recursive function and iterative function has c2660 error. I think I used one arguments each when declaring the function and using the function. How can I fix this problem?
The big issue here is in your recursive function. Every recursive function needs a base case. That is, there must be some condition that, when true, does not cause a recursive call. Also, unless that condition is based on some global variable (which is not a good idea), you need to change the parameter(s) with which you call the function as otherwise it'll just do the same thing every time and never reach the base case. As you have it, no call to recursive will ever return since it always ends up calling itself with the same argument.
Without understanding the purpose of the function, it's difficult to know what that condition should be.

Factorial function only counts to 12

This factorial function starts giving wrong results with 13 and above. I have no idea why.
#include <stdio.h>
int fatorial (int p);
int main() {
int x = 13;
int test = fatorial(x);
printf("%d", test);
}
int fatorial (int p) {
if (p <= 0)
return 1;
else
return p*fatorial(p-1);
}
for x = 0, 1, 2 ...12 it prints the right result, but for 13! it prints 1932053504 which is not correct.
For x=20 it prints -210213273 for example.
I know that this is not the best way to do a factorial. Its my homework tho, it HAS to be this way.
If you try this you will get the maximum value that int can hold:
#include <stdio.h>
#include <limits.h>
int main(void)
{
printf("%d\n", INT_MAX);
}
Your code causes overflow.
You could get a few more numbers if you use a bigger type, but not by very much. You could use this:
unsigned long long fatorial (unsigned long long p) {
if (p <= 0)
return 1;
else
return p*fatorial(p-1);
}
It won't get you far though. If you want bigger than that you need to find a library for bigger integers or create some custom solution. One such library is https://gmplib.org/ but that is likely out of scope for your homework.
And btw, a condition like p <= 0 is not good. It indicates that the factorial of a negative number is always one, which is false.
It is because after 12, the result of factorial of any number exceeds the size of int.
you can try the following code:
#include<stdio.h>
int main()
{
int a[100],n,counter,temp,i;
a[0]=1;
counter=0;
printf("Enter the number: ");
scanf("%d",&n);
for(; n>=2; n--)
{
temp=0;
for(i=0; i<=counter; i++)
{
temp=(a[i]*n)+temp;
a[i]=temp%10;
temp=temp/10;
}
while(temp>0)
{
a[++counter]=temp%10;
temp=temp/10;
}
}
for(i=counter; i>=0; i--)
printf("%d",a[i]);
return 0;
}
The result of the function is too big. I think big int would work better for your purposes. Big int allows you to have bigger numbers. Also, this is what I would do.
int x = the number you want to factorialize
int ans = 1;
(Then instead of all of those functions)
for(var i = x; i > 0; i--) {
ans = ans*i;
}
System.out.println(ans);
Javascript link: https://jsfiddle.net/8gxyj913/
I need to get to 100!
100! is about 9.332622e+157. Simply using standard integer types is insufficient. 32-bit int is good to 12!. With 64-bit integer math, code could get to about 21!
Could use floating point math and give up precision.
Instead consider a string approach.

Nested function in c?

The aim was to implement a c function, that takes two unsingned int n and m and computes the non-negative result m^n. It also said to ignore possible overlows.
So here is the solution given out by the lecturer:
unsigned int power(unsigned int m, unsigned n) {
int power(int x, int y) {
int result = 1;
while(m > 0) {
result *= n;
--m;
}
return result;
}
While i understand the algorithm itself, i fail to get why he chose to use a nested function. And also why there is a curly bracket missing.
I would have simply written something like this:
unsigned int power(unsigned int m, unsigned n) {
int result = 1;
while(m > 0) {
result *= n;
--m;
}
return result;
}
Could somebody please explain, why he chose the nested one and why that's better?
Looks like the int version was a copy/paste left over error: there are no references to either x or y.
unsigned int power(unsigned int m, unsigned n) {
int power(int x, int y) { /* copy/paste left overs */
int result = 1;
while(m > 0) {
result *= n;
--m;
}
return result;
}
Nested functions are not supported in standard C and there is a extension in GNU C which supports it but is not a standard.
The code what you have written is good and there is a mistake in the code your lecturer has given you.
To know about nested functions you can look here:
https://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html
There is probably a mistake in the solution the lecturer gave you. Your code seems correct.
C language does not support defining functions inside functions. You can however declare a function inside a function.
gcc has an extension that supports nested functions. See this.

how to calculate the sum of successive integers starting at 1 and ending at n by using a recursion function

My function gets a number and returns the sum of the numbers before the input including the input; however, i was wondering if it is possible to calculate the sum of successive integers starting at 1 and ending at n(as input)
#include<stdio.h>
int sum(int x){
if(x>0)return x+sum(x-1);
else return 0;
}
main(){
int x;
scanf("%d",&x);;
printf("%d\n\n",sum(x));
}
I found the answer for my question, but the stackoverflow.com don't let me answer it. So, I'll answer it here:
It is really simple, all it needs is another argument for incrementation and the other one to keep track of the value inputed.
#include<stdio.h>
int sum(int x,int t){
if(t<=x) return t+sum(x,t+1);
else return 0;
}
main(){
int x;
printf("enter int: ");
scanf("%d",&x);
printf("%d\n",sum(x,0));
}
The sum of all the intergers smaller than n, and larger than 0 can be found with
int sum = (n*(n+1))/2
which has much less overhead than a recursive function. But if you really want to then you function looks correct, I'd add some curly braces though:
int sum(int x){
if(x>0) {
return x+sum(x-1);
}
else {
return 0;
}
}
The problem with the above function, is that is uses the stack for for memorisation, so you probably won't be able to calculate large ns. You can make your function tail recursive:
int sum(int x, int sum){
if(x>0) {
return sum(x-1, sum + x);
}
else {
return sum;
}
}
This wont use the stack to memorise your intermediate sums. However a simple loop is probably better, and if you want it to look really cryptic and effective, you can do:
int sum = (n*(++n))>>1

Unable to get a factorial function to work in C

I cannot get the following code to work.
#include <stdio.h>
// I am not sure whethere I should void here or not.
int main() {
// when the first bug is solved, I put here arg[0]. It should be
// similar command line parameter as args[0] in Java.
int a=3;
int b;
b = factorial(a);
// bug seems to be here, since the %1i seems to work only in fprintf
printf("%1i", b);
return 0;
}
int factorial(int x) {
int i;
for(i=1; i<x; i++)
x *= i;
return x;
}
How can you get the code to work?
You're modifying your loop terminating variable (x) inside the loop. Currently your code blows up after a few iterations, when x overflows the range of a 32 bit integer and then becomes negative and very large, hence terminating the loop.
It should be:
int factorial(int n) {
int i, x = 1;
for (i = 2; i <= n; ++i) {
x *= i;
}
return x;
}
Better yet, you should use long instead of int for the variable x and the return value, because n! gets very large very quickly.
AInitak gave the right answer, but I want to add that one way you can find the bug in your code is to print out the values of i and x in the factorial loop.
int factorial(int x) {
int i;
for(i=1; i<x; i++)
{
x *= i;
printf("%d, %d\n", i, x);
}
return x;
}
This gives you the output
1, 3
2, 6
3, 18
4, 72
5, 360
6, 2160
7, 15120
8, 120960
9, 1088640
10, 10886400
11, 119750400
12, 1437004800
13, 1501193216
14, -458131456
-458131456
This makes it easier to see what's going wrong. The loop doesn't stop where you expect it to for the reasons AInitak explained.
It's bad style in C to leave out void when defining or declaring a function. So put it in
int main(void)
While it doesn't change anything about the number of parameters the function has (the function has zero parameters without that void either), it will declare the function as one that accepts only zero arguments, while it won't tell anything about the amount and types of accepted arguments when you omit the void. However, both versions with and without void are correct.
Read this answer about that matter too.
#include<stdio.h>
#include<stdlib.h>
int main(int c,char *v[])
{
int x,y;
int *num;
if(c==1)
{
printf("Usage : programName : number");
return 0;
}
num=(int *)malloc(sizeof(int));
*num=atoi(v[1]);
x=1;y=1;
while(x<=*num)
{
y=y*x;
x++;
}
printf("Factorial of %d is %d ",*num,y);
free(num);
return 0;
}
What error message do you get?
First off, declare your function factorial before main. Also, pay attention to correct indentation. Your declaration of function main is correct, by the way.
I would suggest to use also double or unsigned long for factorial computation in order to be able to compute the greater value of the factorial function.
double fact( double n)
{
if ( n == 1)
return 1;
return n*(fact(n-1));
}
A more elegant non-recursive function.
#include<stdio.h>
long long int fact(long long int);
long long int fact(long long int n){
long long int num = 1;
long long int fi = 0;
for(long long int i=2;i<=n;i++){
for(long long int j=1;j<=i;j++){
fi += num;
}
num = fi;
fi = 0;
}
return num;
}
int main(){
long long int n;
scanf("%lld",&n);
printf("%lld\n",fact(n));
return 0;
}

Resources