How to improve execution time when calculating prime factors - c

I have to make a program to find the largest way to show a n! number (excluding the 1).
for example: 4! = 1x2x3x4 = 1x2x3x2x2. so you can use the product of 5 numbers to show the 4!.
so the imput is 4 and the output is 5.
5 is the max amount of numbers with which you can express the 4!.
In simple words is factorize a factorial number in prime factors, count how many they are and show it.
What I did was a 'for' cycle where I count all the prime factors of 1 to 'n' and amount of them.
But I have a problem with big numbers like when 'n' is 100000, it takes 8 seconds to complete. I need to improve the speed.
I think the problem is in the factorization function.
int factors( int fact )
{
int i,cont,product=1, control;
cont=0;
control=fact;
for (i= 2;control != product;)
{
if ((fact%i == 0))
{
cont++;
fact/=i;
product*=i;}
else
i++;
}
return cont;
}
I need to improve it to get a best execution time. Or maybe the method that i'm using to get the prime factors from a factorial number isn't a good option?
NOTE: I do not calculate the value of 100000!. I just factorize all the numbers from 1 to 10000 and count them.

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
int *prime;
int prime_n;
void make_prime_table(int n){
prime = malloc(sizeof(int) * n / 2);
prime_n =0;
prime[prime_n++] = 2;
prime[prime_n++] = 3;
int i, j;
for(i = 5; i <= n; i +=2){
bool is_prime = true;
for(j = 1; j < prime_n ; ++j){
int t = prime[j];
if(t * t > i)
break;
if(i % t == 0){
is_prime = false;
break;
}
}
if(is_prime)
prime[prime_n++] = i;
}
}
int factors(int fact_n ){
int i, c, p, sum=0;
for(i = 0; i < prime_n ; ++i){
c = fact_n;//number of prime in N : (x1 = N / P) + (x2 = x1 / P) + ...
while(c = c / prime[i]){
sum += c;
}
}
return sum;
}
int main(void){
int n = 100000;
make_prime_table(n);
int ans = factors(n);
printf("ans = %d\n", ans);
free(prime);
return 0;
}
number of prime P in N! :
case of 2 in 10!
1 2 3 4 5 6 7 8 9 10
* * * * * # There are 5 number that is divided by 2. 5 = 10 / 2
* * # Number that can be divided further part of the mark of `*`(5/2).
* # The number of total is the number of `*`.
*search "theorem of Legendre"

Related

Euler Project 4: Finding the largest palindrome product

So, I've wrote several function prototypes for finding the largest palindrome products. The idea is that put the original number into an array in reverse order then convert the array into a number as reverse number. Then compare the reverse number with original number to see if these two numbers are equal or not. However, I am stuck at implementing these functions prototypes in main method. If yes, then it is a palindrome product/ Any suggestions? Please, have mercy I am new to C
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
// Taking a number and reverse it. Put it in reverse order into an array. Then, convert all elements in the array into an array again
//Ex: Original number = 6542
//Input: "6542" -> arr[4] = {2,4,5,6} -> Output: "2456"
//Original Number = 6542; Reverse Number = 2456
//Original Number != Reverse Number -> The number is not palindrome. Palindrome Number Example: 456654, 1, 2332.
int convert_reverse_num (int original_num, int digits_count){
int arr_size = digits_count;
int x = original_num;
int final_reverse_num = 0;
int *arr;
arr = (int*)malloc (arr_size * sizeof(int));
//convert the number into arr array by placing the first index with the last trailing digit on the right
for (int i = 0; i < arr_size; i++){
arr[i] = x % 10;
x /= 10;
}
//Adding all values in the array into a number
//starting from the first index of the array which has the value of the last digit of the number
for (int i = 0; i < arr_size; i++){
final_reverse_num *= 10;
final_reverse_num += arr[i];
}
free(arr);
return final_reverse_num;
}
//Check the number is palindrome or not by comparing the original num and reverse num
bool is_palindrome(int original_num, int reverse_num){
int x = original_num;
int y = reverse_num;
if(x == y)
return 1;
else
return 0;
}
//Count number of digits in a number in order to declare the buffer size
int count_digit_num(int product_digits){
int y = product_digits;
int digits_count = 0;
while(y!=0){
y /= 10;
++digits_count;
}return digits_count;
}
//Find all possible products from two ndigits(2 digits, 3 digits, 4 digits) number
// Examples: 1 digits: 1*2. 2 digits: 12*13. 3 digits: 100 * 999
int find_largest_palindrome(int ndigits){
int min = 1;
int max;
int smallest_num;
int largest_num = 0;
int product = 0;
//Finding the minima. 1 digit = 1; 2 digits = 10; 3 digits = 100
smallest_num = min * pow(10, ndigits-1);
//Finding the maxima. 1 digits = 9; 2 digits = 99; 3 digits = 999
for (int i = 0; i < ndigits; i++){
max = 9 * pow(10, i);
largest_num += max;
}
//All possible products from minima and maxima
for (int x = largest_num; x >= smallest_num; x--){
for (int y = largest_num; y >= smallest_num; y--){
product = x * y;
}
}
return product;
}
int main(){
return 0;
}

