-4
\$\begingroup\$

My solution runs properly and I have tested it against various test cases. Is this the best approach?

#include<stdio.h> #include<math.h> int primefactors(int); int main() { int num; printf("Enter a no:-\n"); scanf("%d",&num); printf("%d",primefactors(num)); return 0; } int primefactors(int n){ for(int i=2; i<=sqrt(n);i++){ while(n%i==0){ printf("%d ", i); return primefactors(n/i); } } if(n>2) return(n); } 
\$\endgroup\$
1
  • 5
    \$\begingroup\$ Welcome to CodeReview@SE. runs properly and I have tested it against various test cases (there indentation at the end of primefactors() is inconsistent) please add the required behaviour to the question - primefactors()' return value looks undefined for many values of n. What is the required output for, say, 126? Consider adding the test code to the question, making it unmistakable when wanting it excluded from review. \$\endgroup\$ Commented Sep 20, 2020 at 10:48

4 Answers 4

4
\$\begingroup\$

Does your compiler not complain? If not, might want to turn warnings on. I just tried at repl.it and it rightly warns about control may reach end of non-void function. It still ran, but when I entered 2, I got the output 32690. And for 8, I got 2 2 0. So no, it doesn't run properly.

An unconditional return in a while loop doesn't make sense. I guess you meant if?

Let's say you found a large prime factor. The recursive call restarts the search at 2. Not efficient. You already know that none of the primes smaller than that large one divide the remaining n.

\$\endgroup\$
3
\$\begingroup\$

I'm going to address the coding, asking if an algorithm is a best approach is somewhat opinion based and to be avoided.

Avoid using abbreviations such as no. in prompts, it is better to use real words.

Iterative approaches may be better than recursive approaches because they use less resources (less memory for instance on the stack).

There is no reason to have a function prototype for the function primefactors if you swap the order of the functions primefactors() and main(). In C it is very common for the last function in a file to be main().

The indentation of the last } is problematic and should be corrected.

Leave horizontal space between operators such as , and & in all statements. that makes the code much more readable and easier to maintain. Examples:

 scanf("%d", &num); printf("%d", primefactors(num)); 

and

 for(int i=2; i <= sqrt(n); i++){ while(n % i == 0){ printf("%d ", i); return primefactors(n / i); } } if(n > 2) return(n); 

Leave vertical spacing between functions and sometimes separating logical blocks of code.

#include<stdio.h> #include<math.h> int primefactors(int n){ for(int i = 2; i <= sqrt(n); i++){ while(n % i == 0){ printf("%d ", i); return primefactors(n / i); } } if(n > 2) return(n); } int main() { int num; printf("Enter a no:-\n"); scanf("%d", &num); printf("%d", primefactors(num)); return 0; } 

Update with testing:

I have altered the code in the following way to get the prime factors for 2 through 100, the code fails on any power of 2, returning an unknown value for the final power of 2. It works properly in all other cases. This is approximately a 7% failure rate, an edge case fails.

#include<stdio.h> #include<math.h> int primefactors(int n) { for (int i = 2; i <= sqrt(n); i++) { while (n % i == 0) { printf(" %d ", i); return primefactors(n / i); } } if (n > 2) return(n); } int main() { for (int i = 2; i <= 100; i++) { printf("primefactors(%d) = ", i); printf("%d ", primefactors(i)); printf("\n"); } return 0; } 
\$\endgroup\$
5
  • \$\begingroup\$ With regard to iterative vs recursive, does C have a 'stack limit' where an artificial limitation is implemented. For example the stack in Python can't have a depth of more than 1000. (this can be adjusted but is ill advised) \$\endgroup\$ Commented Sep 20, 2020 at 15:17
  • \$\begingroup\$ @Peilonrayz Not that I know of, but that could depend on the implementation in the C library or the hardware. \$\endgroup\$ Commented Sep 20, 2020 at 15:23
  • 2
    \$\begingroup\$ @Peilonrayz Both Windows and Linux impose a stack size limit. You can configure the stack size in MSVC during compilation. On linux, calling getrlimit with RLIMIT_STACK will give you the current setting, which you can configure just like any other resource limit. I am not familiar with other systems well enough to comment on them. \$\endgroup\$ Commented Sep 26, 2020 at 13:34
  • \$\begingroup\$ @JoseFernandoLopezFernandez Thank you for the answer. I'm on Linux at the moment and noticed Python has a getrlimit bind and RLIMIT_STACK flag which, obviously, work. Cool, thanks for the info! \$\endgroup\$ Commented Sep 26, 2020 at 13:43
  • \$\begingroup\$ @Peilonrayz You're welcome, glad to help \$\endgroup\$ Commented Sep 26, 2020 at 17:04
1
\$\begingroup\$

"My solution runs properly", but not for all int

  • primefactors(n_less_than_2) does not return anything. This hints that not all warnings were enabled. Save time and enable all compiler warnings.

  • With primefactors(some_negative_value), code attempts the sqrt() of a negative leading to math woes.

  • sqrt(some_perfect_square) is likely to form the exact correct square root, yet weak libraries exist and will instead return value just a little less, breaking the algorithm. Best to avoid floating point math for an integer problem.

  • Should int unusually have more precision than double, then i<=sqrt(n) will not always form the correct test limit.

  • Use i <= n/i instead. As it has a nearby n%i, a good compiler will likely form both the quotient and remainder for the time cost of one.


Incorporating the above fixes:

int primefactors(int n) { for (int i = 2; i <= n/i; i++) { while(n%i == 0){ printf("%d ", i); return primefactors(n/i); } } if (n>2) { return n; } return 1; // Unclear what OP really wants here. } 
\$\endgroup\$
1
\$\begingroup\$

Never ignore the return value from scanf():

scanf("%d",&num); printf("%d",primefactors(num)); 

Here, we have no idea whether num was assigned or not, so passing it to primefactors() is a bad idea.

Suggested replacement:

if (scanf("%d", &num) != 1) { puts("Input was not a valid integer\n", stderr); return EXIT_FAILURE; } printf("%d\n", primefactors(num)); 

(I also modified the printf() call to produce a complete line of output).

Having said that, it seems inappropriate to be reading from standard input at all - why not simply pass numbers as command-line arguments? Like this:

#include <limits.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char*argv[]) { if (argc < 2) { fprintf(stderr, "Usage: %s NUMBER...\n", argv[0]); return EXIT_FAILURE; } while (*++argv) { char *end; long n = strtol(*argv, &end, 0); if (end == *argv || *end != '\0') { fprintf(stderr, "%s is not a valid number!\n", *argv); return EXIT_FAILURE; } if (n < INT_MIN || n > INT_MAX) { /* Why are we using signed numbers anyway? */ fprintf(stderr, "%s is outside the accepted range!\n", *argv); return EXIT_FAILURE; } printf("%d\n", primefactors((int)n)); } return EXIT_SUCCESS; /* optional for main() */ } 
\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.