Skip to content

Commit

Permalink
Switch to uint8_t, some optimizations (#979)
Browse files Browse the repository at this point in the history
  • Loading branch information
davepl authored Oct 20, 2024
1 parent 57a5077 commit 887109f
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 60 deletions.
111 changes: 51 additions & 60 deletions PrimeCPP/solution_2/PrimeCPP_PAR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,80 +24,64 @@ using namespace std::chrono;
const uint64_t DEFAULT_UPPER_LIMIT = 10'000'000LLU;

class BitArray {
uint32_t *array;
size_t arrSize;
uint8_t *array;
size_t logicalSize;

inline static size_t arraySize(size_t size)
static constexpr size_t arraySize(size_t size)
{
return (size >> 5) + ((size & 31) > 0);
return (size >> 3) + ((size & 7) > 0);
}

inline static size_t index(size_t n)
static constexpr size_t index(size_t n)
{
return (n >> 5);
}

inline static uint32_t getSubindex(size_t n, uint32_t d)
{
return d & uint32_t(uint32_t(0x01) << (n % 32));
}

inline void setFalseSubindex(size_t n, uint32_t &d)
{
d &= ~uint32_t(uint32_t(0x01) << (n % (8*sizeof(uint32_t))));
return (n >> 3);
}

public:
explicit BitArray(size_t size) : arrSize(size)
explicit BitArray(size_t size) : logicalSize(size)
{
array = new uint32_t[arraySize(size)];
std::memset(array, 0xFF, (size >> 3) + ((size & 7) > 0));
auto arrSize = (size + 1) / 2; // Only store bits for odd numbers
array = new uint8_t[arraySize(arrSize)];
std::memset(array, 0x00, arraySize(arrSize));
}

~BitArray() {delete [] array;}
~BitArray() { delete[] array; }

bool get(size_t n) const
constexpr bool get(size_t n) const
{
return getSubindex(n, array[index(n)]);
if (n % 2 == 0)
return false; // Even numbers > 2 are not prime
n = n / 2; // Map the actual number to the index in the array
return !(array[index(n)] & (uint8_t(1) << (n % 8)));
}

static constexpr uint32_t rol(uint32_t x, uint32_t n)
void set(size_t n)
{
return (x<<n) | (x>>(32-n));
n = n / 2; // Map the actual number to the index in the array
array[index(n)] |= (uint8_t(1) << (n % 8));
}

void setFlagsFalse(size_t n, size_t skip)
constexpr size_t size() const
{
auto rolling_mask = ~uint32_t(1 << n % 32);
auto roll_bits = skip % 32;
while (n < arrSize) {
array[index(n)] &= rolling_mask;
n += skip;
rolling_mask = rol(rolling_mask, roll_bits);
}
}

inline size_t size() const
{
return arrSize;
return logicalSize;
}
};


// prime_sieve
//
// Represents the data comprising the sieve (an array of N bits, where N is the upper limit prime being tested)
// as well as the code needed to eliminate non-primes from its array, which you perform by calling runSieve.
// Represents the data comprising the sieve (an array of bits representing odd numbers starting from 3)
// and includes the code needed to eliminate non-primes from its array by calling runSieve.

class prime_sieve
{
private:

BitArray Bits; // Sieve data, where 1==prime, 0==not
BitArray Bits; // Sieve data, where 0==prime, 1==not

public:

prime_sieve(uint64_t n) : Bits(n) // Initialize all to true (potential primes)
prime_sieve(uint64_t n) : Bits(n) // Initialize bits to zero default
{
}

Expand All @@ -117,15 +101,21 @@ class prime_sieve

while (factor <= q)
{
for (uint64_t num = factor; num < Bits.size(); num += 2)
// Find the next prime number
for (; factor <= q; factor += 2)
{
if (Bits.get(num))
if (Bits.get(factor))
{
factor = num;
break;
}
}
Bits.setFlagsFalse(factor * factor, factor + factor);

// Mark multiples of the prime number as not prime
uint64_t start = factor * factor;
for (uint64_t num = start; num <= Bits.size(); num += factor * 2)
{
Bits.set(num);
}

factor += 2;
}
Expand All @@ -137,9 +127,9 @@ class prime_sieve

size_t countPrimes() const
{
size_t count = (Bits.size() >= 2); // Count 2 as prime if within range
for (int i = 3; i < Bits.size(); i+=2)
if (Bits.get(i))
size_t count = (Bits.size() >= 2); // Count 2 as prime if within range
for (uint64_t num = 3; num <= Bits.size(); num += 2)
if (Bits.get(num))
count++;
return count;
}
Expand All @@ -150,23 +140,24 @@ class prime_sieve

bool isPrime(uint64_t n) const
{
if (n & 1)
return Bits.get(n);
else
if (n == 2)
return true;
if (n < 2 || n % 2 == 0)
return false;
return Bits.get(n);
}

// validateResults
//
// Checks to see if the number of primes found matches what we should expect. This data isn't used in the
// Checks to see if the number of primes found matches what we should expect. This data isn't used in the
// sieve processing at all, only to sanity check that the results are right when done.

bool validateResults() const
{
const std::map<const uint64_t, const int> resultsDictionary =
{
{ 10LLU, 4 }, // Historical data for validating our results - the number of primes
{ 100LLU, 25 }, // to be found under some limit, such as 168 primes under 1000
{ 10LLU, 4 }, // Historical data for validating our results - the number of primes
{ 100LLU, 25 }, // to be found under some limit, such as 168 primes under 1000
{ 1'000LLU, 168 },
{ 10'000LLU, 1229 },
{ 100'000LLU, 9592 },
Expand All @@ -190,8 +181,8 @@ class prime_sieve
if (showResults)
cout << "2, ";

size_t count = (Bits.size() >= 2); // Count 2 as prime if in range
for (uint64_t num = 3; num <= Bits.size(); num+=2)
size_t count = (Bits.size() >= 2); // Count 2 as prime if in range
for (uint64_t num = 3; num <= Bits.size(); num += 2)
{
if (Bits.get(num))
{
Expand All @@ -210,7 +201,7 @@ class prime_sieve
<< "Average: " << duration/passes << ", "
<< "Limit: " << Bits.size() << ", "
<< "Counts: " << count << "/" << countPrimes() << ", "
<< "Valid : " << (validateResults() ? "Pass" : "FAIL!")
<< "Valid: " << (validateResults() ? "Pass" : "FAIL!")
<< "\n";

// Following 2 lines added by rbergen to conform to drag race output format
Expand Down Expand Up @@ -317,7 +308,7 @@ int main(int argc, char **argv)
}

if (bOneshot)
cout << "Oneshot is on. A single pass will be used to simulate a 5 second run." << endl;
cout << "Oneshot is on. A single pass will be used to simulate a 5 second run." << endl;

if (bOneshot && (cSecondsRequested > 0 || cThreadsRequested > 1))
{
Expand Down Expand Up @@ -352,8 +343,8 @@ int main(int argc, char **argv)
else
{
auto tStart = steady_clock::now();
std::thread threads[cThreads];
uint64_t l_passes[cThreads];
std::vector<std::thread> threads(cThreads);
std::vector<uint64_t> l_passes(cThreads);
for (unsigned int i = 0; i < cThreads; i++)
threads[i] = std::thread([i, &l_passes, &tStart](size_t llUpperLimit)
{
Expand Down
Binary file added PrimeCPP/solution_2/primes_par.exe
Binary file not shown.

0 comments on commit 887109f

Please sign in to comment.