I'm currently trying to implement the Sieve of Eratosthenes in C using a BitSet, but I get a segmentation fault, when I try to sieve the primes up to 1,000,000 (1 million) - 100,000 (100 thousand) is still working though and I can't figure out why I get the seg-fault.
This is the code I use (I marked the line, in which the error occurs):
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
void eSieve(uint64_t upperLimit);
int main(int argc, char *argv[]) {
uint64_t upperLimit;
if (argc == 2) {
upperLimit = (uint64_t) atoll(argv[1]);
printf("Using custom limit: %" PRIu64 "\n", upperLimit);
} else {
upperLimit = 1000;
printf("Using default limit: %" PRIu64 "\n", upperLimit);
}
eSieve(upperLimit);
return 0;
}
typedef uint32_t prime_t;
void eSieve(uint64_t upperLimit) {
if (upperLimit < 2) {
printf("FAILURE: Bad upper limit.\n");
return;
}
prime_t *sieve = calloc(1, (upperLimit + sizeof(prime_t) - 1)/sizeof(prime_t));
if (!sieve) {
printf("FAILURE: Could not initialize sieve.\n");
return;
}
sieve[0] |= 3; // Set first and second bit (representing 0 and 1)
uint64_t prime, number;
for (prime = 2; prime * prime < upperLimit; ) {
for (number = prime * prime; number < upperLimit; number += prime) {
// Segmentation fault for prime = 2 and number = 258048
sieve[number/sizeof(prime_t)] |= (((prime_t) 1) << (number % sizeof(prime_t)));
}
while ((sieve[++prime/sizeof(prime_t)] & (prime_t)1 << (prime % sizeof(prime_t))) != 0)
;
}
number = upperLimit;
while ((sieve[--number/sizeof(prime_t)] & (((prime_t)1) << (number % sizeof(prime_t)))) != 0)
;
printf("Greatest prime-number below %" PRIu64 ": %" PRIu64 "\n",
upperLimit, number);
}
Does anybody know why the error occurs? I'm guessing that now enough space is allocated (somehow), but I can't see how this would be possible at the moment...
You're not getting the correct bit number:
sieve[number/sizeof(prime_t)] |= (((prime_t) 1) << (number % sizeof(prime_t)));
When you do the division and mod, you need to divide/mod by the number of bits, not the number of bytes:
sieve[number/(sizeof(prime_t)*8)] |= (((prime_t) 1) << (number % (sizeof(prime_t)*8)));
And similarly:
while ((sieve[++prime/(sizeof(prime_t)*8)] & (prime_t)1 << (prime % (sizeof(prime_t)*8))) != 0)
...
while ((sieve[--number/(sizeof(prime_t)*8)] & (((prime_t)1) << (number % (sizeof(prime_t)*8)))) != 0)
EDIT:
You're also not allocating the right amount of memory. You need a number of bytes equal to the limit divided by the number of bits, plus 1 sizeof(prime_t) to round up.
prime_t *sieve = calloc(1, (upperLimit / 8) + sizeof(prime_t));
As it right now, you're allocating twice the bytes you need.
Also, if you want to defend against cases where there are more or less than 8 bits to a byte, use CHAR_BIT in the above code in place of 8. Whatever sizeof(uint64_t) evaluates to shouldn't matter, as you'll still get the proper number of bits required.
You allocate X bytes with calloc, dividing the total by sizeof(prime_t), yet act as if you have room for X prime_t elements later on.
Edit: Or actually even, you are allocating an array of 1 element with size X.
If you want to do it the way you are using it now, you should do:
calloc(X, sizeof(prime_t)) instead.
Edit: The major other issue in your code is that you are using byte-level indexing instead of bit-level.
Note that there are sizeof(prime_t) * 8 bits in a prime_t, so in every byte you set exactly 1 bit, true. You divide by sizeof(prime_t) instead of (sizeof(prime_t) * 8) when indexing.
Related
Here is a sample code
int x = rand() % 90000;
When I was doing something like this I realized all the numbers were around 0 - 30000.
Is there a limit for this? If there is how can I use it without limits?
You should not use rand(), because it is quite poor in many C standard library implementations. It will return a pseudorandom number between 0 and RAND_MAX, inclusive, but RAND_MAX is often relatively small; for example, 32767.
Using the modulo operator to yield a range of integers is problematic if the range is a large fraction of the range of values the generator function can return, because the distribution is not exactly uniform.
For example, let's say RAND_MAX is 59999, and we used rand() % 40000. The probability of the result being between 0 and 19999 is 67%, but only 33% between 20000 and 39999. This is because that rand() produces a value in [0,19999] at 1/3 probability, [20000,39999] at 1/3 probability, and [40000..59999] at 1/3 probability; but that last third folds back so that it yields [0,19999] after the modulo operation!
For small ranges the bias is not so noticeable.
Personally, I like to generate enough random bits to cover the desired range, then use the exclusion method to pick the value.
If we need to use rand(), we can use the following helper function to generate a pseudorandom number whose range is at least atleast (but may be larger; i.e. it can return a larger value):
#include <inttypes.h>
static inline uint64_t rand_atleast(uint64_t atleast)
{
uint64_t result = 0;
do {
result = ((uint64_t)RAND_MAX + 1) * result + (uint64_t)rand();
atleast /= ((uint64_t)RAND_MAX + 1);
} while (atleast > 0);
return result;
}
To use the exclusion method to create ints within a desired range, we can use a structure to contain the stuff we need, a helper function to initialize that range (to describe some specific range of ints), and another helper function to generate integers within that range:
struct range_spec {
uint64_t mask;
uint64_t limit;
int base;
};
static inline void set_range(struct range_spec *spec,
int minimum, int maximum)
{
uint64_t mask;
int base;
if (minimum <= maximum) {
base = minimum;
mask = maximum - minimum;
} else {
base = maximum;
mask = minimum - maximum;
}
spec->base = base;
spec->limit = mask;
mask |= mask >> 1;
mask |= mask >> 2;
mask |= mask >> 4;
mask |= mask >> 8;
mask |= mask >> 16;
mask |= mask >> 32;
spec->mask = mask;
}
static inline int rand_range(const struct range_spec *spec)
{
const uint64_t mask = spec->mask;
const uint64_t limit = spec->limit;
uint64_t result;
do {
result = rand_atleast(mask) & mask;
} while (result > limit);
return spec->base + result;
}
However, this is a lot of work to get pretty poor pseudorandom numbers: not worth it in my opinion.
I usually use Xorshift64* instead. It is fast, quite random (see this extended comment of mine), and really easy to implement.
Essentially, you can use a small header file, say rng64.h:
#ifndef RNG64_H
#define RNG64_H
#include <inttypes.h>
#include <time.h>
typedef struct {
uint64_t limit;
int64_t base;
int shift;
} rng64_intrange_spec;
static uint64_t rng64_state = 1;
static inline uint64_t rng64(void)
{
uint64_t x = rng64_state;
x ^= x >> 12;
x ^= x << 25;
x ^= x >> 27;
rng64_state = x;
return x * UINT64_C(2685821657736338717);
}
static inline uint64_t rng64_randomize(void)
{
uint64_t x;
int n = 1000;
x = ((uint64_t)time(NULL) * UINT64_C(19076794157513))
^ ((uint64_t)clock() * UINT64_C(809712647));
if (!x)
x = 1;
while (n-->0) {
x ^= x >> 12;
x ^= x << 25;
x ^= x >> 27;
}
rng64_state = x;
return x;
}
static inline double rng64_one(void)
{
return (double)rng64() / 18446744073709551616.0;
}
static inline int64_t rng64_intrange(rng64_intrange_spec *spec)
{
const uint64_t limit = spec->limit;
const int shift = spec->shift;
uint64_t value;
do {
value = rng64() >> shift;
} while (value > limit);
return spec->base + value;
}
static inline void rng64_set_intrange(rng64_intrange_spec *spec,
int64_t minimum,
int64_t maximum)
{
int64_t base;
uint64_t limit;
int bits = 0;
if (minimum <= maximum) {
base = minimum;
limit = maximum - minimum;
} else {
base = maximum;
limit = minimum - maximum;
}
spec->base = base;
spec->limit = limit;
while (limit >= 32768) {
limit >>= 16;
bits += 16;
}
while (limit >= 8) {
limit >>= 4;
bits += 4;
}
while (limit > 0) {
limit >>= 1;
bits += 1;
}
spec->shift = 64 - bits;
}
#endif /* RNG64_H */
Somewhere near the beginning of your program, call rng64_randomize() to generate a state based on the current time (wall clock via time(), and CPU time used to execute the current process via clock()). The initial state is churned a bit, to ensure you don't get similar sequences when running the code in quick succession. You can set the rng64_state to any value except zero, to generate a specific sequence. (Zero state will generate only zeroes.) I recommend using
printf("Using %" PRIu64 " as the Xorshift64* random number seed.\n", rng64_randomize());
which prints both the seed, and the pseudorandom number generator algorithm used, near the beginning of the program. That allows someone to reproduce the test (by setting rng64_state to that value instead of calling rng64_randomize(), or reimplement the test using their own equivalent code). Reproducibility is good.
While (uint64_t)time(NULL) is not guaranteed to work by the C standard, it does work in all current widely-used C implementations I am aware of.
If you want to compare to a different pseudorandom number generator, just reimplement another using a similar header file, and include that instead. That way you don't need to change any code that uses the generator, only the generator code itself.
rng_one() returns uniform pseudorandom numbers between 0 and 1.0, inclusive. If you want the upper limit to be exclusive, use e.g.
static inline double rng64_one(void)
{
double r;
do {
r = (double)rng64() / 18446744073709551616.0;
} while (r >= 1.0);
return r;
}
and if both limits exclusive (so it never returns 0.0 or 1.0 exactly), while (r <= 0.0 || r >= 1.0); instead.
Here's an example of how to use the rng64.h above:
#include <stdlib.h>
#include <inttypes.h>
#include <string.h>
#include <stdio.h>
#include "rng64.h"
int main(int argc, char *argv[])
{
rng64_intrange_spec r;
int minval, maxval, count, i;
char dummy;
if (argc != 4 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s MIN MAX COUNT\n", argv[0]);
fprintf(stderr, "\n");
fprintf(stderr, "This program outputs COUNT pseudorandom integers,\n");
fprintf(stderr, "between MIN and MAX, inclusive.\n");
fprintf(stderr, "\n");
return EXIT_FAILURE;
}
if (sscanf(argv[1], " %d %c", &minval, &dummy) != 1) {
fprintf(stderr, "%s: Invalid minimum.\n", argv[1]);
return EXIT_FAILURE;
}
if (sscanf(argv[2], " %d %c", &maxval, &dummy) != 1 || maxval < minval) {
fprintf(stderr, "%s: Invalid maximum.\n", argv[2]);
return EXIT_FAILURE;
}
if (sscanf(argv[3], " %d %c", &count, &dummy) != 1 || count < 0) {
fprintf(stderr, "%s: Invalid count.\n", argv[3]);
return EXIT_FAILURE;
}
fprintf(stderr, "Generating %d pseudorandom integers in [%d, %d],\n", count, minval, maxval);
fprintf(stderr, "using Xorshift64* with seed %" PRIu64 ".\n", rng64_randomize());
fflush(stderr);
rng64_set_intrange(&r, minval, maxval);
for (i = 0; i < count; i++)
printf("%d\n", (int)rng64_intrange(&r));
return EXIT_SUCCESS;
}
Specify the minimum and maximum values (integers), and the number of integers to output, as command-line parameters.
I have a algorithm problem that I need to speed up :)
I need a 32bit random number, with exact 10 bits set to 1. But in the same time, patterns like 101 (5 dec) and 11 (3 dec) to be considered illegal.
Now the MCU is a 8051 (8 bit) and I tested all this in Keil uVision. My first attempt completes, giving the solution
0x48891249
1001000100010010001001001001001 // correct, 10 bits 1, no 101 or 11
The problem is that it completes in 97 Seconds or 1165570706 CPU cycles which is ridiculous!!!
Here is my code
// returns 1 if number is not good. ie. contains at leats one 101 bit sequence
bool checkFive(unsigned long num)
{
unsigned char tmp;
do {
tmp = (unsigned char)num;
if(
(tmp & 7) == 5
|| (tmp & 3) == 3
) // illegal pattern 11 or 101
return true; // found
num >>= 1;
}while(num);
return false;
}
void main(void) {
unsigned long v,num; // count the number of bits set in v
unsigned long c; // c accumulates the total bits set in v
do {
num = (unsigned long)rand() << 16 | rand();
v = num;
// count all 1 bits, Kernigen style
for (c = 0; v; c++)
v &= v - 1; // clear the least significant bit set
}while(c != 10 || checkFive(num));
while(1);
}
The big question for a brilliant mind :)
Can be done faster? Seems that my approach is naive.
Thank you in advance,
Wow, I'm impressed, thanks all for suggestions. However, before accept, I need to test them these days.
Now with the first option (look-up) it's just not realistic, will complete blow my 4K RAM of entire 8051 micro controller :) As you can see in image bellow, I tested for all combinations in Code Blocks but there are way more than 300 and it's not finished yet until 5000 index...
The code I use to test
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
//#define bool bit
//#define true 1
//#define false 0
// returns 1 if number is not good. ie. contains at leats one 101 bit sequence
bool checkFive(uint32_t num)
{
uint8_t tmp;
do {
tmp = (unsigned char)num;
if(
(tmp & 7) == 5
|| (tmp & 3) == 3
) // illegal pattern 11 or 101
return true; // found
num >>= 1;
}while(num);
return false;
}
void main(void) {
uint32_t v,num; // count the number of bits set in v
uint32_t c, count=0; // c accumulates the total bits set in v
//printf("Program started \n");
num = 0;
printf("Program started \n");
for(num=0; num <= 0xFFFFFFFF; num++)
{
//do {
//num = (uint32_t)rand() << 16 | rand();
v = num;
// count all 1 bits, Kernigen style
for (c = 0; v; c++)
v &= v - 1; // clear the least significant bit set
//}while(c != 10 || checkFive(num));
if(c != 10 || checkFive(num))
continue;
count++;
printf("%d: %04X\n", count, num);
}
printf("Complete \n");
while(1);
}
Perhaps I can re-formulate the problem:
I need a number with:
precise (known) amount of 1 bits, 10 in my example
not having 11 or 101 patterns
remaining zeroes can be any
So somehow, shuffle only the 1 bits inside.
Or, take a 0x00000000 and add just 10 of 1 bits in random positions, except the illegal patterns.
Solution
Given a routine r(n) that returns a random integer from 0 (inclusive) to n (exclusive) with uniform distribution, the values described in the question may be generated with a uniform distribution by calls to P(10, 4) where P is:
static uint32_t P(int a, int b)
{
if (a == 0 && b == 0)
return 0;
else
return r(a+b) < a ? P(a-1, b) << 3 | 1 : P(a, b-1) << 1;
}
The required random number generator can be:
static int r(int a)
{
int q;
do
q = rand() / ((RAND_MAX+1u)/a);
while (a <= q);
return q;
}
(The purpose of dividing by (RAND_MAX+1u)/a and the do-while loop is to trim the range of rand to an even multiple of a so that bias due to a non-multiple range is eliminated.)
(The recursion in P may be converted to iteration. This is omitted as it is unnecessary to illustrate the algorithm.)
Discussion
If the number cannot contain consecutive bits 11 or 101, then the closest together two 1 bits can be is three bits apart, as in 1001. Fitting ten 1 bits in 32 bits then requires at least 28 bits, as in 1001001001001001001001001001. Therefore, to satisfy the constraints that there is no 11 or 101 and there are exactly 10 1 bits, the value must be 1001001001001001001001001001 with four 0 bits inserted in some positions (including possibly the beginning or the end).
Selecting such a value is equivalent to placing 10 instances of 001 and 4 instances of 0 in some order.1 There are 14! ways of ordering 14 items, but any of the 10! ways of rearranging the 10 001 instances with each other are identical, and any of the 4! ways of rearranging the 0 instances with each other are identical, so the number of distinct selections is 14! / 10! / 4!, also known as the number of combinations of selecting 10 things from 14. This is 1,001.
To perform such a selection with uniform distribution, we can use a recursive algorithm:
Select the first choice with probability distribution equal to the proportion of the choices in the possible orderings.
Select the remaining choices recursively.
When ordering a instances of one object and b of a second object, a/(a+b) of the potential orderings will start with the first object, and b/(a+b) will start with the second object. Thus, the design of the P routine is:
If there are no objects to put in order, return the empty bit string.
Select a random integer in [0, a+b). If it is less than a (which has probability a/(a+b)), insert the bit string 001 and then recurse to select an order for a-1 instances of 001 and b instances of 0.
Otherwise, insert the bit string 0 and then recurse to select an order for a instances of 001 and b-1 instances of 0.
(Since, once a is zero, only 0 instances are generated, if (a == 0 && b == 0) in P may be changed to if (a == 0). I left it in the former form as that shows the general form of a solution in case other strings are involved.)
Bonus
Here is a program to list all values (although not in ascending order).
#include <stdint.h>
#include <stdio.h>
static void P(uint32_t x, int a, int b)
{
if (a == 0 && b == 0)
printf("0x%x\n", x);
else
{
if (0 < a) P(x << 3 | 1, a-1, b);
if (0 < b) P(x << 1, a, b-1);
}
}
int main(void)
{
P(0, 10, 4);
}
Footnote
1 This formulation means we end up with a string starting 001… rather than 1…, but the resulting value, interpreted as binary, is equivalent, even if there are instances of 0 inserted ahead of it. So the strings with 10 001 and 4 0 are in one-to-one correspondence with the strings with 4 0 inserted into 1001001001001001001001001001.
One way to satisfy your criteria in a limited number of solutions is to utilize the fact that there can be no more that four groups of 000s within the bit population. This also means that there can one be one group of 0000 in the value. Knowing this, you can seed your value with a single 1 in bits 27-31 and then continue adding random bits checking that each bit added satisfies your 3 or 5 constraints.
When adding random bits to your value and satisfying your constraints, there can always be combinations that lead to a solution that can never satisfy all constraints. To protect against those cases, just keep an iteration count and reset/restart the value generation if iterations exceed that value. Here, if a solution is going to be found, it will be found in less than 100 iterations. And is generally found in 1-8 attempts. Meaning for each value you generate, you have on average no more than 800 iterations which will be a far cry less than "97 Seconds or 1165570706 CPU cycles" (I haven't counted cycles, but the return is almost instantaneous)
There are many ways to approach this problem, this is just one that worked in a reasonable amount of time:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <limits.h>
#define BPOP 10
#define NBITS 32
#define LIMIT 100
/** rand_int for use with shuffle */
static int rand_int (int n)
{
int limit = RAND_MAX - RAND_MAX % n, rnd;
rnd = rand();
for (; rnd >= limit; )
rnd = rand();
return rnd % n;
}
int main (void) {
int pop = 0;
unsigned v = 0, n = NBITS;
size_t its = 1;
srand (time (NULL));
/* one of first 5 bits must be set */
v |= 1u << (NBITS - 1 - rand_int (sizeof v + 1));
pop++; /* increment pop count */
while (pop < BPOP) { /* loop until pop count 10 */
if (++its >= LIMIT) { /* check iterations */
#ifdef DEBUG
fprintf (stderr, "failed solution.\n");
#endif
pop = its = 1; /* reset for next iteration */
v = 0;
v |= 1u << (NBITS - 1 - rand_int (sizeof v + 1));
}
unsigned shift = rand_int (NBITS); /* get random shift */
if (v & (1u << shift)) /* if bit already set */
continue;
/* protect against 5 (101) */
if ((shift + 2) < NBITS && v & (1u << (shift + 2)))
continue;
if ((int)(shift - 2) >= 0 && v & (1u << (shift - 2)))
continue;
/* protect against 3 (11) */
if ((shift + 1) < NBITS && v & (1u << (shift + 1)))
continue;
if ((int)(shift - 1) >= 0 && v & (1u << (shift - 1)))
continue;
v |= 1u << shift; /* add bit at shift */
pop++; /* increment pop count */
}
printf ("\nv : 0x%08x\n", v); /* output value */
while (n--) { /* output binary confirmation */
if (n+1 < NBITS && (n+1) % 4 == 0)
putchar ('-');
putchar ((v >> n & 1) ? '1' : '0');
}
putchar ('\n');
#ifdef DEBUG
printf ("\nits: %zu\n", its);
#endif
return 0;
}
(note: you will probably want a better random source like getrandom() or reading from /dev/urandom if you intend to generate multiple random solutions within a loop -- expecially if you are calling the executable in a loop from your shell)
I have also included a DEBUG define that you can enable by adding the -DDEBUG option to your compiler string to see the number of failed solutions and number of iterations on the final.
Example Use/Output
The results for 8 successive runs:
$ ./bin/randbits
v : 0x49124889
0100-1001-0001-0010-0100-1000-1000-1001
v : 0x49124492
0100-1001-0001-0010-0100-0100-1001-0010
v : 0x48492449
0100-1000-0100-1001-0010-0100-0100-1001
v : 0x91249092
1001-0001-0010-0100-1001-0000-1001-0010
v : 0x92488921
1001-0010-0100-1000-1000-1001-0010-0001
v : 0x89092489
1000-1001-0000-1001-0010-0100-1000-1001
v : 0x82491249
1000-0010-0100-1001-0001-0010-0100-1001
v : 0x92448922
1001-0010-0100-0100-1000-1001-0010-0010
As Eric mentioned in his answer, since each 1 but must be separated by at least two 0 bits, you basically start with the 28-bit pattern 1001001001001001001001001001. It's then a matter of placing the remaining four 0 bits within this bit pattern, and there are 11 distinct places to insert each zero.
This can be accomplished by first selecting a random number from 1 to 11 to determine where to place a bit. Then you left shift all the bits above the target bit by 1. Repeat 3 more times, and you have your value.
This can be done as follows:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
void binprint(uint32_t n)
{
int i;
for (i=0;i<32;i++) {
if ( n & (1u << (31 - i))) {
putchar('1');
} else {
putchar('0');
}
}
}
// inserts a 0 bit into val after pos "1" bits are found
uint32_t insert(uint32_t val, int pos)
{
int cnt = 0;
uint32_t mask = 1u << 31;
uint32_t upper, lower;
while (cnt < pos) {
if (val & mask) { // look for a set bit and count if you find one
cnt++;
}
mask >>= 1;
}
if (mask == (1u << 31)) {
return val; // insert at the start: no change
} else if (mask == 0) {
return val << 1; // insert at the end: shift the whole thing by 1
} else {
mask = (mask << 1) - 1; // mask has all bits below the target set
lower = val & mask; // extract the lower portion
upper = val & (~mask); // extract the upper portion
return (upper << 1) | lower; // recombine with the upper portion shifted 1 bit
}
}
int main()
{
int i;
uint32_t val = 01111111111; // hey look, a good use of octal!
srand(time(NULL));
for (i=0;i<4;i++) {
int p = rand() % 11;
printf("p=%d\n", p);
val = insert(val, p);
}
binprint(val);
printf("\n");
return 0;
}
Sample output for two runs:
p=3
p=10
p=9
p=0
01001001000100100100100100100010
...
p=3
p=9
p=3
p=1
10001001000010010010010010010001
Run time is negligible.
Since you don't want a lookup table here is the way:
Basically you have this number with 28 bits set to 0 and 1 in which you need to insert 4x 0 :
0b1001001001001001001001001001
Hence you can use the following algorithm:
int special_rng_nolookup(void)
{
int secret = 0b1001001001001001001001001001;
int low_secret;
int high_secret;
unsigned int i = 28; // len of secret
unsigned int rng;
int mask = 0xffff // equivalent to all bits set in integer
while (i < 32)
{
rng = __asm__ volatile(. // Pseudo code
"rdrand"
);
rng %= (i + 1); // will generate a number between 0 and 28 where you will add a 0. Then between 0 and 29, 30, 31 for the 3 next loop.
low_secret = secret & (mask >> (i - rng)); // locate where you will add your 0 and save the lower part of your number.
high_secret = (secret ^ low_secret) << (!(!rng)); // remove the lower part to your int and shift to insert a 0 between the higher part and the lower part. edit : if rng was 0 you want to add it at the very beginning (left part) so no shift.
secret = high_secret | low_secret; // put them together.
++i;
}
return secret;
}
I have a program that requires me to find primes up till 10**10-1 (10,000,000,000). I wrote a Sieve of Eratosthenes to do this, and it worked very well (and accurately) as high as 10**9 (1,000,000,000). I confirmed its accuracy by having it count the number of primes it found, and it matched the value of 50,847,534 on the chart found here. I used unsigned int as the storage type and it successfully found all the primes in approximately 30 seconds.
However, 10**10 requires that I use a larger storage type: long long int. Once I switched to this, the program is running signifigantly slower (its been 3 hours plus and its still working). Here is the relevant code:
typedef unsigned long long ul_long;
typedef unsigned int u_int;
ul_long max = 10000000000;
u_int blocks = 1250000000;
char memField[1250000000];
char mapBit(char place) { //convert 0->0x80, 1->0x40, 2->0x20, and so on
return 0x80 >> (place);
}
for (u_int i = 2; i*i < max; i++) {
if (memField[i / 8] & activeBit) { //Use correct memory block
for (ul_long n = 2 * i; n < max; n += i) {
char secondaryBit = mapBit(n % 8); //Determine bit position of n
u_int activeByte = n / 8; //Determine correct memory block
if (n < 8) { //Manual override memory block and bit for first block
secondaryBit = mapBit(n);
activeByte = 0;
}
memField[activeByte] &= ~(secondaryBit); //Set the flag to false
}
}
activeBit = activeBit >> 1; //Check the next
if (activeBit == 0x00) activeBit = 0x80;
}
I figure that since 10**10 is 10x larger then 10**9 it should take 10 times the amount of time. Where is the flaw in this? Why did changing to long long cause such significant performance issues and how can I fix this? I recognize that the numbers get larger, so it should be somewhat slower, but only towards the end. Is there something I'm missing.
Note: I realize long int should technically be large enough but my limits.h says it isn't even though I'm compiling 64 bit. Thats why I use long long int in case anyone was wondering. Also, keep in mind, I have no computer science training, just a hobbyist.
edit: just ran it in "Release" as x86-64 with some of the debug statements suggested. I got the following output:
looks like I hit the u_int bound. I don't know why i is getting that large.
Your program has an infinite loop in for (u_int i = 2; i*i < max; i++). i is an unsigned int so i*i wraps at 32-bit and is always less than max. Make i an ul_long.
Note that you should use simpler bit pattern from 1 to 0x80 for bit 0 to 7.
Here is a complete version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef unsigned long long ul_long;
typedef unsigned int u_int;
#define TESTBIT(a, bit) (a[(bit) / 8] & (1 << ((bit) & 7)))
#define CLEARBIT(a, bit) (a[(bit) / 8] &= ~(1 << ((bit) & 7)))
ul_long count_primes(ul_long max) {
size_t blocks = (max + 7) / 8;
unsigned char *memField = malloc(blocks);
if (memField == NULL) {
printf("cannot allocate memory for %llu bytes\n",
(unsigned long long)blocks);
return 0;
}
memset(memField, 255, blocks);
CLEARBIT(memField, 0); // 0 is not prime
CLEARBIT(memField, 1); // 1 is not prime
// clear bits after max
for (ul_long i = max + 1; i < blocks * 8ULL; i++) {
CLEARBIT(memField, i);
}
for (ul_long i = 2; i * i < max; i++) {
if (TESTBIT(memField, i)) { //Check if i is prime
for (ul_long n = 2 * i; n < max; n += i) {
CLEARBIT(memField, n); //Reset all multiples of i
}
}
}
unsigned int bitCount[256];
for (int i = 0; i < 256; i++) {
bitCount[i] = (((i >> 0) & 1) + ((i >> 1) & 1) +
((i >> 2) & 1) + ((i >> 3) & 1) +
((i >> 4) & 1) + ((i >> 5) & 1) +
((i >> 6) & 1) + ((i >> 7) & 1));
}
ul_long count = 0;
for (size_t i = 0; i < blocks; i++) {
count += bitCount[memField[i]];
}
printf("count of primes up to %llu: %llu\n", max, count);
free(memField);
return count;
}
int main(int argc, char *argv[]) {
if (argc > 1) {
for (int i = 1; i < argc; i++) {
count_primes(strtoull(argv[i], NULL, 0));
}
} else {
count_primes(10000000000);
}
return 0;
}
It completes in 10 seconds for 10^9 and 131 seconds for 10^10:
count of primes up to 1000000000: 50847534
count of primes up to 10000000000: 455052511
I want to create a rand() range between 1 and the dynamic value of bit_cnt.
After reading more about the rand() function, I understand that out of the box rand() has a range of [0, RAND_MAX]. I also understand that RAND_MAX's value is library-dependent, but is guaranteed to be at least 32767.
I had to create a bit mask of 64 0s.
Now, I am trying to left shift the bit mask by a dynamic value of bit_cnt anded with the a randomly generated number of bits between 1 and the dynamic value of bit_cnt.
For example, when bit_cnt is 10, I want to randomize the lowest 10 bits.
Originally, I had
mask = (mask << bit_cnt) + (rand()% bit_cnt);
which caused a floating point exception. From what I am understanding, that exception occurred because the value of bit_cntbecame 0.
Therefore, I attempted to create an if statement like this:
if((rand()%bit_cnt))!=0){
mask = (mask << bit_cnt) + (rand()% bit_cnt);
}
,but the floating point exception still occurred.
Then I tried the following thinking that the value not be 0 so increase the value to at least 1:
mask = (mask << bit_cnt) + ((rand()% bit_cnt)+1);
,but the floating point exception still occurred.
Afterwards, I tried the following:
mask = (mask << bit_cnt) + (1+(rand()%(bit_cnt+1)));
and the following 20 lines of 64 bits outputted:
0000000000000000000000000000000000000000000000000000000000000010
0000000000000000000000000000000000000000000000000000000000000011
0000000000000000000000000000000000000000000000000000000000000101
0000000000000000000000000000000000000000000000000000000000001010
0000000000000000000000000000000000000000000000000000000000010011
0000000000000000000000000000000000000000000000000000000000100011
0000000000000000000000000000000000000000000000000000000001000110
0000000000000000000000000000000000000000000000000000000010000100
0000000000000000000000000000000000000000000000000000000100001001
0000000000000000000000000000000000000000000000000000001000000010
0000000000000000000000000000000000000000000000000000010000000100
0000000000000000000000000000000000000000000000000000100000000111
0000000000000000000000000000000000000000000000000001000000000101
0000000000000000000000000000000000000000000000000010000000001001
0000000000000000000000000000000000000000000000000100000000000111
0000000000000000000000000000000000000000000000001000000000001111
0000000000000000000000000000000000000000000000010000000000001010
0000000000000000000000000000000000000000000000100000000000000101
0000000000000000000000000000000000000000000001000000000000001101
0000000000000000000000000000000000000000000010000000000000001100
What was the cause of the floating point exception? Is this how to dynamic create a range of the rand() function?
I appreciate any suggestions. Thank you.
UPDATE:
I changed the if statement to be the following:
if(bit_cnt !=0)
and then performed the rest of the logic.
I received the following output:
0000000000000000000000000000000000000000000000000000000000000001
0000000000000000000000000000000000000000000000000000000000000010
0000000000000000000000000000000000000000000000000000000000000100
0000000000000000000000000000000000000000000000000000000000001000
0000000000000000000000000000000000000000000000000000000000010010
0000000000000000000000000000000000000000000000000000000000100001
0000000000000000000000000000000000000000000000000000000001000100
0000000000000000000000000000000000000000000000000000000010000110
0000000000000000000000000000000000000000000000000000000100000011
0000000000000000000000000000000000000000000000000000001000000000
0000000000000000000000000000000000000000000000000000010000001000
0000000000000000000000000000000000000000000000000000100000000111
0000000000000000000000000000000000000000000000000001000000000110
0000000000000000000000000000000000000000000000000010000000000110
0000000000000000000000000000000000000000000000000100000000001100
0000000000000000000000000000000000000000000000001000000000000010
0000000000000000000000000000000000000000000000010000000000001101
0000000000000000000000000000000000000000000000100000000000000110
0000000000000000000000000000000000000000000001000000000000010000
0000000000000000000000000000000000000000000010000000000000000100
Is there any possible way to know if the range is correct? Like is there any possible way to know by looking at the output?
const int LINE_CNT = 20;
void print_bin(uint64_t num, unsigned int bit_cnt);
uint64_t rand_bits(unsigned int bit_cnt);
int main(int argc, char *argv[]) {
int i;
srand(time(NULL));
for(i = 0; i < LINE_CNT; i++) {
uint64_t val64 = rand_bits(i);
print_bin(val64, 64);
}
return EXIT_SUCCESS;
}
void print_bin(uint64_t num, unsigned int bit_cnt) {
int top_bit_cnt;
if(bit_cnt <= 0) return;
if(bit_cnt > 64) bit_cnt = 64;
top_bit_cnt = 64;
while(top_bit_cnt > bit_cnt) {
top_bit_cnt--;
printf(" ");
}
while(bit_cnt > 0) {
bit_cnt--;
printf("%d", (num & ((uint64_t)1 << bit_cnt)) != 0);
}
printf("\n");
return;
}
uint64_t rand_bits(unsigned int bit_cnt) {
uintmax_t mask = 1;
if (bit_cnt != 0) {
mask = (mask << bit_cnt) + (rand()% bit_cnt);
}
return mask;
}
I am trying to modify the function rand_bits to return all 0 expect for the lowest bits aka bit_cnt which are randomized.
Returns a 64 bit pattern with all zeros except for the lowest requested bits, which are randomized. This allows for arbitrary length random bit patterns in a portable fashion as the C standard "rand()" function is only required to return
random numbers between 0 and 32767... effectively, a random 15 bit pattern.
Parameter, "bit_cnt": How many of the lowest bits, including the lowest order bit (bit 0) to be randomized.
UPDATE: Added Barmar's newest suggestion of mask = rand() % (1 << bit_cnt);:
0000000000000000000000000000000000000000000000000000000000000001
0000000000000000000000000000000000000000000000000000000000000001
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000010
0000000000000000000000000000000000000000000000000000000000001000
0000000000000000000000000000000000000000000000000000000000001001
0000000000000000000000000000000000000000000000000000000000000010
0000000000000000000000000000000000000000000000000000000000010101
0000000000000000000000000000000000000000000000000000000001001111
0000000000000000000000000000000000000000000000000000000010000011
0000000000000000000000000000000000000000000000000000001010101001
0000000000000000000000000000000000000000000000000000010101101100
0000000000000000000000000000000000000000000000000000101011111000
0000000000000000000000000000000000000000000000000001001010101111
0000000000000000000000000000000000000000000000000011101011000101
0000000000000000000000000000000000000000000000000001001101111101
0000000000000000000000000000000000000000000000001111000000111010
0000000000000000000000000000000000000000000000000101100000001100
0000000000000000000000000000000000000000000000100111101000111111
0000000000000000000000000000000000000000000001010101011101000110
uint64_t rand_bits(unsigned int bit_cnt) {
uintmax_t mask = 1;
if (bit_cnt != 0) {
mask = rand() % (1 << bit_cnt);
}
return mask;
}
The problem is that anything % bit_cnt will get an error if bit_cnt is 0. You need to check bit_cnt before you try to perform the modulus.
if (bit_cnt != 0) {
mask = (mask << bit_cnt) + (rand()% bit_cnt) + 1;
}
All your attempts performed the modulus and then tried to do something with the result, but that's after the error happens.
This uses the bit count to generate a mask. If you want a bit count greater than can be filled by RAND_MAX, implement another random function as I commented earlier.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void) {
int bit_cnt = 10;
unsigned mask = 0;
int i;
int num;
srand((unsigned)time(NULL));
for(i = 0; i < bit_cnt; i++)
mask = (mask << 1) | 1;
printf ("For bit_cnt=%d, mask=0x%X\n\n", bit_cnt, mask);
for (i = 0; i < 5; i++) {
num = rand() & mask;
printf("Random number 0x%0*X\n", 1+(bit_cnt-1)/4, num);
}
}
Program output:
For bit_cnt=10, mask=0x3FF
Random number 0x327
Random number 0x39C
Random number 0x1B1
Random number 0x088
Random number 0x26E
What would be the best way to generate a random 32-bit hexadecimal value in C? In my current implementation I am generating each bit separately but the output is not completely random ... many values are repeated several times. Is it better to generate the entire random number instead of generating each bit separately?
The random number should make use of the entire 32 bit address space (0x00000000 to 0xffffffff)
file = fopen(tracefile,"wb"); // create file
for(numberofAddress = 0; numberofAddress<10000; numberofAddress++){ //create 10000 address
if(numberofAddress!=0)
fprintf(file,"\n"); //start a new line, but not on the first one
fprintf(file, "0 ");
int space;
for(space = 0; space<8; space++){ //remove any 0 from the left
hexa_address = rand() % 16;
if(hexa_address != 0){
fprintf(file,"%x", hexa_address);
space++;
break;
}
else if(hexa_address == 0 && space == 7){ //in condition of 00000000
fprintf(file,"%x", "0");
space++;
}
}
for(space; space<8; space++){ //continue generating the remaining address
hexa_address = rand() % 16;
fprintf(file,"%x", hexa_address);
}
}
x = rand() & 0xff;
x |= (rand() & 0xff) << 8;
x |= (rand() & 0xff) << 16;
x |= (rand() & 0xff) << 24;
return x;
rand() doesn't return a full random 32-bit integer. Last time I checked it returned between 0 and 2^15. (I think it's implementation dependent.) So you'll have to call it multiple times and mask it.
Do this way.It creates a bigger number than the earlier logic .If you are interested the MSB then the below logic is good .:
/** x = rand() ^ rand()<<1; **/
#include <algorithm>
#include <string.h>
#include <ctype.h>
#include <stdint.h>
#include <string>
#include <stdio.h>
int main () {
int i, n;
n = 50;
uint x,y ;
//4294967295 :UNIT_MAX
/* Intializes random number generator */
srand((unsigned) time(0));
for( i = 0 ; i < n ; i++ ) {
/**WAY 1 **/
x = rand() ^ rand()<<1;
printf("x:%u\t",x);
printf("Difference1:(4294967295 - %u) = %u\n",x,(4294967295 - x));
/**WAY 2 **/
y = rand() & 0xff;
y |= (rand() & 0xff) << 8;
y |= (rand() & 0xff) << 16;
y |= (rand() & 0xff) << 24;
printf("y:%u\t",y);
printf("Difference2:(4294967295 - %u) = %u\n",y,(4294967295 - y));
printf("Difference between two is = %u\n",(x) - (y));
}
printf("End\n");
return(0);
}
You can just create any random number that's at least 32 bit wide and format that as hex. Examples:
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
uint32_t n;
n = mrand48(); // #1
n = rand(); // #2
FILE * f = fopen("/dev/urandom", "rb");
fread(&n, sizeof(uint32_t), 1, f); // #3
// ... etc. etc. E.g. Windows Crypto API
char hex[9];
sprintf(hex, "%08X", n);
Now hex is a string containing eight random hexadecimal digits. Don't forget to seed the various pseudo random number generators (using srand48() and srand(), respectively, for #1 and #2). Since you'll essentially have to seed the PRNGs from random source with at least one 32-bit integer, you might as well tap the random source directly (unless you're using time() or something "non-random" like that).