Switch to C, stop using OpenMP, start using GMP.

This commit is contained in:
Nicolás A. Ortega 2016-12-09 23:02:51 +01:00
parent 05c50652b8
commit 79a9ba11ff
No known key found for this signature in database
GPG Key ID: 614272579C2070D1
8 changed files with 169 additions and 62 deletions

View File

@ -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"

View File

@ -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)

View File

@ -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 ..

View File

@ -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
View 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
View 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
View 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
View File

@ -0,0 +1,3 @@
#pragma once
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)