C prime factorization (loop failure?) - c

I've been looking into this simple piece of code for 1.5 hrs now and do not find the mistake. I start going crazy ;)
Could anyone of you with a fresh mind and view give me a little hint, where I might have the mistake in? (I am relatively new to C)
The problem is: The code works fine for most of the numbers I entered and tested, but accidentically I found a number that does not work: 3486118 (or 55777888 which is a multiple of it) It goes right for the first loop(s), but after factor 2 it becomes an endless loop.
Here is my code: (any help is greatly appreciated)
// Program calculates prime factors of entered number and returns them
#include <stdio.h>
int main() {
long int num, num_cp;
long int product=1;
/*prime number array up to 100.000*/
long int prime[] = {2, 3, **[...cut out MANY numbers...]** 99971, 99989, 99991};
printf("Please enter a positive integer:\n");
scanf("%li", &num);//55777888 or 3486118 not working... why?
//copy the entered number to keep the original for comparison with "product" and "break;" if equal
num_cp=num;
printf("prime factorization of %li:\n\n", num);
for (int i=0; i<sizeof(prime); i++) {
if (num_cp%prime[i]==0) {
num_cp/=prime[i];
product*=prime[i];
if (product==num) {
printf("%li\n\n", prime[i]);
break;
}
printf("%li*", prime[i]);
//If prime factor found but "product" is still not equal to "num" reset loop counter "i" to -1 (==0 in next loop)
i=-1;
}
}
printf("END");
return 0;
}

"I've been looking into this simple piece of code for 1.5 hrs now and do not find the mistake. I start going crazy ;)"
Don't. Leave it. Go away and eat a pizza. Veg out in front of your favourite movie. Have a shower. Aim for a new high-score on 2048 (or whatever). Your brain gets stuck in a rut and you are no longer seeing your code. You are only seeing what you think your code is.
When you get your brain out of the rut, then -- and only then -- go back and actually read the code you wrote. Not the code you think you wrote, but the code you actually wrote. Yes, they are different.