Program to print sum of primes in C

#include <stdio.h>
#include <math.h>
int main() {
int n, count, sum;
printf("Enter upper bound n \n");
scanf("%d", &n);
for (int a = 1; a <= n; a++) {
count = 0;
sum = 0;
for (int i = 2; i <= sqrt(a); ++i) {
if (a % i == 0) {
count++;
break;
}
}
if (count == 0 && a != 1) {
sum = a + sum;
}
}
printf("%d", sum);
}
The program is my attempt to print summation of primes < n. I am getting sum = 0 every time and I am unable to fix this issue.
The reason you do not get the sum of primes is you reset the value of sum to 0 at the beginning of each iteration. sum will be 0 or the value of the n if n happens to be prime.
Note also that you should not use floating point functions in integer computations: i <= sqrt(a) should be changed to i * i <= a.
The test on a != 1 can be removed if you start the loop at a = 2.
Here is a modified version:
#include <stdio.h>
int main() {
int n = 0, sum = 0;
printf("Enter upper bound n: \n");
scanf("%d", &n);
// special case 2
if (n >= 2) {
sum += 2;
}
// only test odd numbers and divisors
for (int a = 3; a <= n; a += 2) {
sum += a;
for (int i = 3; i * i <= a; i += 2) {
if (a % i == 0) {
sum -= a;
break;
}
}
}
printf("%d\n", sum);
return 0;
}
For large values of n, a much more efficient approach would use an array and perform a Sieve of Eratosthenes, a remarkable greek polymath, chief librarian of the Library of Alexandria who was the first to compute the circumference of the earth, 2300 years ago.
Here is an improved version:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int n = 0;
long long sum = 0;
if (argc > 1) {
sscanf(argv[1], "%i", &n);
} else {
printf("Enter upper bound n: \n");
scanf("%i", &n);
}
// special case 2
if (n >= 2) {
sum += 2;
}
unsigned char *p = calloc(n, 1);
for (int a = 3; a * a <= n; a += 2) {
for (int b = a * a; b < n; b += a + a) {
p[b] = 1;
}
}
for (int b = 3; b < n; b += 2) {
sum += p[b] * b;
}
free(p);
printf("%lld\n", sum);
return 0;
}
Error about sum getting set to zero inside the loop has been already pointed out in previous answers
In current form also, your code will not return zero always. It will return zero if value of upper bound is given as non prime number. If prime number is given as upper bound, it will return that number itself as sum.
As mentioned in comment you should initialize sum before first loop something like
int n, count, sum=0;
or you can initialize sum in the loop like
for(a=1,sum=0;a <= n; a++)
and remove sum=0; inside the first loop because it changes sum to 0 every time first loop executes. You can check this by inserting this lines to your code
printf("Before sum %d",sum);
sum = 0;
printf("After Sum %d",sum);
make sure sure that if you are initializing sum in the loop, define "a" in outer of the loop if not the sum goes to local variable to for loop and it hides the outer sum.

for loop unexpectedly jumping down in value

