Switch to C, stop using OpenMP, start using GMP.
This commit is contained in:
parent
05c50652b8
commit
79a9ba11ff
@ -2,12 +2,19 @@ image: gcc
|
|||||||
|
|
||||||
build:
|
build:
|
||||||
stage: build
|
stage: build
|
||||||
|
# Install dependencies
|
||||||
before_script:
|
before_script:
|
||||||
- apt update && apt -y install cmake libgomp1 libgmp-dev
|
- apt update && apt -y install cmake libgmp-dev
|
||||||
|
# Build the project
|
||||||
script:
|
script:
|
||||||
- cd build/
|
- cd build/
|
||||||
- cmake -DCMAKE_BUILD_TYPE=Release ..
|
- cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||||
- make
|
- make
|
||||||
|
# Find the resulting binary
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- build/indivisible
|
- build/indivisible
|
||||||
|
# Cache .o files for faster compiling
|
||||||
|
cache:
|
||||||
|
paths:
|
||||||
|
- "*.o"
|
||||||
|
@ -13,20 +13,21 @@ set(CMAKE_MODULE_PATH
|
|||||||
${CMAKE_MODULE_PATH}
|
${CMAKE_MODULE_PATH}
|
||||||
${CMAKE_SOURCE_DIR}/cmake/)
|
${CMAKE_SOURCE_DIR}/cmake/)
|
||||||
|
|
||||||
find_package(OpenMP REQUIRED)
|
|
||||||
find_package(GMP REQUIRED)
|
find_package(GMP REQUIRED)
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
${GMP_INCLUDE_DIR})
|
${GMP_INCLUDE_DIR})
|
||||||
|
|
||||||
set(SRCS
|
set(SRCS
|
||||||
src/Main.cpp)
|
src/main.c
|
||||||
|
src/list.c)
|
||||||
|
|
||||||
set(CMAKE_CXX_FLAGS "-std=c++11 ${OpenMP_CXX_FLAGS} -fno-elide-constructors -pedantic-errors -Wall -Wextra -Werror -Wpedantic -Winit-self -Wmissing-declarations -Wuninitialized -Wfatal-errors")
|
# Define the C flags.
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
|
set(CMAKE_C_FLAGS "-std=gnu99 -Wall -Wextra -Werror -Wfatal-errors -Wmissing-declarations -pedantic-errors")
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0")
|
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -g -O0")
|
||||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-g -O3")
|
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -O3")
|
||||||
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os")
|
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS} -g -O3")
|
||||||
|
set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS} -Os")
|
||||||
|
|
||||||
if(NOT CMAKE_BUILD_TYPE MATCHES Debug AND NOT CMAKE_BUILD_TYPE MATCHES RelWithDebInfo)
|
if(NOT CMAKE_BUILD_TYPE MATCHES Debug AND NOT CMAKE_BUILD_TYPE MATCHES RelWithDebInfo)
|
||||||
add_definitions(-DNDEBUG)
|
add_definitions(-DNDEBUG)
|
||||||
|
@ -2,12 +2,15 @@ Indivisible
|
|||||||
===========
|
===========
|
||||||
[![build status](https://gitlab.com/Deathsbreed/Indivisible/badges/master/build.svg)](https://gitlab.com/Deathsbreed/Indivisible/commits/master)
|
[![build status](https://gitlab.com/Deathsbreed/Indivisible/badges/master/build.svg)](https://gitlab.com/Deathsbreed/Indivisible/commits/master)
|
||||||
|
|
||||||
Indivisible is an optimized prime number generator written in C++.
|
Indivisible is an optimized prime number generator written in C.
|
||||||
|
|
||||||
Building
|
Building
|
||||||
--------
|
--------
|
||||||
This project uses CMake to build and depends on OpenMP.
|
There are multiple dependencies to install before compiling the project:
|
||||||
|
- CMake
|
||||||
|
- GMP
|
||||||
|
|
||||||
|
Once the dependencies are installed you can compile by running the following from the root directory of the project:
|
||||||
```bash
|
```bash
|
||||||
$ cd build/
|
$ cd build/
|
||||||
$ cmake ..
|
$ cmake ..
|
||||||
|
52
src/Main.cpp
52
src/Main.cpp
@ -1,52 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <omp.h>
|
|
||||||
#include <vector>
|
|
||||||
#include <csignal>
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
static bool run;
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
std::cout << "Indivisible v0.1\n";
|
|
||||||
run = true;
|
|
||||||
|
|
||||||
signal(SIGINT, [](int signum) {
|
|
||||||
std::cout << "Exiting (" << signum << ")\n";
|
|
||||||
run = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
std::vector<unsigned long long> primes;
|
|
||||||
primes.push_back(2);
|
|
||||||
unsigned long long num = 3;
|
|
||||||
|
|
||||||
// Use for to accomodate for OpenMP
|
|
||||||
#pragma omp parallel
|
|
||||||
{
|
|
||||||
do {
|
|
||||||
unsigned long long myNum;
|
|
||||||
#pragma omp critical
|
|
||||||
{
|
|
||||||
myNum = num;
|
|
||||||
num += 2;
|
|
||||||
}
|
|
||||||
bool isPrime = true;
|
|
||||||
#pragma omp barrier
|
|
||||||
for(auto i : primes) {
|
|
||||||
if(i > myNum / 2) break;
|
|
||||||
if(myNum % i == 0) {
|
|
||||||
isPrime = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(isPrime) {
|
|
||||||
#pragma omp critical
|
|
||||||
{
|
|
||||||
primes.push_back(num);
|
|
||||||
std::cout << num << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while(run);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
44
src/list.c
Normal file
44
src/list.c
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#include "list.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "optimizers.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the number of elements by which the list expands.
|
||||||
|
* WARNING: Always use doubles for this number (2^X)
|
||||||
|
*/
|
||||||
|
#define BLOCK_SIZE 1024
|
||||||
|
|
||||||
|
void initList(List *l) {
|
||||||
|
l->list = malloc(sizeof(mpz_t) * BLOCK_SIZE);
|
||||||
|
if(!l->list) {
|
||||||
|
fprintf(stderr, "Failed to allocate memory to list!\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
l->size = BLOCK_SIZE;
|
||||||
|
l->end = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deInitList(List *l) {
|
||||||
|
free(l->list);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addToList(List *l, mpz_t n) {
|
||||||
|
if(l->end == l->size) {
|
||||||
|
l->size += BLOCK_SIZE;
|
||||||
|
if(unlikely(l->size == 0)) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"size has reached limit of `long long int' type!\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
void *tmp = realloc(l->list, sizeof(mpz_t) * l->size);
|
||||||
|
if(!tmp) {
|
||||||
|
fprintf(stderr, "Failed to allocate more memory to list!\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
l->list = (mpz_t*)tmp;
|
||||||
|
}
|
||||||
|
mpz_init(l->list[l->end]);
|
||||||
|
mpz_set(l->list[l->end++], n);
|
||||||
|
}
|
36
src/list.h
Normal file
36
src/list.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <gmp.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief An infinitely expanding list type.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
mpz_t *list; //!< The list of elements
|
||||||
|
unsigned long long int size; //!< How many elements are in the list
|
||||||
|
unsigned long long int end; //!< The last element of the list (in use)
|
||||||
|
} List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize a List.
|
||||||
|
* @details Initialize the list and its variables, allocating memory
|
||||||
|
* to the pointer array inside. Returns true on success and false on
|
||||||
|
* failure.
|
||||||
|
* @param[in] l A pointer to a List type to be initialized.
|
||||||
|
*/
|
||||||
|
void initList(List *l);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deinitialize a List.
|
||||||
|
* @details Release all memory that has been allocated to the list.
|
||||||
|
* @param[in] l A pointer to a List type to be deinitialized.
|
||||||
|
*/
|
||||||
|
void deInitList(List *l);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new item to a List type.
|
||||||
|
* @details Add item `n' at the end of a List type.
|
||||||
|
* @param[out] l List to which the variable should be appended.
|
||||||
|
* @param[in] n variable to be appended to the list.
|
||||||
|
*/
|
||||||
|
void addToList(List *l, mpz_t n);
|
65
src/main.c
Normal file
65
src/main.c
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <gmp.h>
|
||||||
|
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
|
static bool run;
|
||||||
|
void leave();
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
printf("Indivisible v0.2\n");
|
||||||
|
|
||||||
|
// Quit on ^C by setting `run = false'
|
||||||
|
run = true;
|
||||||
|
signal(SIGINT, leave);
|
||||||
|
|
||||||
|
// Primes we've found
|
||||||
|
List primes;
|
||||||
|
initList(&primes);
|
||||||
|
|
||||||
|
// The number we're going to be testing for
|
||||||
|
mpz_t num;
|
||||||
|
mpz_init(num);
|
||||||
|
|
||||||
|
// Add 2, a known prime to this list
|
||||||
|
mpz_set_ui(num, 2);
|
||||||
|
addToList(&primes, num);
|
||||||
|
if(mpz_out_str(stdout, 10, num) == 0) {
|
||||||
|
fprintf(stderr, "Could not print to `stdout'!\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
mpz_add_ui(num, num, 1);
|
||||||
|
|
||||||
|
do {
|
||||||
|
// Loop through found primes
|
||||||
|
for(unsigned long long int i = 0; i < primes.size; ++i) {
|
||||||
|
// If `num' is divisible by a prime then go to the next number
|
||||||
|
if(mpz_divisible_p(num, primes.list[i]) != 0) goto nextPrime;
|
||||||
|
}
|
||||||
|
|
||||||
|
// `num' is a prime so we add it to the list and print it
|
||||||
|
addToList(&primes, num);
|
||||||
|
if(mpz_out_str(stdout, 10, num) == 0) {
|
||||||
|
fprintf(stderr, "Could not print to `stdout'!\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
nextPrime:
|
||||||
|
// Add 2 (skip even numbers since they're all divisible by 2)
|
||||||
|
mpz_add_ui(num, num, 2);
|
||||||
|
} while(run);
|
||||||
|
|
||||||
|
// Deinitialize the list
|
||||||
|
deInitList(&primes);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void leave() {
|
||||||
|
printf("Exiting...\n");
|
||||||
|
run = false;
|
||||||
|
}
|
3
src/optimizers.h
Normal file
3
src/optimizers.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
#define likely(x) __builtin_expect(!!(x), 1)
|
||||||
|
#define unlikely(x) __builtin_expect(!!(x), 0)
|
Loading…
Reference in New Issue
Block a user