I have a function which calls another function and checks for condition to see if it's true, then it increments an integer. It's all fine and working but there will be a problem for very large results. It couldn't fit even in long long.
Example:
unsigned long long div(int num_first[], int num_second[])
{
unsigned long long div_result = 0;
while (compare(num_first, num_second) != -1)
{
divsub(num_first, num_second);
div_result++;
}
return div_result; // return div_result to main
}
That function works fine, but if div_result gets too large it crashes or causes undefined behavior. I want to store its result as array like so:
div_result = 25464878454
I want it to be:
div_result[max] = {2, 5, 4, 6, 4, 8, 7, 8, 4, 5, 4}
How do I achieve this?
EDIT:
I decided to use unsigned long long as folks suggest. That suits my case.
you can write your own little bigint plus increment functionality:
#include <iostream>
using namespace std;
const int MAXDIGITS=12;
void inc(int bignum[MAXDIGITS])
{
++bignum[MAXDIGITS-1];
int carry=0;
for(int i = MAXDIGITS-1; i>=0; --i)
{
bignum[i] += carry;
if(bignum[i]>9)
{
carry = 1;
bignum[i] = 0;
}
else
break;
}
}
int main()
{
int div_result[MAXDIGITS] = {0};
// test inc function
for(int i=0; i<9999991; ++i)
inc(div_result);
for(int i=0; i<MAXDIGITS; ++i)
cout << div_result[i];
return 0;
}
Well since I worked on your original question, I'll go ahead and post the results for that as well in case you change your mind. Converting a number to an array can be approached in a number of ways. Here is one scheme using a recursive function and a helper to correct the order of the digits.
note: for 32-bit OS, overflow will occurr due to x86 utilizing a 4-bit long, a 32-bit safe version using 8-bit long long is included below, a 3rd version using preprocessor directives integrating both versions is included at the end:
#include <stdio.h>
#include <stdlib.h>
#define MAXDIG 32
void digits2array (long x, long *a, size_t *idx);
int digits2array_rev (long x, long *a, size_t *i);
int main (void) {
long n = 25464878454;
long ar[MAXDIG] = {0};
size_t idx = 0;
int i = 0;
digits2array (n, ar, &idx); /* convert n to array */
printf ("\n array:\n\n");
for (i = 0; i < idx; i++) /* output results */
printf (" ar[%2d] : %ld\n", i, ar[i]);
return 0;
}
/* converts x to array of digits in a (reverse order) */
int digits2array_rev (long x, long *a, size_t *i)
{
if (x < 10) {
a[(*i)++] = x;
return x;
}
a[(*i)++] = x % 10;
return digits2array_rev (x / 10, a, i);
}
/* helper function to reverse results of digits2array_rev */
void digits2array (long x, long *a, size_t *idx)
{
long tmp[MAXDIG] = {0};
int i = 0;
digits2array_rev (x, tmp, idx); /* fill array with digits (reversed) */
for (i = 0; i < *idx; i++) /* reverse to correct order */
a[*idx - 1 - i] = tmp[i];
}
Output/Results
$ ./bin/digits2array
array:
ar[ 0] : 2
ar[ 1] : 5
ar[ 2] : 4
ar[ 3] : 6
ar[ 4] : 4
ar[ 5] : 8
ar[ 6] : 7
ar[ 7] : 8
ar[ 8] : 4
ar[ 9] : 5
ar[10] : 4
32-bit Safe Version (using long long)
On 32-bit OS's overflow would still occur. Changing the types to long long (8-bit int on x86), allows the program to operate on x86 without issue.
#include <stdio.h>
#include <stdlib.h>
#define MAXDIG 32
void digits2array (long long x, long long *a, size_t *idx);
long long digits2array_rev (long long x, long long *a, size_t *i);
int main (void) {
long long n = 25464878454;
long long ar[MAXDIG] = {0};
size_t idx = 0;
int i = 0;
digits2array (n, ar, &idx); /* convert n to array */
printf ("\n array:\n\n");
for (i = 0; i < idx; i++) /* output results */
printf (" ar[%2d] : %lld\n", i, ar[i]);
return 0;
}
/* converts x to array of digits in a (reverse order) */
long long digits2array_rev (long long x, long long *a, size_t *i)
{
if (x < 10) {
a[(*i)++] = x;
return x;
}
a[(*i)++] = x % 10;
return digits2array_rev (x / 10, a, i);
}
/* helper function to reverse results of digits2array_rev */
void digits2array (long long x, long long *a, size_t *idx)
{
long long tmp[MAXDIG] = {0};
int i = 0;
digits2array_rev (x, tmp, idx); /* fill array with digits (reversed) */
for (i = 0; i < *idx; i++) /* reverse to correct order */
a[*idx - 1 - i] = tmp[i];
}
64/32-bit Version w/Preprocessor Directives
You can accomplish the same thing for x86, while preserving the original types for x86_64 through the use of preprocessor directives. (understanding that there is actually no storage benefit -- long (8-bit on x86_64), long long (8-bit on x86)).
#include <stdio.h>
#include <stdlib.h>
#if defined(__LP64__) || defined(_LP64)
# define BUILD_64 1
#endif
#define MAXDIG 32
#ifdef BUILD_64
void digits2array (long x, long *a, size_t *idx);
int digits2array_rev (long x, long *a, size_t *i);
#else
void digits2array (long long x, long long *a, size_t *idx);
long long digits2array_rev (long long x, long long *a, size_t *i);
#endif
int main (void) {
#ifdef BUILD_64
long n = 25464878454;
long ar[MAXDIG] = {0};
#else
long long n = 25464878454;
long long ar[MAXDIG] = {0};
#endif
size_t idx = 0;
int i = 0;
digits2array (n, ar, &idx); /* convert n to array */
printf ("\n array:\n\n");
for (i = 0; i < idx; i++) /* output results */
#ifdef BUILD_64
printf (" ar[%2d] : %ld\n", i, ar[i]);
#else
printf (" ar[%2d] : %lld\n", i, ar[i]);
#endif
return 0;
}
/* converts x to array of digits in a (reverse order) */
#ifdef BUILD_64
int digits2array_rev (long x, long *a, size_t *i)
#else
long long digits2array_rev (long long x, long long *a, size_t *i)
#endif
{
if (x < 10) {
a[(*i)++] = x;
return x;
}
a[(*i)++] = x % 10;
return digits2array_rev (x / 10, a, i);
}
/* helper function to reverse results of digits2array_rev */
#ifdef BUILD_64
void digits2array (long x, long *a, size_t *idx)
{
long tmp[MAXDIG] = {0};
#else
void digits2array (long long x, long long *a, size_t *idx)
{
long long tmp[MAXDIG] = {0};
#endif
int i = 0;
digits2array_rev (x, tmp, idx); /* fill array with digits (reversed) */
for (i = 0; i < *idx; i++) /* reverse to correct order */
a[*idx - 1 - i] = tmp[i];
}
Related
I am writing a small C program to count the number of bits which need to be flipped to make one number equal to another.
The program works very fine but i observe abnormal behaviour (Program hangs) when i pass ULONG_MAX as an argument. Why is this happening? See code below
#include <stdio.h>
#include <limits.h>
#include <stddef.h>
/**
* flip_bits - Count the number of bits to flip to equalize two numbers
* #n: First number
* #m: Second number
*
* Return: the number of bits to flip
*/
unsigned int flip_bits(unsigned long int n, unsigned long int m)
{
unsigned long int diff, count;
int i;
diff = n ^ m;
count = 0;
i = 0;
while (diff >> i)
{
if (diff >> i & 1)
count++;
i++;
}
return (count);
}
/**
* main - check the code
*
* Return: Always 0.
*/
int main(void)
{
unsigned int n;
n = flip_bits(1024, 1);
printf("%u\n", n);
n = flip_bits(402, 98);
printf("%u\n", n);
n = flip_bits(1024, 3);
printf("%u\n", n);
n = flip_bits(ULONG_MAX, 0);
printf("%u\n", n);
return (0);
}
Be explicit with signedness and size of all relevant types involved. Don't use bitwise arithmetic on signed numbers. You can simplify this whole code quite a bit by using a readable for loop instead:
#include <stdint.h>
uint32_t count_diff32 (uint32_t x, uint32_t y)
{
uint32_t diff = x ^ y;
uint32_t count = 0;
for(size_t i=0; i<32; i++)
{
if (diff & (1u<<i))
{
count++;
}
}
return count;
}
My task is to run the matrix vector multiplication c program for like 14-16 minutes. And I am only able that to run for like 20 seconds maximum. I also tried increasing the value of row and columns and also other bunch of stuff and I am not able to do it. Can you please help me?
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#define NUM_ROWS 600000 // M dimension
#define NUM_COLS 200000// N dimension
void main(int argc, char *argv[])
{
struct timeval start, stop, elapse; // declaring the structure elements
gettimeofday( &start, NULL ); // calling gettimeofday function to calculate time
long long int myid, numprocs, i, j;
long long int local_row_sum;
double starttime, endtime;
long long int *matrix = (long long int*)malloc(NUM_ROWS * NUM_COLS * sizeof(long long int));
long long int *vector = (long long int*)malloc(NUM_COLS * sizeof(long long int ));
long long int *local_result = (long long int *)malloc(NUM_ROWS * sizeof(long long int));
long long int *final_result = (long long int *)malloc(NUM_ROWS * sizeof(long long int ));
// Initialize array and vector
for (i = 0; i < NUM_ROWS; i++) {
for(j = 0; j < NUM_COLS; j++) {
matrix[i * NUM_COLS + j] = i + j;
}
}
for (j = 0; j < NUM_COLS; j++) {
vector[j] = j;
}
int k, l;
long long int*sequential_result = (long long int*)malloc(NUM_ROWS * 1 * sizeof(long long int ));
for (k = 0; k < NUM_ROWS; k++)
{
sequential_result[k] = 0;
for (l = 0; l < NUM_COLS; l++)
{
sequential_result[k] += *(matrix + k * NUM_COLS + l) * *(vector + l);
}
printf("The result: %lld\n", sequential_result[k]);
// Check that sequential result equals MPI result (0 is error code here)
}
gettimeofday( &stop, NULL ); // calling gametimeofday function to stop counting the time taken
timersub( &stop, &start, &elapse ); // calling this function to calculate the time difference
fprintf( stderr, "Elapse time\t%g\n", elapse.tv_sec+0.000001*elapse.tv_usec );
}
You're getting a compile error on:
long long int *matrix = (long long int *) malloc(NUM_ROWS * NUM_COLS * sizeof(long long int));
The error is:
orig.c:21:60: warning: integer overflow in expression of type ‘int’ results in ‘-259084288’ [-Woverflow]
orig.c:21:44: warning: argument 1 value ‘18446744071636877312’ exceeds maximum object size 9223372036854775807 [-Walloc-size-larger-than=]
That's because you put the sizeof as the last term, so it used int (32 bits) instead of size_t [probably 64 bits].
Thus, the size argument actually passed to malloc gets wrapped/truncated to 32 bits before it is passed as an argument. So, you'll only allocate a much smaller area than you expect.
This probably results in UB (undefined behavior) because the rest of the code will assume the larger area and will modify memory beyond the end of the actual allocation.
To fix, do this:
long long int *matrix = malloc(sizeof(*matrix) * NUM_ROWS * NUM_COLS);
This will force the entire argument expression to be 64 bits [which is what you want/need]. You should do similar changes for your other malloc calls.
Edit: Oops, I missed the fact that your allocation is so large that it can't be fulfilled by malloc [which was flagged by the second error message]. You'll have to cut down the array sizes [see below]
BTW, don't cast the return from malloc: Do I cast the result of malloc?.
And, using the sizeof(*matrix) trick is much more likely to produce robust code.
Also, you should definitely check the return value from malloc for NULL and abort if so. You're allocating a huge array. Your system may not have enough memory (either physical memory or logical memory if you've defined swap areas).
Since this check has to be repeated, consider using a wrapper function:
void *
safe_malloc(size_t size)
{
void *ptr;
ptr = malloc(size);
if (ptr == NULL) {
fprintf(stderr,"safe_malloc: malloc failure -- size=%zu -- %s\n",
size,strerror(errno));
exit(1);
}
return ptr;
}
And, replace the [fixed/adjusted] malloc calls with calls to safe_malloc.
I sometimes also use a macro to further reduce repeating boilerplate:
#define DEFINE_AND_ALLOC_VECTOR(_typ,_ptr,_count) \
_typ *_ptr = safe_malloc(sizeof(*_ptr) * (_count))
Then, you can do:
DEFINE_AND_ALLOC_VECTOR(long long int,matrix,NUM_ROWS * NUM_COLS);
UPDATE:
what about long long int*sequential_result = (long long int*)malloc(NUM_ROWS * 1 * sizeof(long long int ));
No, I wouldn't do that for a few reasons. It violates the DRY (don't repeat yourself) principle [because you repeated long long int three times.
Under C, casting the return value of malloc which returns a void * is cruft and can silently mask a bug [if you inadvertently fail to do #include <stdlib.h> the compiler will default the return type to int and truncate the return value to 32 bits].
Suppose you changed the type of sequential_result from long long int to (e.g. long double). But, didn't change the [bad] cast type or the sizeof.
Now, you've got a bug:
long double *sequential_result = (long long int *) malloc(sizeof(long long int) * NUM_COLS);
Here not enough space was allocated.
That's why experienced programmers [usually] prefer the sizeof(*ptr)
Further tip: The preferred grouping is:
long long int *sequential_result = ...;
And, not:
long long int* sequential_result = ...;
That's because if you have:
int* a,b;
That seems to be the equivalent of:
int *a;
int *b;
But, it is actually:
int *a;
int b;
The asterisk binds tightly right-to-left and not left-to-right. So, doing int* is deceptive.
UPDATE #2:
Can you please rewrite the program?
Here is the refactored code. I've cut down the dimensions by a factor of 100 to fit into a sane amount of memory.
From your question, it seems you want large arrays so you can benchmark for an extended period of time.
I do a lot of code optimization and benchmarking. Smaller size arrays will give you accurate timing data. For a simple matrix multiply, about 10 seconds is sufficient.
I've used cpp conditionals to show old vs. new code:
#if 0
// old [broken] code
#else
// new [fixed] code
#endif
Anyway, here is the refactored code [as I would write it]:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#if 0
#define NUM_ROWS 600000 // M dimension
#define NUM_COLS 200000 // N dimension
#else
#define NUM_ROWS 6000 // M dimension
#define NUM_COLS 2000 // N dimension
#endif
#define DEFINE_AND_ALLOC_VECTOR(_typ,_ptr,_count) \
_typ *_ptr = safe_malloc(sizeof(*_ptr) * _count)
typedef long long int bignum_t;
double
tscgetf(void)
{
struct timespec ts;
double sec;
clock_gettime(CLOCK_MONOTONIC,&ts);
sec = ts.tv_nsec;
sec /= 1e9;
sec += ts.tv_sec;
return sec;
}
void *
safe_malloc(size_t size)
{
void *ptr;
ptr = malloc(size);
if (ptr == NULL) {
fprintf(stderr,"safe_malloc: malloc failure -- size=%zu -- %s\n",
size,strerror(errno));
exit(1);
}
return ptr;
}
int
main(int argc, char **argv)
{
double start, stop;
start = tscgetf();
//int myid;
//int numprocs;
size_t i;
size_t j;
//bignum_t local_row_sum;
DEFINE_AND_ALLOC_VECTOR(bignum_t,matrix,NUM_ROWS * NUM_COLS);
DEFINE_AND_ALLOC_VECTOR(bignum_t,vector,NUM_COLS);
DEFINE_AND_ALLOC_VECTOR(bignum_t,local_result,NUM_ROWS);
DEFINE_AND_ALLOC_VECTOR(bignum_t,final_result,NUM_ROWS);
bignum_t *mat;
// Initialize array and vector
#if 0
for (i = 0; i < NUM_ROWS; i++) {
for (j = 0; j < NUM_COLS; j++) {
matrix[i * NUM_COLS + j] = i + j;
}
}
#else
for (i = 0; i < NUM_ROWS; i++) {
mat = &matrix[i * NUM_COLS];
for (j = 0; j < NUM_COLS; j++)
mat[j] = i + j;
}
#endif
for (j = 0; j < NUM_COLS; j++)
vector[j] = j;
DEFINE_AND_ALLOC_VECTOR(bignum_t,sequential_result,NUM_ROWS);
#if 0
int k, l;
#else
size_t k, l;
#endif
#if 0
for (k = 0; k < NUM_ROWS; k++) {
sequential_result[k] = 0;
for (l = 0; l < NUM_COLS; l++) {
sequential_result[k] += *(matrix + k * NUM_COLS + l) *
*(vector + l);
}
}
#else
for (k = 0; k < NUM_ROWS; ++k) {
bignum_t acc = 0;
mat = &matrix[k * NUM_COLS];
for (l = 0; l < NUM_COLS; ++l)
acc += mat[l] * vector[l];
sequential_result[k] = acc;
#endif
printf("The %zu result: %lld\n", k, sequential_result[k]);
// Check that sequential result equals MPI result (0 is error code here)
}
stop = tscgetf();
fprintf(stderr, "Elapse time\t%.9f seconds\n", stop - start);
return 0;
}
There are several fast algorithms to calculate prime numbers up to a given number n. But, what is the fastest implementation to list all the numbers r relatively prime to some number n in C? That is, find all the elements of the multiplicative group with n elements as efficiently as possible in C. In particular, I am interested in the case where n is a primorial.
The n primorial is like the factorial except only prime numbers are multiplied together and all other numbers are ignored. So, for example 12 primorial would be 12#=11*7*5*3*2.
My current implementation is very naive. I hard code the first 3 groups as arrays and use those to create the larger ones. Is there something faster?
#include "stdafx.h"
#include <stdio.h> /* printf, fgets */
#include <stdlib.h> /* atoi */
#include <math.h>
int IsPrime(unsigned int number)
{
if (number <= 1) return 0; // zero and one are not prime
unsigned int i;
unsigned int max=sqrt(number)+.5;
for (i = 2; i<= max; i++)
{
if (number % i == 0) return 0;
}
return 1;
}
unsigned long long primorial( int Primes[], int size)
{
unsigned long long answer = 1;
for (int k = 0;k < size;k++)
{
answer *= Primes[k];
}
return answer;
}
unsigned long long EulerPhi(int Primes[], int size)
{
unsigned long long answer = 1;
for (int k = 0;k < size;k++)
{
answer *= Primes[k]-1;
}
return answer;
}
int gcd( unsigned long long a, unsigned long long b)
{
while (b != 0)
{
a %= b;
a ^= b;
b ^= a;
a ^= b;
}
//Return whethere a is relatively prime to b
if (a > 1)
{
return false;
}
return true;
}
void gen( unsigned long long *Gx, unsigned int primor, int *G3)
{
//Get the magic numbers
register int Blocks = 30; //5 primorial=30.
unsigned long long indexTracker = 0;
//Find elements using G3
for (unsigned long long offset = 0; offset < primor; offset+=Blocks)
{
for (int j = 0; j < 8;j++) //The 8 comes from EulerPhi(2*3*5=30)
{
if (gcd(offset + G3[j], primor))
{
Gx[indexTracker] = offset + G3[j];
indexTracker++;
}
}
}
}
int main(int argc, char **argv)
{
//Hardcoded values
int G1[] = {1};
int G2[] = {1,5};
int G3[] = {1,7,11,13,17,19,23,29};
//Lazy input checking. The world might come to an end
//when unexpected parameters given. Its okey, we will live.
if (argc <= 1) {
printf("Nothing done.");
return 0;
}
//Convert argument to integer
unsigned int N = atoi(argv[1]);
//Known values
if (N <= 2 )
{
printf("{1}");
return 0;
}
else if (N<=4)
{
printf("{1,5}");
return 0;
}
else if (N <=6)
{
printf("{1,7,11,13,17,19,23,29}");
return 0;
}
//Hardcoded for simplicity, also this primorial is ginarmous as it is.
int Primes[50] = {0};
int counter = 0;
//Find all primes less than N.
for (int a = 2; a <= N; a++)
{
if (IsPrime(a))
{
Primes[counter] = a;
printf("\n Prime: : %i \n", a);
counter++;
}
}
//Get the group size
unsigned long long MAXELEMENT = primorial(Primes, counter);
unsigned long long Gsize = EulerPhi(Primes, counter);
printf("\n GSize: %llu \n", Gsize);
printf("\n GSize: %llu \n", Gsize);
//Create the list to hold the values
unsigned long long *GROUP = (unsigned long long *) calloc(Gsize, sizeof(unsigned long long));
//Populate the list
gen( GROUP, MAXELEMENT, G3);
//Print values
printf("{");
for (unsigned long long k = 0; k < Gsize;k++)
{
printf("%llu,", GROUP[k]);
}
printf("}");
return 0;
}
If you are looking for a faster prime number check, here is one that is reasonably fast and eliminates all calls to computationally intensive functions (e.g. sqrt, etc..)
int isprime (int v)
{
int i;
if (v < 0) v = -v; /* insure v non-negative */
if (v < 2 || !((unsigned)v & 1)) /* 0, 1 + even > 2 are not prime */
return 0;
for (i = 2; i * i <= v; i++)
if (v % i == 0)
return 0;
return 1;
}
(note: You can adjust the type as required if you are looking for numbers above the standard int range.)
Give it a try and let me know how it compares to the once you are currently using.
I was trying to run a Hilbert curve code written in C, which I found here
http://www.tddft.org/svn/octopus/trunk/src/grid/hilbert.c
The code runs, but the results I get form the output are not correct. I made a simple driver routine, that takes 3 values as arguments from the command line and passes them to a Hilbert curve encode, decode routines.
More precisely, I can't decode back the original coordinates (x,y,z).
One of my problems was to understand what the variable nbits is doing. I assume it is the size of the encoded Hilbert value. To check this I tried to modify the original definition of one of the functions from
void InttoTranspose(const int dim, const long long int h, int * x)
to
void InttoTranspose(const int dim, const long long int h, int * x, int* size)
Where I assign to *size the bit count variable ifbit. Anyway, this all didn't work. Therefore I would like to ask for your help.
The modified code is here:
#include<stdio.h>
//#include <config.h>
#include <assert.h>
/* This code is based on the implementation of the Hilbert curves
presented in:
J. Skilling, Programming the Hilbert curve, AIP Conf. Proc. 707, 381 (2004); http://dx.doi.org/10.1063/1.1751381
*/
*/ The int* size was included later in an attempt to find the proper size /*
/* void InttoTranspose(const int dim, const long long int h, int * x)*/
void InttoTranspose(const int dim, const long long int h, int * x, int* size){
/* the code uses some funny way of storing the bits */
int idir, ibit, ifbit;
for(idir = 0; idir < dim; idir++) x[idir] = 0;
ifbit = 0;
for(ibit = 0; ibit < 21; ibit++){
for(idir = dim - 1; idir >= 0; idir--){
x[idir] += (((h>>ifbit)&1)<<ibit);
ifbit++;
}
}
*size=ifbit; // I think that this should be nbits
}
void TransposetoAxes(int* X, int b, int n ){ /* position, #bits, dimension */
int N = 2 << (b-1), P, Q, t;
int i;
/* Gray decode by H ^ (H/2) */
t = X[n-1] >> 1;
for(i = n - 1; i > 0; i--) X[i] ^= X[i-1];
X[0] ^= t;
/* Undo excess work */
for( Q = 2; Q != N; Q <<= 1 ) {
P = Q - 1;
for( i = n-1; i >= 0 ; i-- ){
if( X[i] & Q ) {
X[0] ^= P; /* invert */
} else{
t = (X[0]^X[i]) & P; X[0] ^= t; X[i] ^= t; /* exchange */
}
}
}
}
//void FC_FUNC_(hilbert_index_to_point, HILBERT_INDEX_TO_POINT)(const int * dim, const int * nbits, const long long int * index, int * point){
// InttoTranspose(*dim, *index, point);
// TransposetoAxes(point, *nbits, *dim);
//}
int main(int argc,char* argv[]){
long long int hilbert;
int i=0,x[2],m;
while(argc--){
if(m=atoi(*argv++)) x[i++]=m, printf("--> %5d %5d\n",m,argc);
}
printf("x= %5d y= %5d z= %5d \n",x[0],x[1],x[2]);
InttoTranspose(3, hilbert, x,&m);
printf("hilbert encoded --> %llu size -->%d \n",hilbert,m);
TransposetoAxes(x,m, 3 );
printf("x= %5d y= %5d z= %5d \n",x[0],x[1],x[2]);
return 0;
}
I am trying to find primes using Sieve of Eratosthenes with bit arrays, but I am using unsigned int array. I need to be able to generate upto 2,147,483,647 primes. My code works and can generate around 10,000,000 but when I increase the size of my array to accommodate larger numbers it fails. Can someone guide me on how to use bit vectors with c (not c++).
Thanks
Here's my code:
#include <stdio.h>
#include <stdlib.h>
#define MAXBYTES 2000000
#define MAX 50000000
#define BITSIZE 32
void ClearBit(unsigned int [], unsigned int);
void SetBit(unsigned int [], unsigned int);
int BitVal(unsigned int [], unsigned int);
void PrintBitStream(unsigned int [], unsigned long);
void PrintBitStreamData(unsigned int[], unsigned long);
int Sieve(unsigned int[], unsigned int, unsigned int);
int main(int argc, char ** argv) {
unsigned int maxsize = MAX;
unsigned int i;
//Set Bit Array
unsigned int BitArray[MAXBYTES] = {0};
SetBit(BitArray, 0);
SetBit(BitArray, 1);
i = 2;
for (;i < maxsize;i++){
if(Sieve(BitArray, i, maxsize)==0)
break;
}
PrintBitStreamData(BitArray, maxsize-1);
return EXIT_SUCCESS;
}
void PrintBitStreamData(unsigned int BitArray[], unsigned long maxsize) {
unsigned int i;
for (i = 0; i < maxsize; i++)
if (!BitVal(BitArray, i))
printf("%ld ", i);
printf("\n");
}
void PrintBitStream(unsigned int BitArray[], unsigned long maxsize) {
unsigned int i;
for (i = 2; i < maxsize; i+=2)
printf("%d", BitVal(BitArray, i));
printf("\n");
}
void SetBit(unsigned int BitArray[], unsigned int pos) {
BitArray[pos / BITSIZE] |= 1 << (pos % BITSIZE);
}
void ClearBit(unsigned int BitArray[], unsigned int pos) {
BitArray[pos / BITSIZE] &= ~(1 << (pos % BITSIZE));
}
int BitVal(unsigned int BitArray[], unsigned int pos) {
return ((BitArray[pos / BITSIZE] & (1 << (pos % BITSIZE))) != 0);
}
int Sieve(unsigned int BitArray[], unsigned int p, unsigned int maxsize) {
unsigned int i;
unsigned int j;
j = 0;
for (i = 2 * p; i < maxsize; i += p) {
SetBit(BitArray, i);
j++;
}
return j;
}
I definitely would NOT use a bit array, but an array of the native int (64-bit or 32-bit dependign on architecture) and wrapping around a function to remap normal numbers to the right place and bit with bitwise | and &.
Also consider leaving out the even numbers, almost none of them are prime. So you could store the first 128 numbers in the first 64-bit number, the next 128 in the second etc.
It sounds a bit complicated, but is a bit fun to get it work!
Project Euler seems to have produced some really nice solutions.
The good thing is: to sieve you don't need to recalculate the even-odd-transfer, but you can unset every third bit for sieving 3, every 5th bit for sieving 5 etc.
Come into chat if you want a quick java solution as a detailed reference.
EDIT4: corrected Working code, but yet slow. Memo: Remember using calloc!
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <limits.h>
#include <time.h>
typedef unsigned long long number;
number lookFor = 2147483648ULL;
number max = 2147483648ULL*10ULL; // hopefully more then every 10th uneven number is prime
unsigned long * isComposite;
number bitslong = CHAR_BIT*sizeof(long);
time_t rawtime;
struct tm * timeinfo;
char buffer[80];
// is not called during sieve, only once per sieving prime
// and needed for reading if a number is prime
inline long getParts(number pos, number *slot, unsigned int *bit){
*slot = pos / bitslong;
*bit = (unsigned int)(pos % bitslong);
}
int isPrime(number n){
if(n == 1){
return 0;
}
if(n < 4){
return 1;
}
if((n%2) == 0){
return 0;
}
number slot=0;
unsigned int bit=0;
number pos = (number)(n-3)/2;
getParts(pos, &slot, &bit);
// printf("? n=%lld pos = %lld slot = %lld bit = %lu ret %d \n", n, pos, slot, bit, !(isComposite[slot] & (1<<bit)));
return !(isComposite[slot] & (1UL<<bit));
}
// start sieving at offset (internal position) offset with width step
int doSieve(number offset, number step){
rawtime = time(0);
time (&rawtime);
timeinfo = localtime (&rawtime);
strftime(buffer, 80, "%Y-%m-%d %H:%I:%S", timeinfo);
unsigned int bit=0;
number slot=0;
getParts(offset, &slot, &bit);
printf("doSieve %s %lld %lld %lu \n", buffer, offset, step, isComposite[slot]);
while(slot < max/bitslong){
slot += (step + bit)/bitslong;
bit = (step + bit) % bitslong;
isComposite[slot] |= (1UL << bit);
}
return 1;
}
int sieve(){
number spot;
spot=1;
number pos;
pos = 0;
while(spot < 1 + sqrt((float)max)){
spot+=2;
if(! isPrime(spot)){
pos++;
continue;
}
doSieve(pos, spot);
pos++;
}
}
void main(int argc, char *argv[]){
if(argc > 1){
char *tp = malloc(sizeof(char*));
max = strtol(argv[1], &tp, 10);
}
printf("max %lld , sq %ld, malloc: %lld\n", max, (long)(1 + sqrt((float)max)), 1+max/bitslong);
isComposite = calloc((2+max/bitslong), sizeof(unsigned long)) ;
if(! isComposite){
printf("no mem\n");
exit(5);
}
sieve();
number i;
number found = 0;
for(i = 1; i<max && found < lookFor; i++){
if(isPrime(i)){
found++;
// printf(" %30lld %30lld \n", found, i);
if(found % 10000 == 0 ){
printf("%30lld %30lld \n", found, i);
}
}
/*
if(i % 1000 == 17){
printf("%5lld %5lld \n", i, found);
}
*/
}
}
Example using bit access into an integer
Note GetBit() and SetBit().
An optimizing compiler will make the / and % fast for powers of 2 are used.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ubitsize (sizeof(unsigned)*8)
unsigned GetBit(const unsigned *List, unsigned long index) {
return !!(List[index / ubitsize] & (1u << (index % ubitsize)));
}
void SetBit(unsigned *List, unsigned long index) {
List[index / ubitsize] |= (1u << (index % ubitsize));
}
void Sieve_of_Eratosthenes_via_bit_array(unsigned long MaxCandidatePrime) {
unsigned long uByteSize = MaxCandidatePrime/ubitsize + 1;
unsigned *List = calloc(uByteSize, sizeof *List);
if (List == 0) return;
unsigned long PrimeCount = 0;
unsigned long Index = 0;
for (Index = 2; Index <= MaxCandidatePrime; Index++) {
// If found a prime ...
if (GetBit(List, Index) == 0) {
PrimeCount++;
// let's see the progress
if ((PrimeCount % (256LU*1024)) == 0) printf("%lu\n", Index);
// Mark subsequent multiples as not--a-prime
unsigned long Index2 = Index*2;
while (Index2 <= MaxCandidatePrime) {
SetBit(List, Index2);
Index2 += Index;
}
}
}
printf("X %lu\n", Index);
free(List);
}
void test(void) {
Sieve_of_Eratosthenes_via_bit_array(200LU*1000*1000);
}
A re-write could employ usual suggestion to not save even numbers, treating 2 as a special case. This helps but I assume this is an exercise. I could save a factor of about 4 by saving using 1 byte to encode every 30th multiple as, after 30, for there are at most 8 primes every 30 integers. Other schemes exist.