Goldbach's conjecture states that every even integer over 4 is the sum of two primes, I am writing a program in C to find these pairs. To do this it first finds all the primes less than a user given number. I have a for loop to iterate from 4 to the user given number and find the pairs within the loop body. When that loop gets to about around 40, suddenly jumps back down by about 30 and then continues to iterate up (with user input 50 it jumped from 38 to 9, with input 60 it jumped from 42 to 7). I can't figure out why this is happening. Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/types.h>
#include <unistd.h>
struct pair{
int a;
int b;
}pair_t;
int main(){
int N;
int numPrimes = 1;
int *primes = malloc(100*sizeof(int));
int isPrime = 1;
primes[0] = 2;
int timesRealloc = 0;
int availableSlots = 100;
printf("Please enter the largest even number you want to find the Goldbach pair for: \n");
scanf("%d", &N);
struct pair pairs[N/2 + 4];
int j = 0;
int i;
for (i = 3; i <= N; i+=2){
j = 0;
isPrime = 1;
while (primes[j] <= sqrt(i)) {
if (i%primes[j] == 0) {
isPrime = 0;
break;
}
j++;
}
if (isPrime == 1){
primes[numPrimes] = i;
numPrimes++;
}
if (availableSlots == numPrimes){
timesRealloc++;
availableSlots += 100;
primes = realloc(primes, availableSlots*sizeof(int));
}
}
printf("The largest prime I found was %d\n", primes[(numPrimes-1)]);
int k;
for (i=4; i<=N; i+=2){
printf("i is %d, N is %d\n", i, N);
if (i > N){ break; }
for (j=0; j<numPrimes; j++){
for (k=0; k<numPrimes; k++){
int sum = primes[j] + primes[k];
if(sum == i){
pairs[i].a = primes[j];
pairs[i].b = primes[k];
}
}
}
}
for (i=4; i<=N; i+=2){
printf("%d is the sum of %d and %d\n", i, pairs[i].a, pairs[i].b);
}
return 0;
}
You attempt to be space efficient by compressing the pairs array to just hold every other (even) number and start from 4 instead of zero. However, you miscalculate its size and then when you go to use it, you treat it like it hasn't been compressed and that there's a slot for every natural number.
The code suffers from having the prime array calculation in main() along with the other code, this is best separated out. And when it looks for pairs, it doesn't quit when it finds one, nor when it starts getting sums greater than the target. My rework below attempts to address all of these issues:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdbool.h>
#define INITIAL_SLOTS (100)
struct pair {
int a;
int b;
} pair_t;
int compute_primes(int limit, unsigned **primes, int size) {
int numPrimes = 0;
(*primes)[numPrimes++] = 2;
for (int i = 3; i <= limit; i += 2) {
bool isPrime = true;
for (int j = 0; (*primes)[j] <= i / (*primes)[j]; j++) {
if (i % (*primes)[j] == 0) {
isPrime = false;
break;
}
}
if (isPrime) {
(*primes)[numPrimes++] = i;
}
if (numPrimes == size) {
size *= 2;
*primes = realloc(*primes, size * sizeof(unsigned));
}
}
return numPrimes;
}
int main() {
int N;
printf("Please enter the largest even number you want to find the Goldbach pair for: \n");
scanf("%d", &N);
unsigned *primes = calloc(INITIAL_SLOTS, sizeof(unsigned));
int numPrimes = compute_primes(N, &primes, INITIAL_SLOTS);
printf("The largest prime I found was %d\n", primes[numPrimes - 1]);
struct pair pairs[(N - 4) / 2 + 1]; // compressed data structure
for (int i = 4; i <= N; i += 2) {
int offset = (i - 4) / 2; // compressed index
bool found = false;
for (int j = 0; ! found && j < numPrimes; j++) {
for (int k = 0; ! found && k < numPrimes; k++) {
int sum = primes[j] + primes[k];
if (sum == i) {
pairs[offset].a = primes[j];
pairs[offset].b = primes[k];
found = true;
} else if (sum > i) {
break;
}
}
}
}
for (int i = 4; i <= N; i += 2) {
int offset = (i - 4) / 2; // compressed index
printf("%d is the sum of %d and %d\n", i, pairs[offset].a, pairs[offset].b);
}
free(primes);
return 0;
}
OUTPUT
> ./a.out
Please enter the largest even number you want to find the Goldbach pair for:
10000
The largest prime I found was 9973
4 is the sum of 2 and 2
6 is the sum of 3 and 3
8 is the sum of 3 and 5
10 is the sum of 3 and 7
12 is the sum of 5 and 7
14 is the sum of 3 and 11
...
9990 is the sum of 17 and 9973
9992 is the sum of 19 and 9973
9994 is the sum of 53 and 9941
9996 is the sum of 23 and 9973
9998 is the sum of 31 and 9967
10000 is the sum of 59 and 9941
>

how can I make this programme faster? [duplicate]