The prime factors of 55777888 are 2·2·2·2·2·1743059, where the last factor is too large to be contained in your list.
You can fix this in your code: When the product is equal to the product of the prime factors you have found, num_cp is 1. If num_cp is greater than one after you have exhausted your prime list, it is a factor of num. If num/num_cp is smaller than the largest prime you have checked, you can assume that the remaining value of num_cp is a prime. If it wasn't you'd have found more factors earlier.
You can fix this by adding an additional check after your main loop:
if (num_cp > 1) printf("%li\n\n", num_cp);
(If long int is a 64-bit number on your system, you're still not safe: The remaining factor might be made up of several numbers that are not in your array.)
Finally: Resetting the for loop counter so that the loop starts over isn't a good idea. It always starts from the beginning and re-checks primes that you have already checked. And it just isn't natural program flow, which makes it hard to read. A while loop instead of the inner if block would be more natural in my opinion.
Edit: To illustrate:
#include <stdio.h>
int main() {
long int num;
/* prime number array up to 100.000 */
long int prime[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31};
int nprime = sizeof(prime) / sizeof(*prime);
num = 55;
printf("%li == ", num);
for (int i = 0; i < nprime; i++) {
long int p = prime[i];
if (num <= 1) break;
while (num % p == 0) {
num /= prime[i];
printf("%li", p);
if (num > 1) printf(" * ");
}
}
if (num > 1) printf("%li", num);
printf("\n");
return 0;
}
Things to note:
Instead of resetting the main loop counter i, a while loop is used, which consumes all repetitions of the same factor. If a prime p doesn't divide the number, the while loop isn't entered, just like an if clause.
I've removed the copy of num and used num throughout, mainly to remove clutter. I've also removed the product. Your logic that all prime factors should multiply to the original number, is good. But it also works the other way round: After dividing the number by all primes, we are left with 1. And we have to divide the number anyways. By removing the product, we have to keep track of only one variable instead of two.
I've moved the break condition to the front, so we catch negative numbers and 0 early.
That said, your way to code isn't wrong, just maybe a bit unusual in places.

Related

Visual studio code bug

I was a writing a program to invert a 5 digit number in vs code and it goes like this:
// Program to reverse the number
#include <stdio.h>
#include <math.h>
int main()
{
int num, rev_num, a, temp,i;
printf("\nEnter the number to be reveresed: ");
scanf("%d", &num);
a = 0;
for (i = 4; i > (-1); i--)
{
temp = num % 10;
num = (num - temp) / 10;
a = a + temp * pow(10, i);
}
printf("\nThe reverse number is: %d",a);
return 0;
}
One of the input is here:
INPUT PIC
It yielded the output by subtracting 1 from the last digit. Similar is the case with other inputs too.
It yielded the correct output in all the c compilers except vs code. Is there some bug in the vs code or my program is wrong.
You are using a float function for integer purposes.
Getting an off-by-one problem is normal when doing so.
Compare Is floating point math broken?
The dirty details of floats where integers should be used can also easily explain differences between seemingly correct behaviour on one compiler and incorrect results on others.
So, assuming your question is "Is there some bug in the vs code[?] or my program is wrong[?]". I'd say there proabbly is a bug in VSCode (because I simply assume that for any larger program out there...), but not one explaining your observation. The problem is in your code.
In this case it would be easy to keep an increment (*10 instead of +1) number, which goes through values 1, 10, 100, 1000.
The point is to avoid floating points when the input, the output and the logic of the goal is integer.
Most elegantly (by which I mean with least changes to your code) this can be done by calculating a incrementally ("increment" by *10, not by +1). I.e. by multiplying by 10 each loop iteration.
I.e. instead of using pow(), to update a, do:
a = a*10 + temp;
This way, whatever is inside a at the start of the iteration (0 the first time) gets "moved to the left" and the 1-valued digit of the input number, which is found in temp is added.
Because of the way the integer / works you can also simplify the previous line to num = num / 10;, but that line as it is in your code also works fine.
This does not explicitly contain a variable which "increments" 1, 10, 100, it is more that a is going through temporary result values, which are in effect multiplied by 1, 10, 100, ... but the core of the idea is there and I think the minimal change to your code is an advantage of this solution.

why my answer is only partially accepted in a hackerearth practice problem

Problem:
You are provided an array A of size N that contains non-negative integers. Your task is to determine whether the number that is formed by selecting the last digit of all the N numbers is divisible by 10.
Note: View the sample explanation section for more clarification.
Input format
First line: A single integer N denoting the size of array Ai.
Second line: N space-separated integers.
Output format:
If the number is divisible by 10 , then print Yes . Otherwise, print No.
Constraints:
1<=N<=100000
0<=A[i]<=100000
i have used int, long int ,long long int as well for declaring N and 'm'.But the answer was again partially accepted.
#include <stdio.h>
int main() {
long long int N,m,i;
scanf("%ld", &N);
long data[N];
for(auto i=0; i<N; i++) {
scanf("%ld", &data[i]);
}
// write your code here
// ans =
m=(data[0]%10);
for(i=1; i<N; i++) {
m=m*10;
m=(data[i]%10)+m;
}
if(m%10!=0 && m==0) {
printf("Yes");}
else{
printf("No");
}
return 0;
}
Try making a test suite, that is, several tests for which you know the answer. Run your program on each of the tests; compare the result with the correct answer.
When making your tests, try to hit also corner cases. What do I mean by corner cases? You have them in your problem statement:
1<=N<=100000
0<=A[i]<=100000
You should have at least one test with minimal and maximal N - you should test whether your program works for these extremes.
You should also have at least one test with minimal and maximal A[i].
Since each of them can be different, try varying them - make sure your program works on the case where some of the A[i] are large and some are small.
For each category, include tests for which the answer is Yes and No - to exclude the case where your algorithm always outputs e.g. Yes by mistake.
In general, you should try to make tests which challenge your program - try to prove that it has a bug, even if you believe it's correct.
This code overflows:
m=(data[0]%10);
for(i=1; i<N; i++) {
m=m*10;
m=(data[i]%10)+m;
}
For example, when N is 1000, and each of the input items A[i] (scanned into data[i]) ends in 9, this attempts to compute m = 99999…99999, which grossly overflows the capability of the long long m.
To determine whether the numeral formed by concatenating a sequence of digits is divisible by ten, you merely need to know whether the last digit is zero. The number is divisible by ten iff data[N-1] % 10 == 0. You do not even need to store these numbers in an array; simply use scanf to read but ignore N−1 numerals (e.g., scanf("%*d")), then read the last one and examine its last digit.
Also scanf("%ld", &N); wrongly uses %ld for the long long int N. It should be %lld, or N should be long int.
An integer number given in decimal is divisible by ten if, and only if, its least significant digit is zero.
If this expression from your problem:
the number that is formed by selecting the last digit of all the N numbers
means:
a number, whose decimal representation comes from concatenating the least significant digits of all input numbers
then the last (the least significant) digit of your number is the last digit of the last input number. And that digit being zero is equivalent to that last number being divisible by 10.
So all you need to do is read and ignore all input data except the last number, then test the last number for divisibility by 10:
#include <stdio.h>
int main() {
long N, i, data;
scanf("%ld", &N);
for(i=0; i<N; i++)
scanf("%ld", &data); // scan all input data
// the last input number remains in data
if(data % 10 == 0) // test the last number
printf("Yes");
else
printf("No");
return 0;
}

Finding Largest Twin Prime

I am trying to create a c program which prompts for user input and then, finds the largest twin prime within that number. This program then loops continuously, prompting the user for an input again and again and finding the largest twin prime until the user enters -1, after which it terminates. I wrote down the basic code, but have yet been able to make it loop continuously when using certain numbers such as 20 and 65. I cannot figure out what is wrong with my code.
I seem to be having another problem as well. For 20, the values show (15,17) instead of (17,19). Obviously the logic is wrong somewhere but I am not sure exactly where either.
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include<conio.h>
int prime(int x)
{
int i,numroot;
numroot=sqrt(x);
for(i=2;i<=numroot;i++)
if(x%i==0){
return(0);
}
return(1);
}
int main()
{
double N;
printf("This program prints out all the possible twin primes until a specific number which...\nyou can choose!");
printf("\nA note of caution: Although this program accepts decimals, the value entered must be between 5 and 10^9,inclusive of the 2 numbers.");
printf("\nKey in -1 to exit.");
printf("\nEnter N value upto which twin primes ought to be calculated until: ");
scanf("%lf",&N);
while (N!=-1) {
if (N<5 || N>pow(10,9)) {
printf("\nNumber not in the valid range was inputted. \nPlease reenter the value: ");
scanf("%lf",&N);
}
else {
int n;
n=floor(N);
int prime(int x);
int f,originalval;
originalval=N;
f=prime(n);
while(f==0){//Calculates for largest prime number below user input
n--;
f=prime(n);
}
int smallint=n-2;
while(prime(smallint)==1){
n--;
f=prime(n);
while(f==0){
n--;
f=prime(n);
}
int smallint=n-2;
}
printf("The largest twin prime pair not above %d is (%d,%d)",originalval,smallint,n);
printf("\nPlease re-enter the value:");
scanf("%lf",&N);
}
}
printf("\nProgram successfully terminated.");
return 0;
}
You are doing a research about prime numbers "upto" a given number N.
In this class of problems is more efficient (although more expensive in RAM space) to store information in tables of primes and composite numbers, like the Sieve of Eratosthenes.
Once you have filled the table with the information of which numbers are prime and composite, it's just a matter of iterate on the table to look for the twin primes, wherever they are.
However, although you inform to the user that all the twin primes will be shown, actually what your program does is trying to show only the lastest.
Please, have clear which is the goal of your program.
On the other hand, you are redefining the identifier smallint inside the innest loop, which is, for sure, a logical error.
In case you cannot use arrays to store the Sieve of Eratosthenes, then I show you here a method that is not hard to implement (but it's not, of course, the most efficient; however it will avoid a lot of redundant computations).
The twin primes (greater than 4) can be of two different forms:
6k-1, 6k+1
6k+1, 6k+5
So, I would jump in the sequence of numbers having the form 6k+1, 6k+5, for k = 0, 1, 2, 3, ..., so that I only would analyze the odd numbers in the sequence:
5, 7, 11, 13, 17, 19, 23, 25, 29, 31, 35, 37, 41, 43, 47, 49, ...
This can be obtained by adding 2, then 4, then 2, then 4, then 2, then 4...
So, one can take the first pair, let's say 5 and 7.
We divide both of them by the odd numbers of the form 6k+1 and 6k+5 less than the square root of the greatest of them (sqrt(7)).
If the less number (in this case 5) would be divisible by some number, we pick the following number in the list, which is 11, and divide it by all the numbers that were used so far to test if 7 is prime or not. From this point, we follow by dividing together, 7 and 11, by the remaining numbers up to sqrt(11), and so on.
Note that, for big numbers, 6k+1 and 6k+5 have very similar square roots.
If the opposite case happens, that is, that for the pair (5, 7), the biggest element of the couple (in this case: 7) is divisible by some other number, then we discard both of them (5 and 7) and pick the following two elementos of the list (in this example would be 11 and 13). So, we start the search from scratch (that is, by dividing by small numbers).
finally, if the loop ends without finding divisors for any element of the couple (which is indeed the case for 6 and 7), then we can inform that this couple is of twin primes.
(Or well we can keep silent).
Then, we discard the smallest element (in this case: 5) and retain the biggest element (in this case: 7).
Since we already know that 7 is prime, we only pick the following element of the list above (in this case, 11), and search for divisors of it, only.
I think that the method I have explained will avoid to you a lot of redundant computations.
Besides, it's necessary to keep the latest updated couple of twin primes found. I assume that is not necessary that I explain to you how to do that.
We should procure that both of numbers are prime. Between difference is 2. As you know first twin prime is (3,5). I haven't found a formula what I expected. So, I've used iteration for solution. If you look through the code, you can understand.
#include <stdio.h>
#include <math.h>
int twinPrime(int m);
int IsPrime(unsigned int number);
int main()
{
double N;
int floored;
int prime;
printf("This program prints out all the possible twin primes"
"until a specific number which...\nyou can choose!");
printf("\nA note of caution: Although this program accepts decimals, "
"the value entered must be between 5 and 10^9,inclusive of the 2 numbers.");
printf("\nKey in -1 to exit.");
printf("\nEnter N value upto which twin primes ought to be calculated until: ");
scanf("%lf",&N);
while (N != -1)
{
if (N < 5 || N > pow(10,9))
{
printf("\nNumber not in the valid range was inputted. \n"
"Please reenter the value: ");
scanf("%lf",&N);
}
else
{
floored = floor(N);
prime = twinPrime(floored);
printf("The largest twin prime pair not above %d is (%d,%d)",floored,prime - 2,prime);
printf("\nPlease re-enter the value:");
scanf("%lf",&N);
}
}
printf("\nProgram successfully terminated.");
return 0;
}
int twinPrime(int m)
{
int p = 3;
int q = 5;
for (; q < m - 1; q += 2)
{
if (IsPrime(q))
{
if (q - p == 2)
{
continue;
}
p = q;
}
}
return q;
}
int IsPrime(unsigned int number)
{
if (number <= 1) return 0; // zero and one are not prime
if ((number > 2) && ((number % 2) == 0)) return 0; //no even number is prime number (bar 2)
unsigned int i;
for (i=2; i*i<=number; i++)
{
if (number % i == 0) return 0;
}
return 1;
}

C program stops responding for large inputs

I am (re-)learning C and in the book I am following we are covering arrays, and the book gives an algorithm for finding the first n primes; myself being a mathematician and a decently skilled programmer in a few languages I decided to use a different algorithm (using the sieve of Eratosthenes) to get the first n primes. Well making the algorithm went well, what I have works, and even for moderately large inputs, i.e. the first 50,000 primes take a bit to run as you would expect, but no issues. However when you get to say 80,000 primes pretty much as soon as it begins a window pops up saying the program is not responding and will need to quit, I made sure to make the variables that take on the primes were unsigned long long int, so I should still be in the acceptable range for their values. I did some cursory browsing online and other people that had issues with large inputs received the recommendation to create the variables outside of main, to make them global variables. I tried this for some of the variables that I could immediately put outside, but that didn't fix the issue. Possibly I need to put my arrays isPrime or primes outside of main as well? But I couldn't really see how to do that since all of my work is in main.
I realize I should have done this with separate functions, but I was just writing it as I went, but if I moved everything into separate functions, my arrays still wouldn't be global, so I wasn't sure how to fix this issue.
I tried making them either static or extern, to try and get them out of the stack memory, but naturally that didn't work since they arrays change size depending on input, and change over time.
the code is:
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
unsigned long long int i,j;
unsigned long long int numPrimes,numPlaces;
int main(void)
{
bool DEBUG=false;
printf("How many primes would you like to generate? ");
scanf("%llu",&numPrimes);
// the nth prime is bounded by n*ln(n)+n*ln(ln(n)), for n >=6
// so we need to check that far out for the nth prime
if (numPrimes>= 6)
numPlaces = (int) numPrimes*log(numPrimes)+
numPrimes*log(log(numPrimes));
else
numPlaces = numPrimes*numPrimes;
if(DEBUG)
printf("numPlaces: %llu\n\n", numPlaces);
// we will need to check each of these for being prime
// add one so that we can just ignore starting at 0
bool isPrime[numPlaces+1];
// only need numPrimes places, since that is all we are looking for
// but numbers can and will get large
unsigned long long int primes[numPrimes];
for (i=2; i<numPlaces+1;i++)
isPrime[i] = true; // everything is prime until it isn't
i=2; // represents current prime
while (i < numPlaces + 1)
{
for (j=i+1;j<numPlaces+1;j++)
{
if (isPrime[j] && j%i ==0) // only need to check if we haven't already
{
isPrime[j] = false;// j is divisibly by i, so not prime
if(DEBUG)
{
printf("j that is not prime: %llu\n",j);
printf("i that eliminated it: %llu\n\n",i);
}//DEBUG if
}//if
}//for
// ruled out everything that was divisible by i, need to choose
// the next i now.
for (j=i+1;j<numPlaces+2;j++)// here j is just a counter
{
if (j == numPlaces +1)// this is to break out of while
{
i = j;
break;
}// if j = numPlaces+1 then we are done
else if (isPrime[j]==true)
{
i = j;
if (DEBUG)
{
printf("next prime: %llu\n\n",i);
}//DEBUG if
break;
}//else if
}// for to decide i
}//while
// now we have which are prime and which are not, now to just get
// the first numPrimes of them.
primes[0]=2;
for (i=1;i<numPrimes;i++)// i is now a counter
{
// need to determine what the ith prime is, i.e. the ith true
// entry in isPrime, 2 is taken care of
// first we determine the starting value for j
// the idea here is we only need to check odd numbers of being
// prime after two, so I don't need to check everything
if (i<3)
j=3;
else if (i % 2 ==0)
j = i+1;
else
j = i;
for (;j<numPlaces+1;j+=2)// only need to consider odd nums
{
// check for primality, but we don't care if we already knew
// it was prime
if (isPrime[j] && j>primes[i-1])
{
primes[i]=j;
break;
}//if, determined the ith prime
}//for to find the ith prime
}//for to fill in primes
// at this point we have all the primes in 'primes' and now we just
// need to print them
printf(" n\t\t prime\n");
printf("___\t\t_______\n");
for(i=0;i<numPrimes;i++)
{
printf("%llu\t\t%llu\n",i+1,primes[i]);
}//for
return 0;
}//main
I suppose I could just avoid the primes array and just use the index of isPrime, if that would help? Any ideas would help thanks!
Your problem is here, in the definition of the VLA ("Variable Length Array", not "Very Large Array")
bool isPrime[numPlaces+1];
The program does not have enough space in the area for local variables for the array isPrime when numPlaces is large.
You have two options:
declare the array with a "big enough" size outside of the main function and ignore the extra space
use another area for storing the array with malloc() and friends
option 1
#include <stdio.h>
unsigned long long int i,j;
bool isPrime[5000000]; /* waste memory */
int main(void)
option 2
int main(void)
{
bool *isPrime;
// ...
printf("How many primes would you like to generate? ");
scanf("%llu",&numPrimes);
// ...
// we will need to check each of these for being prime
// add one so that we can just ignore starting at 0
isPrime = malloc(numPrimes * sizeof *isPrime);
// ... use the pointer exactly as if it was an array
// ... with the same syntax as you already have
free(isPrime);
return 0;
}
The array you allocate is a stack variable (by all likelihood), and stack size is limited, so you are probably overwriting something important as soon as you hit a certain size threshold, causing the program to crash. Try using a dynamic array, allocated with malloc, to store the sieve.

Sorting integers based on their prime factors

I am kind of stuck how to sort integers based on their greatest prime factor in ascending order. For example, we have 3 and 8. The order should be: 8, 3 because 8's prime factor (2) is less than 3's prime factor (3). If we have the same greatest prime factor for 2 numbers like 9 and 27, then the smaller number should be first. In this order: 9, 27
Okay, here's my code, but it needs some modification.
long long sort(long long integers[], long long primes[]) {
/* loop variables */
int i, j;
/* temporary variable */
long long tmp;
for (i = (SIZE - 1); i > 0; i--) {
for (j = 1; j <= i; j++) {
if (integers[j-1] > integers[j]) {
tmp = integers[j-1];
integers[j-1] = integers[j];
integers[j] = tmp;
}
}
}
}
It is also important to mention that integers[i]'s greatest prime factor is stored as primes[i]. Primes are already all set up and good, this thing only needs correct sorting.
I hope you can help me.
Thanks. :)
Surely you just need to use primes somewhere. In your current code you aren't using that variable at all, and it seems rather clear where it should go.
Bonus tip: look up the standard C library function qsort.

Resources