Reputation: 19
I am writing a program to create a file of prime numbers. I am new to C, and thus to its I/O system. The input is the number before (and including) which all prime numbers are to be written in a prime.csv file. I am trying to make my code efficient by using old primes. But, the subsequent prime of the last prime in the prime.csv file is not being appended. I have been stuck on this problem for a while now. Any help will be appreciated.
primes.c:
#include <stdio.h>
#include <stdlib.h>
int isPrime(FILE *file, unsigned int length, unsigned int number);
void primes(unsigned int number);
int main(int argc, char *argv[])
{
if (argc != 2)
{
perror("Usage: a.exe number");
return 1;
}
unsigned int number = atoi(argv[1]);
primes(number);
return 0;
}
int isPrime(FILE *file, unsigned int length, unsigned int number)
{
fseek(file, 0L, SEEK_SET);
unsigned int factor;
for (int i = 0; i < length; i++)
{
fscanf(file, "%u", &factor);
if (number % factor == 0)
return 0;
}
return 1;
}
void primes(unsigned int number)
{
// Getting Header Info
FILE *file_h = fopen("primes_h.csv", "r");
if (file_h == NULL)
{
perror("Was not able to open the file");
return;
}
unsigned int length;
unsigned int last;
fscanf(file_h, "%u,%u", &length, &last);
fclose(file_h);
// If number already less than or equal to last prime
if (number <= last + 1)
{
puts("Condition already satisfied.");
return;
}
// Adding new primes
FILE *file = fopen("primes.csv", "a+");
if (file == NULL)
{
perror("Was not able to open the file");
return;
}
unsigned int newLast;
unsigned int newLength = length;
for (unsigned int now = last + 2; now <= number; now += 2)
{
if (isPrime(file, newLength, now))
{
fprintf(file, "%u\n", now);
newLast = now;
newLength++;
}
}
fclose(file);
// Editing Header Info
FILE *e_file_h = fopen("primes_h.csv", "w");
if (e_file_h == NULL)
{
perror("Was not able to open the file");
return;
}
fprintf(e_file_h, "%u,%u", newLength, newLast);
fclose(e_file_h);
}
primes.csv:
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
61
67
71
73
79
83
89
97
101
103
107
109
and so on...
primes_h.csv:
669,4999
The primes_h.csv contains the header info about the primes.csv in the format: length, last
Upvotes: 0
Views: 42
Reputation: 144770
Reading primes from a file to test a number for primality is very inefficient: you will save a number of divisions, but these savings should be small compared to the overhead of reading from the file system and converting the numbers from text to internal representation. Furthermore, you should stop trying the divisors when they become greater than the square root of the number.
You could instead use an array to store the prime numbers found so far. This array does not need to store more than the prime numbers below the square root of the maximum number.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int primes[46341]; // all primes up to sqrt(INT32_MAX)
int nprimes = 0;
if (argc < 2) {
fprintf(stderr, "primes: missing argument\n");
return 1;
}
int limit = strtol(argv[1], NULL, 0);
FILE *fp = fopen("primes.csv", "w");
if (fp == NULL) {
fprintf(stderr, "primes: cannot open primes.csv\n");
return 1;
}
fprintf(fp, "prime\n");
if (limit >= 2) {
primes[nprimes++] = 2;
fprintf(fp, "2\n");
}
for (int n = 3; n <= limit; n += 2) {
int isprime = 1;
for (int i = 1; i < nprimes; i++) {
int p = primes[i];
if (p * p > n)
break;
if (n % p == 0) {
isprime = 0;
break;
}
}
if (isprime) {
if (nprimes < (int)(sizeof(primes) / sizeof(primes[0])))
primes[nprimes++] = n;
fprintf(fp, "%d\n", n);
}
}
fclose(fp);
return 0;
}
Note however that trial division is not very efficient to enumerate primes numbers up to a limit. A Sieve of Eratosthenes is much faster.
Upvotes: 1