Compare commits
42 Commits
v0.7
...
874cc75431
Author | SHA1 | Date | |
---|---|---|---|
874cc75431 | |||
d2e037e357 | |||
90158fb04c | |||
bb26ae9b9f | |||
1b0b8fd443 | |||
e06e40af3b | |||
eaa238a900 | |||
bd3181a1a0 | |||
89811c1d02 | |||
01a32c0e52 | |||
7aceb7fcc7 | |||
3348d52c49 | |||
c73bfd1501 | |||
2afe144e7f | |||
a988711918 | |||
74a82e2038 | |||
659bdeee27 | |||
d39a51baa2 | |||
7fa4d9d2bf | |||
6ed153b9e2 | |||
c8d1c095ba | |||
ae8cbed179 | |||
69028a15c8 | |||
b20733f3ac | |||
2b5541d2c3 | |||
94248612ba | |||
8ee18c8c4b | |||
bdea1979e8 | |||
a3ec19d47c | |||
22239ec644 | |||
22278999e7 | |||
a5b68282b3 | |||
b9cafadf8e | |||
32076a67cd | |||
9673a4da57 | |||
76936644cd | |||
a6ecea514f | |||
22c7702cf0 | |||
f8726497a4 | |||
3e902efd18 | |||
3246870b75 | |||
09166efe89 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -2,8 +2,5 @@
|
|||||||
build/*
|
build/*
|
||||||
!build/.keep
|
!build/.keep
|
||||||
|
|
||||||
# Ignore documentation
|
|
||||||
doc/
|
|
||||||
|
|
||||||
# Ignore vim temporary files
|
# Ignore vim temporary files
|
||||||
*.sw[a-z]
|
*.sw[a-z]
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
image: gcc
|
|
||||||
|
|
||||||
build:
|
|
||||||
stage: build
|
|
||||||
# Install dependencies
|
|
||||||
before_script:
|
|
||||||
- apt update && apt -y install cmake libgmp-dev libgomp1
|
|
||||||
# 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:
|
|
||||||
- "build/CMakeFiles/indivisible.dir/src/*.o"
|
|
@ -1,8 +0,0 @@
|
|||||||
Authors
|
|
||||||
=======
|
|
||||||
These are a list of people that have contributed to the Uhn project.
|
|
||||||
|
|
||||||
| **Name/Alias** | **E-Mail** |
|
|
||||||
|---------------------------|---------------------------------------|
|
|
||||||
| Deathsbreed | deathsbreed@themusicinnoise.net |
|
|
||||||
|
|
10
CHANGELOG
10
CHANGELOG
@ -30,3 +30,13 @@ Change Log
|
|||||||
- v0.7: Data Saving
|
- v0.7: Data Saving
|
||||||
- Allow user to save found primes to be loaded later.
|
- Allow user to save found primes to be loaded later.
|
||||||
- User can save and read primes in raw output.
|
- User can save and read primes in raw output.
|
||||||
|
- v1.0: Parallelization
|
||||||
|
- Now completely parallelized.
|
||||||
|
- Cleaned up/organized the code-base
|
||||||
|
- Exporting files uses less memory
|
||||||
|
- Allow searching for the nth prime number
|
||||||
|
- Clearing some memory leaks
|
||||||
|
- v2.0: Linked List
|
||||||
|
- Implement linked list for faster addition to list.
|
||||||
|
- Multi-Processor support (MPI).
|
||||||
|
- Code cleanup.
|
||||||
|
@ -1,41 +1,66 @@
|
|||||||
cmake_minimum_required(VERSION 2.6)
|
# Copyright (C) 2017 Ortega Froysa, Nicolás <deathsbreed@themusicinnoise.net>
|
||||||
project(Indivisible)
|
# Author: Ortega Froysa, Nicolás <deathsbreed@themusicinnoise.net>
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
cmake_policy(SET CMP0012 OLD)
|
cmake_minimum_required(VERSION 3.0)
|
||||||
|
project(Indivisible C)
|
||||||
|
|
||||||
set(TARGET_NAME indivisible)
|
set(TARGET_NAME indivisible)
|
||||||
|
set(TARGET_VERSION "v2.0")
|
||||||
|
|
||||||
if(NOT CMAKE_BUILD_TYPE)
|
if(NOT CMAKE_BUILD_TYPE)
|
||||||
set(CMAKE_BUILD_TYPE Debug)
|
set(CMAKE_BUILD_TYPE "release")
|
||||||
endif()
|
endif()
|
||||||
|
string(TOLOWER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE)
|
||||||
|
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH
|
set(CMAKE_MODULE_PATH
|
||||||
${CMAKE_MODULE_PATH}
|
${CMAKE_MODULE_PATH}
|
||||||
${CMAKE_SOURCE_DIR}/cmake/)
|
${CMAKE_SOURCE_DIR}/cmake/)
|
||||||
|
|
||||||
find_package(GMP REQUIRED)
|
find_package(GMP REQUIRED)
|
||||||
find_package(OpenMP REQUIRED)
|
find_package(MPI REQUIRED)
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
|
${MPI_C_INCLUDE_PATH}
|
||||||
${GMP_INCLUDE_DIR})
|
${GMP_INCLUDE_DIR})
|
||||||
|
|
||||||
set(SRCS
|
set(SRCS
|
||||||
src/main.c
|
"src/linked_list.c"
|
||||||
src/files.c
|
"src/main.c")
|
||||||
src/list.c)
|
|
||||||
|
|
||||||
# Define the C flags.
|
# Define the C flags.
|
||||||
set(CMAKE_C_FLAGS "-std=gnu99 ${OpenMP_C_FLAGS} -Wall -Wextra -Werror -Wfatal-errors -Wmissing-declarations -pedantic-errors")
|
set(CMAKE_C_FLAGS "-std=gnu99 ${MPI_C_COMPILE_FLAGS} -Wall -Wextra -Werror -Wfatal-errors -Wmissing-declarations -pedantic-errors")
|
||||||
set(CMAKE_C_FLAGS_DEBUG "-g -O0")
|
set(CMAKE_C_FLAGS_DEBUG "-g -O0")
|
||||||
set(CMAKE_C_FLAGS_RELEASE "-O3")
|
set(CMAKE_C_FLAGS_RELEASE "-O3")
|
||||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-g -O3")
|
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-g -O3")
|
||||||
set(CMAKE_C_FLAGS_MINSIZEREL "-Os")
|
set(CMAKE_C_FLAGS_MINSIZEREL "-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")
|
||||||
|
else()
|
||||||
|
add_definitions("-DDEBUG")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_definitions("-DVERSION=\"${TARGET_VERSION}\"")
|
||||||
|
|
||||||
add_executable(${TARGET_NAME} ${SRCS})
|
add_executable(${TARGET_NAME} ${SRCS})
|
||||||
|
|
||||||
target_link_libraries(${TARGET_NAME}
|
target_link_libraries(${TARGET_NAME}
|
||||||
|
${MPI_C_LIBRARIES}
|
||||||
${GMP_LIBRARY})
|
${GMP_LIBRARY})
|
||||||
|
|
||||||
|
install(TARGETS ${TARGET_NAME}
|
||||||
|
RUNTIME DESTINATION "bin")
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
Contributing
|
|
||||||
============
|
|
||||||
We gladly accept contributions to Indivisible, however there are a few guidelines that must be followed.
|
|
||||||
|
|
||||||
1) Copyright & Licensing
|
|
||||||
------------------------
|
|
||||||
The copyright of this project and all of its code, unless stated otherwise, belongs to Nicolás Ortega and is licensed with the [GNU GPLv3](/LICENSE). This also applies to all contributions (contributors may add themselves to the [authors file](/AUTHORS.md) for recognition). This is purely for legal purposes, there is no intention to deny your contributions.
|
|
||||||
|
|
||||||
2) Documentation
|
|
||||||
----------------
|
|
||||||
All new features added must be well documented using DOxygen style comments. If your merge request adds a new feature and it is not well documented we will ask you to finish documenting the code before accepting a merge. This is simply so that both the maintainers of this repo and other users can understand the new API that bas been added.
|
|
||||||
|
|
||||||
3) Code-Style
|
|
||||||
-------------
|
|
||||||
The only aspects that will be religiously upheld for all contributions to this repo are indentation and bracket placement. All indentation must be tab characters (reason being so that everyone can view the code with the indentation that they prefer rather than being forced to see a specific indentation), and brackets must be attached. Everything else is minor and can be overlooked.
|
|
||||||
|
|
||||||
Things that would be nice is if you could avoid having the lines being too long, and please avoid having more than one empty line in a row.
|
|
||||||
|
|
||||||
4) Fractured Merge Requests
|
|
||||||
---------------------------
|
|
||||||
Please make sure your merge requests are fractured into separate parts so that it may be easy for us to deal with them individually. The reason for this is to avoid having merge requests that both fix bugs and add features when in reality they should be separate requests. The only exception to this will be if the changes made to the code depend on one another to function properly.
|
|
||||||
|
|
||||||
If your merge request meets all these requirements and is passed by one of the moderators it will be merged into the main repo.
|
|
32
README
Normal file
32
README
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
===================
|
||||||
|
*** Indivisible ***
|
||||||
|
===================
|
||||||
|
Indivisible is a parallelized prime number generator written in C.
|
||||||
|
|
||||||
|
# Building
|
||||||
|
----------
|
||||||
|
There are multiple dependencies to install before compiling the project:
|
||||||
|
|
||||||
|
- CMake build system
|
||||||
|
- GNU Multi-Precision Arithmetics Library
|
||||||
|
|
||||||
|
Once the dependencies are installed you can compile by running the following
|
||||||
|
from the root directory of the project:
|
||||||
|
|
||||||
|
cd build/
|
||||||
|
cmake ..
|
||||||
|
make
|
||||||
|
|
||||||
|
This will create a release build, to build with debug options append the
|
||||||
|
`-DCMAKE_BUILD_TYPE=debug' flag to the `cmake' command.
|
||||||
|
|
||||||
|
# Contributing
|
||||||
|
--------------
|
||||||
|
To contribute to indivisible you can send patch files to my e-mail[0].
|
||||||
|
|
||||||
|
[0] nortega@themusicinnoise.net
|
||||||
|
|
||||||
|
# License
|
||||||
|
---------
|
||||||
|
This project is licensed under the GNU General Public License version 3 or
|
||||||
|
greater (see `LICENSE' for more information).
|
29
README.md
29
README.md
@ -1,29 +0,0 @@
|
|||||||
Indivisible
|
|
||||||
===========
|
|
||||||
[](https://gitlab.com/Deathsbreed/Indivisible/commits/master)
|
|
||||||
|
|
||||||
Indivisible is an optimized prime number generator written in C.
|
|
||||||
|
|
||||||
Building
|
|
||||||
--------
|
|
||||||
There are multiple dependencies to install before compiling the project:
|
|
||||||
- CMake
|
|
||||||
- GMP
|
|
||||||
- OpenMP
|
|
||||||
|
|
||||||
Once the dependencies are installed you can compile by running the following from the root directory of the project:
|
|
||||||
```bash
|
|
||||||
$ cd build/
|
|
||||||
$ cmake ..
|
|
||||||
$ make
|
|
||||||
```
|
|
||||||
|
|
||||||
To build a release build run `cmake -DCMAKE_BUILD_TYPE=Release ..` instead.
|
|
||||||
|
|
||||||
Contributing
|
|
||||||
------------
|
|
||||||
If you would like to contribute to Uhn then please read the [contributing file](/CONTRIBUTING.md) before creating a merge request.
|
|
||||||
|
|
||||||
License
|
|
||||||
-------
|
|
||||||
This project is licensed with the [GNU GPLv3](/LICENSE). Since it is an educational project I find it very important that all contributions continue to remain free/libre.
|
|
@ -1,3 +0,0 @@
|
|||||||
--lineend=linux
|
|
||||||
--indent=tab
|
|
||||||
--style=attach
|
|
61
src/files.c
61
src/files.c
@ -1,61 +0,0 @@
|
|||||||
#include "files.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <gmp.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
int inputPrimes(char *file, List *list) {
|
|
||||||
// Assert safeguards
|
|
||||||
assert(file != NULL);
|
|
||||||
assert(list != NULL);
|
|
||||||
|
|
||||||
FILE *pFile = fopen(file, "r");
|
|
||||||
if(pFile == NULL) return 1;
|
|
||||||
mpz_t n;
|
|
||||||
mpz_init(n);
|
|
||||||
while(mpz_inp_raw(n, pFile) != 0) addToList(list, n);
|
|
||||||
if(fclose(pFile) != 0) return 2;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int outputPrimes(char *file, List *list) {
|
|
||||||
// Assert safeguards
|
|
||||||
assert(file != NULL);
|
|
||||||
assert(list != NULL);
|
|
||||||
|
|
||||||
FILE *oFile = fopen(file, "w");
|
|
||||||
if(oFile == NULL) return 1;
|
|
||||||
printf("Saving primes to `%s'...\n", file);
|
|
||||||
puts("0%");
|
|
||||||
for(size_t i = 0; i < list->end; ++i) {
|
|
||||||
if(mpz_out_raw(oFile, list->list[i]) == 0) return 3;
|
|
||||||
if(i == list->end / 4) puts("25%");
|
|
||||||
else if(i == list->end / 2) puts("50%");
|
|
||||||
else if(i == list->end * 3 / 4) puts("75%");
|
|
||||||
}
|
|
||||||
puts("100%");
|
|
||||||
if(fclose(oFile) != 0) return 2;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int exportPrimes(char *file, List *list, int base) {
|
|
||||||
// Assert safeguards
|
|
||||||
assert(file != NULL);
|
|
||||||
assert(list != NULL);
|
|
||||||
assert(list->list != NULL);
|
|
||||||
|
|
||||||
FILE *eFile = fopen(file, "w");
|
|
||||||
if(eFile == NULL) return 1;
|
|
||||||
printf("Exporting primes to `%s'...\n", file);
|
|
||||||
puts("0%");
|
|
||||||
for(size_t i = 0; i < list->end; ++i) {
|
|
||||||
if(mpz_out_str(eFile, base, list->list[i]) == 0) return 3;
|
|
||||||
fprintf(eFile, "\n");
|
|
||||||
if(i == list->end / 4) puts("25%");
|
|
||||||
else if(i == list->end / 2) puts("50%");
|
|
||||||
else if(i == list->end * 3 / 4) puts("75%");
|
|
||||||
}
|
|
||||||
puts("100%");
|
|
||||||
if(fclose(eFile) != 0) return 2;
|
|
||||||
puts("Finished exporting primes.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
36
src/files.h
36
src/files.h
@ -1,36 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file files.h
|
|
||||||
* @author Deathsbreed <deathsbreed@themusicinnoise.net>
|
|
||||||
* @brief Functions to deal with file I/O of primes.
|
|
||||||
* @details Functions that input, output, and export primes from/to files.
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
#include "list.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Load primes from an Indivisible file into a List.
|
|
||||||
* @param file File to input primes from.
|
|
||||||
* @param list List to load primes into.
|
|
||||||
* @returns If 0 then load was successful, if 1 then failed to open,
|
|
||||||
* if 2 failed to close.
|
|
||||||
*/
|
|
||||||
int inputPrimes(char *file, List *list);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Output primes from a List into an Indivisible file.
|
|
||||||
* @param file File to output primes to.
|
|
||||||
* @param list List to read primes from.
|
|
||||||
* @returns If 0 then load was successful, if 1 then failed to open,
|
|
||||||
* if 2 failed to close, if 3 failed when writing.
|
|
||||||
*/
|
|
||||||
int outputPrimes(char *file, List *list);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Export primes from a List to a plain text file.
|
|
||||||
* @param file File to output primes as plain text to.
|
|
||||||
* @param list List to read primes from.
|
|
||||||
* @param base The base in which the primes will be written.
|
|
||||||
* @returns If 0 then load was successful, if 1 then failed to open,
|
|
||||||
* if 2 failed to close, if 3 failed when writing.
|
|
||||||
*/
|
|
||||||
int exportPrimes(char *file, List *list, int base);
|
|
61
src/global.h
Normal file
61
src/global.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Ortega Froysa, Nicolás <nortega@themusicinnoise.net>
|
||||||
|
* Author: Ortega Froysa, Nicolás <nortega@themusicinnoise.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef VERSION
|
||||||
|
# define VERSION "version"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* argp variables */
|
||||||
|
const char *argp_program_version = VERSION;
|
||||||
|
const char *argp_program_bug_address = "<nortega@themusicinnoise.net>";
|
||||||
|
|
||||||
|
/* argp options */
|
||||||
|
static char desc[] = "A parallelized prime number generator.";
|
||||||
|
/*static char args_doc[] = "--count=<number> [--verbose]";*/
|
||||||
|
static struct argp_option opts[] = {
|
||||||
|
{ "count", 'c', "number", 0, "The number of primes to generate (default is 1000)", 0},
|
||||||
|
{ "verbose", 'v', 0, 0, "Print out discovered primes", 0 },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct args {
|
||||||
|
size_t count;
|
||||||
|
int verbose;
|
||||||
|
};
|
||||||
|
|
||||||
|
static error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||||
|
struct args *args = state->input;
|
||||||
|
switch(key)
|
||||||
|
{
|
||||||
|
case 'c':
|
||||||
|
args->count = (size_t)atol(arg);
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
args->verbose = 1;
|
||||||
|
break;
|
||||||
|
case ARGP_KEY_ARG:
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return ARGP_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct argp argp = { opts, parse_opt, 0, desc, 0, 0, 0 };
|
65
src/linked_list.c
Normal file
65
src/linked_list.c
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Ortega Froysa, Nicolás <nortega@themusicinnoise.net>
|
||||||
|
* Author: Ortega Froysa, Nicolás <nortega@themusicinnoise.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "linked_list.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
void llist_init(struct llist *list) {
|
||||||
|
list->size = 0;
|
||||||
|
list->first = NULL;
|
||||||
|
list->last = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int llist_add(struct llist *list, mpz_t num) {
|
||||||
|
struct llist_item *item =
|
||||||
|
malloc(sizeof(struct llist_item));
|
||||||
|
if(!item)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
mpz_init(item->num);
|
||||||
|
mpz_set(item->num, num);
|
||||||
|
|
||||||
|
if(!(list->first))
|
||||||
|
{
|
||||||
|
list->first = item;
|
||||||
|
list->last = item;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
list->last->next = item;
|
||||||
|
list->last = item;
|
||||||
|
}
|
||||||
|
list->size++;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void llist_deinit(struct llist *list) {
|
||||||
|
struct llist_item *i = list->first;
|
||||||
|
|
||||||
|
while(i)
|
||||||
|
{
|
||||||
|
mpz_clear(i->num);
|
||||||
|
struct llist_item *next = i->next;
|
||||||
|
free(i);
|
||||||
|
i = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
list->size = 0;
|
||||||
|
}
|
37
src/linked_list.h
Normal file
37
src/linked_list.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Ortega Froysa, Nicolás <nortega@themusicinnoise.net>
|
||||||
|
* Author: Ortega Froysa, Nicolás <nortega@themusicinnoise.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gmp.h>
|
||||||
|
|
||||||
|
struct llist_item {
|
||||||
|
mpz_t num;
|
||||||
|
struct llist_item *prev;
|
||||||
|
struct llist_item *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct llist {
|
||||||
|
struct llist_item *first;
|
||||||
|
struct llist_item *last;
|
||||||
|
size_t size; // size of the list
|
||||||
|
};
|
||||||
|
|
||||||
|
void llist_init(struct llist *list);
|
||||||
|
int llist_add(struct llist *list, mpz_t num);
|
||||||
|
void llist_deinit(struct llist *list);
|
39
src/list.c
39
src/list.c
@ -1,39 +0,0 @@
|
|||||||
#include "list.h"
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the number of elements by which the list expands.
|
|
||||||
*/
|
|
||||||
#define BLOCK_SIZE 1024
|
|
||||||
|
|
||||||
void initList(List *restrict 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 *restrict l) {
|
|
||||||
for(size_t i = 0; i < l->size; ++i) {
|
|
||||||
mpz_clear(l->list[i]);
|
|
||||||
}
|
|
||||||
free(l->list);
|
|
||||||
}
|
|
||||||
|
|
||||||
void addToList(List *l, mpz_t n) {
|
|
||||||
if(l->end == l->size) {
|
|
||||||
l->size += BLOCK_SIZE;
|
|
||||||
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 = tmp;
|
|
||||||
}
|
|
||||||
mpz_init(l->list[l->end]);
|
|
||||||
mpz_set(l->list[l->end++], n);
|
|
||||||
}
|
|
42
src/list.h
42
src/list.h
@ -1,42 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file list.h
|
|
||||||
* @author Deathsbreed <deathsbreed@themusicinnoise.net>
|
|
||||||
* @brief Code responsible for List management.
|
|
||||||
* @details Code responsible for the definition and management of the
|
|
||||||
* List object.
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
#include <gmp.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief An infinitely expanding list type.
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
mpz_t *list; //!< The list of elements
|
|
||||||
size_t size; //!< How many elements are in the list
|
|
||||||
size_t 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.
|
|
||||||
* @param[in] l A pointer to a List type to be initialized.
|
|
||||||
*/
|
|
||||||
void initList(List *restrict 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 *restrict 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);
|
|
274
src/main.c
274
src/main.c
@ -1,224 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Ortega Froysa, Nicolás <nortega@themusicinnoise.net>
|
||||||
|
* Author: Ortega Froysa, Nicolás <nortega@themusicinnoise.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <signal.h>
|
#include <argp.h>
|
||||||
#include <stdbool.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <gmp.h>
|
#include <gmp.h>
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include "global.h"
|
||||||
|
#include "linked_list.h"
|
||||||
#include "list.h"
|
|
||||||
#include "files.h"
|
|
||||||
|
|
||||||
#define VERSION "v0.7"
|
|
||||||
|
|
||||||
static bool run;
|
|
||||||
|
|
||||||
void printUsage(char *progName);
|
|
||||||
void leave();
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
// Variables for argument parsing
|
struct args args = { 1000, 0 };
|
||||||
bool f_help = false,
|
|
||||||
f_version = false,
|
|
||||||
f_quiet = false;
|
|
||||||
int base = 10;
|
|
||||||
char *file = NULL;
|
|
||||||
char *efile = NULL;
|
|
||||||
|
|
||||||
// Parse commandline arguments
|
argp_parse(&argp, argc, argv, 0, 0, &args);
|
||||||
int c;
|
|
||||||
while((c = getopt(argc, argv, "hvqb:f:e:")) != -1) {
|
if(args.count == 0)
|
||||||
switch(c) {
|
{
|
||||||
case 'h':
|
fprintf(stderr, "ERROR: count must be larger than 0.\n");
|
||||||
f_help = true;
|
|
||||||
break;
|
|
||||||
case 'v':
|
|
||||||
f_version = true;
|
|
||||||
break;
|
|
||||||
case 'q':
|
|
||||||
f_quiet = true;
|
|
||||||
break;
|
|
||||||
case 'b':
|
|
||||||
base = atoi(optarg);
|
|
||||||
if(base < 2 || base > 62) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"Invalid base `%d'. Base must be between 2 and 62.\n",
|
|
||||||
base);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
file = optarg;
|
|
||||||
break;
|
|
||||||
case 'e':
|
|
||||||
efile = optarg;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printUsage(argv[0]);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct llist prime_list;
|
||||||
|
llist_init(&prime_list);
|
||||||
|
|
||||||
|
{
|
||||||
|
// initialize the list with 2
|
||||||
|
mpz_t tmp;
|
||||||
|
mpz_init(tmp);
|
||||||
|
mpz_set_ui(tmp, 2);
|
||||||
|
llist_add(&prime_list, tmp);
|
||||||
|
mpz_clear(tmp);
|
||||||
|
if(args.verbose)
|
||||||
|
puts("2");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Act based on which flags were used
|
mpz_t aux;
|
||||||
if(f_help) {
|
mpz_init(aux);
|
||||||
printUsage(argv[0]);
|
mpz_set_ui(aux, 3);
|
||||||
puts(" -h print this help information");
|
while(prime_list.size < args.count)
|
||||||
puts(" -v print version number of program");
|
{
|
||||||
puts(" -q quiet mode");
|
struct llist_item *item = prime_list.first;
|
||||||
puts(" -b <base> base in which to print primes between 2 and 62 (default 10)");
|
int is_prime = 1;
|
||||||
puts(" -f <file> file in/from which primes are stored and read from in raw format");
|
|
||||||
puts(" -e <file> export input file to plain text format");
|
mpz_t root;
|
||||||
return 0;
|
mpz_init(root);
|
||||||
} else if(f_version) {
|
mpz_sqrt(root, aux);
|
||||||
printf("Indivisible %s\n", VERSION);
|
while(item && mpz_cmp(item->num, root) < 0)
|
||||||
return 0;
|
{
|
||||||
|
if(mpz_divisible_p(aux, item->num))
|
||||||
|
{
|
||||||
|
is_prime = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
item = item->next;
|
||||||
// Quit on ^C by setting `run = false'
|
|
||||||
run = true;
|
|
||||||
signal(SIGINT, leave);
|
|
||||||
|
|
||||||
if(efile != NULL && file == NULL) {
|
|
||||||
fprintf(stderr, "There must be an input file to export! Use `-h' for help.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
bool newFile = true;
|
|
||||||
if(file != NULL) {
|
|
||||||
struct stat s;
|
|
||||||
if(stat(file, &s) == 0) newFile = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int exitCode = 0;
|
|
||||||
|
|
||||||
// Primes we've found
|
|
||||||
List primes;
|
|
||||||
initList(&primes);
|
|
||||||
|
|
||||||
// The number we're going to be testing for
|
|
||||||
mpz_t num;
|
|
||||||
mpz_init(num);
|
|
||||||
|
|
||||||
// Variable for half `num'
|
|
||||||
mpz_t halfNum;
|
|
||||||
mpz_init(halfNum);
|
|
||||||
|
|
||||||
if(efile == NULL) puts("Use Ctrl+C to exit.");
|
|
||||||
|
|
||||||
if(newFile) {
|
|
||||||
// Add 2, a known prime to this list
|
|
||||||
mpz_set_ui(num, 2);
|
|
||||||
addToList(&primes, num);
|
|
||||||
if(!f_quiet) {
|
|
||||||
if(mpz_out_str(stdout, base, num) == 0) {
|
|
||||||
fprintf(stderr, "Could not print to `stdout'!\n");
|
|
||||||
exitCode = 1;
|
|
||||||
goto releaseMemory;
|
|
||||||
}
|
}
|
||||||
|
if(is_prime)
|
||||||
|
{
|
||||||
|
llist_add(&prime_list, aux);
|
||||||
|
if(args.verbose)
|
||||||
|
{
|
||||||
|
mpz_out_str(stdout, 10, aux);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
mpz_add_ui(num, num, 1);
|
|
||||||
} else {
|
|
||||||
// Load primes from file
|
|
||||||
int err = inputPrimes(file, &primes);
|
|
||||||
|
|
||||||
if(err == 0) {
|
|
||||||
printf("Loaded %zu primes.\n", primes.end);
|
|
||||||
} else {
|
|
||||||
if(err == 1)
|
|
||||||
fprintf(stderr, "Failed to open Indivisible file `%s'.\n", file);
|
|
||||||
else if(err == 2)
|
|
||||||
fprintf(stderr, "Failed to close Indivisible file `%s'.\n", file);
|
|
||||||
exitCode = 1;
|
|
||||||
goto releaseMemory;
|
|
||||||
}
|
}
|
||||||
/**
|
mpz_add_ui(aux, aux, 2);
|
||||||
* Yes, I realize there's a -1 here, I don't know why but it won't
|
|
||||||
* work if it's not there, so don't change it unless necessary.
|
|
||||||
*/
|
|
||||||
mpz_set(num, primes.list[primes.end-1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(efile != NULL) {
|
printf("The %zu prime is ", prime_list.size);
|
||||||
int err = exportPrimes(efile, &primes, base);
|
mpz_out_str(stdout, 10, prime_list.last->num);
|
||||||
|
|
||||||
if(err == 0) {
|
|
||||||
puts("Successfully exported primes.");
|
|
||||||
} else {
|
|
||||||
if(err == 1)
|
|
||||||
fprintf(stderr, "Failed to open/create plain text file `%s'.\n", efile);
|
|
||||||
else if(err == 2)
|
|
||||||
fprintf(stderr, "Failed to close plain text file `%s'.\n", efile);
|
|
||||||
else if(err == 3)
|
|
||||||
fprintf(stderr, "Failed to write prime to plain text file `%s'.\n", efile);
|
|
||||||
exitCode = 1;
|
|
||||||
}
|
|
||||||
goto releaseMemory;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
// Calculate half of `num'
|
|
||||||
mpz_fdiv_q_ui(halfNum, num, 2);
|
|
||||||
/**
|
|
||||||
* Loop through primes we've found until we get to half of the number
|
|
||||||
* we're analyzing
|
|
||||||
*/
|
|
||||||
for(size_t i = 0; mpz_cmp(primes.list[i], halfNum) < 0; ++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(!f_quiet) {
|
|
||||||
if(mpz_out_str(stdout, base, num) == 0) {
|
|
||||||
fprintf(stderr, "Could not print to `stdout'!\n");
|
|
||||||
exitCode = 1;
|
|
||||||
goto releaseMemory;
|
|
||||||
}
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
|
llist_deinit(&prime_list);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
nextPrime:
|
|
||||||
// Add 2 (skip even numbers since they're all divisible by 2)
|
|
||||||
mpz_add_ui(num, num, 2);
|
|
||||||
} while(run);
|
|
||||||
|
|
||||||
printf("Found %zu primes.\n", primes.end);
|
|
||||||
|
|
||||||
if(file != NULL) {
|
|
||||||
int err = outputPrimes(file, &primes);
|
|
||||||
if(err == 0) {
|
|
||||||
puts("Successfully saved primes.");
|
|
||||||
} else {
|
|
||||||
if(err == 1)
|
|
||||||
fprintf(stderr, "Failed to open/create file `%s'.\n", file);
|
|
||||||
else if(err == 2)
|
|
||||||
fprintf(stderr, "Failed to close file `%s'.\n", file);
|
|
||||||
else if(err == 3)
|
|
||||||
fprintf(stderr, "Failed while writing a prime to `%s'.\n", file);
|
|
||||||
exitCode = 1;
|
|
||||||
goto releaseMemory;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear GMP variables
|
|
||||||
mpz_clear(halfNum);
|
|
||||||
mpz_clear(num);
|
|
||||||
|
|
||||||
releaseMemory:
|
|
||||||
puts("Clearing memory...");
|
|
||||||
// Deinitialize the list
|
|
||||||
deInitList(&primes);
|
|
||||||
|
|
||||||
puts("Exit successful.");
|
|
||||||
return exitCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
void printUsage(char *progName) {
|
|
||||||
printf("%s [OPTIONS]\n", progName);
|
|
||||||
}
|
|
||||||
|
|
||||||
void leave() { run = false; }
|
|
||||||
|
Reference in New Issue
Block a user