From 79a9ba11ffedd02929a2a523188c4bec4e3154bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20A=2E=20Ortega?= Date: Fri, 9 Dec 2016 23:02:51 +0100 Subject: [PATCH] Switch to C, stop using OpenMP, start using GMP. --- .gitlab-ci.yml | 9 ++++++- CMakeLists.txt | 15 +++++------ README.md | 7 ++++-- src/Main.cpp | 52 -------------------------------------- src/list.c | 44 ++++++++++++++++++++++++++++++++ src/list.h | 36 +++++++++++++++++++++++++++ src/main.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ src/optimizers.h | 3 +++ 8 files changed, 169 insertions(+), 62 deletions(-) delete mode 100644 src/Main.cpp create mode 100644 src/list.c create mode 100644 src/list.h create mode 100644 src/main.c create mode 100644 src/optimizers.h diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 51ce770..073eef2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,12 +2,19 @@ image: gcc build: stage: build + # Install dependencies before_script: - - apt update && apt -y install cmake libgomp1 libgmp-dev + - apt update && apt -y install cmake libgmp-dev + # Build the project script: - cd build/ - cmake -DCMAKE_BUILD_TYPE=Release .. - make + # Find the resulting binary artifacts: paths: - build/indivisible + # Cache .o files for faster compiling + cache: + paths: + - "*.o" diff --git a/CMakeLists.txt b/CMakeLists.txt index e5db0e6..bf5e3ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,20 +13,21 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake/) -find_package(OpenMP REQUIRED) find_package(GMP REQUIRED) include_directories( ${GMP_INCLUDE_DIR}) 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") -set(CMAKE_CXX_FLAGS_RELEASE "-O3") -set(CMAKE_CXX_FLAGS_DEBUG "-g -O0") -set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-g -O3") -set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os") +# Define the C flags. +set(CMAKE_C_FLAGS "-std=gnu99 -Wall -Wextra -Werror -Wfatal-errors -Wmissing-declarations -pedantic-errors") +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -g -O0") +set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -O3") +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) add_definitions(-DNDEBUG) diff --git a/README.md b/README.md index 3d8df55..81e3afd 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,15 @@ Indivisible =========== [![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 -------- -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 $ cd build/ $ cmake .. diff --git a/src/Main.cpp b/src/Main.cpp deleted file mode 100644 index ee10780..0000000 --- a/src/Main.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include -#include -#include -#include - -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 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; -} diff --git a/src/list.c b/src/list.c new file mode 100644 index 0000000..de163b3 --- /dev/null +++ b/src/list.c @@ -0,0 +1,44 @@ +#include "list.h" +#include +#include + +#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); +} diff --git a/src/list.h b/src/list.h new file mode 100644 index 0000000..5e45018 --- /dev/null +++ b/src/list.h @@ -0,0 +1,36 @@ +#pragma once +#include +#include + +/** + * @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); diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..42a3d67 --- /dev/null +++ b/src/main.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include + +#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; +} diff --git a/src/optimizers.h b/src/optimizers.h new file mode 100644 index 0000000..c743819 --- /dev/null +++ b/src/optimizers.h @@ -0,0 +1,3 @@ +#pragma once +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0)