This question already has answers here:
Algorithm to find all the exact divisors of a given integer
(7 answers)
Closed 5 years ago.
The assignment was to write a program which reads in an integer k, and prints out the number of positive integers
between 1 and 100000 (inclusive) which have exactly k divisors. As an example, the number 24 has 8 divisors:
1, 2, 3, 4, 6, 8, 12, and 24.
I have a running programme, but is there anyway i could make the search faster??
#include <stdio.h>
#include <math.h>
int main(void)
{ int a; //user input//
int divisors; //running total of number of divisors//
int sum; //running total of numbers with the required number of divisors//
printf("Enter the target number of divisors:");
scanf("%d", &a);
printf("\n");
int i;
for (i=1; i<=100000; i++)
{
divisors=2;
int p;
for(p=2; p<i; p++)
{if (i%p==0)
divisors++;}
if (divisors==a)
sum++;}
printf("There are %d numbers between 1 and 100000 inclusive which have exactly %d divisors.", sum, a);
return 0;
}
Example code. Moved declarations for i and p to be compatible with old C type compilers (I'm using Microsoft / Visual Studio). Uses ceil(sqrt(i)) outer loops. The code handles an input of 1 (only the number 1 has 1 divisor). An input of 2 will output the number of prime numbers less than 100,000 (there are 9592 prime numbers less than 100,000).
This method takes a bit over 21 million iterations. Number of iterations ~= .67 n sqrt(n).
#include <stdio.h>
int main(void)
{
int a; /* user input */
int divisors; /* total number of divisors */
int sum; /* count of numbers with required number of divisors */
int i; /* moved here for C compiler */
int p; /* moved here for C compiler */
int sqrti; /* ceil(sqrt(i)) */
printf("Enter the target number of divisors: ");
scanf("%d", &a);
printf("\n");
sum = 0; /* init sum */
sqrti = 1; /* init sqrti */
for (i = 1; i <= 100000; i++)
{
divisors = 0; /* init number of divisors */
if(sqrti*sqrti < i) /* update sqrti as needed */
sqrti += 1;
for(p = 1; p < sqrti; p++)
if(i%p == 0) /* if p is a divisor, count it and i/p */
divisors += 2;
if(p*p == i) /* if p*p == i, count it */
divisors += 1;
if (divisors == a) /* if i has a divisors, increment sum */
sum += 1;
}
printf("There are %d numbers from 1 to 100000 inclusive which have exactly %d divisors.\n", sum, a);
return 0;
}
If an array can be used similar to sieve method for primes, this method takes a bit over 1 million iterations. Number of iterations ~= n ln(n).
#include <stdio.h>
#define n 100000
int main(void)
{
int * cnt = (int *)calloc(n+1, sizeof(int));
int d;
printf("Enter the target number of divisors: ");
scanf("%d", &d);
/* time complexity O(n log(n)) */
{
int i, j;
for (i = 1; i <= n; i++) {
for(j = i; j <= n; j += i) {
cnt[j]++;
}
}
}
{
int i;
int sum = 0;
for (i = 1; i <= n; i++)
sum += (cnt[i] == d) ? 1 : 0;
printf("excactly %d numbers have %d divisors\n", sum, d);
}
free(cnt);
return 0;
}
Rather than checking for the value of p uptil i we can optimize by checking until sqrt(i) and instead of incrementing divisors by 1, we increament it by 2, one for the number say k divided by i and second for the number i/k.
n=1000000;
for (i=1; i<=10000; i++)
{
divisors=2;
int p;
for(p=2; p<=sqrt(i); p++)
{
if (i%p==0)
{
if(p != (i/p)
divisors = divisors + 2;
else
divisors++;
}
}
if (divisors==a)
sum++;
}

Counting Positive Integers with a Given Number of Divisors

basically what i was trying to do is insert an integer k that represents the number of divisors and then finding all the numbers that have k divisors from 1-100000
#include <stdio.h>
int main(void)
{
int k, x = 1, y = 100000, divisor, count;
printf("Enter the target number of divisors:\n");
scanf("%d", &k);
for (divisor = 0; divisor <= 1; divisor++)
if (x % divisor == 0 && y % divisor == 0)
count++;
printf("There are %d numbers between 1 and 100000 inclusive which have exactly %d divisors\n", k, divisor);
return 0;
}
However I can't seem to be able to do it, please do help me as I'm fairly new to the programming scene and haven't found an answer elsewhere.
There is a theorem that states if you have the canonical representation of an integer being a1b1 * a2b2 ... anbn then the number of divisors of this integer is (b1 + 1) * (b2 + 1) ... (bn + 1).
Now that you have this theorem, you can modify slightly Eratosthenes's sieve to get all integers up to 100 000 in canonical form.
Here is some code that does what I mean by modified erathosthenes's sieve.
const int size = 100000;
int devs[size + 1];
void compute_devs() {
for (int i = 0; i < size + 1; ++i) {
devs[i] = (i%2 == 0) ? 2 : 1;
}
int o = sqrt(size);
for (int i = 3; i <= size; i += 2) {
if (devs[i] != 1) {
continue;
}
devs[i] = i;
if (i <= o) {
for (int j = i * i; j < size; j += 2 * i) {
devs[j] = i;
}
}
}
}
After calling compute_devs the value of devs will store the value of the greatest prime divisor of each number up to size. I will leave the rest of the task to you, but having this array it becomes pretty straight forward.

Resources