diff --git a/C/Makefile b/C/Makefile index 5217fc5..e792fa9 100644 --- a/C/Makefile +++ b/C/Makefile @@ -15,8 +15,14 @@ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +UNAME := $(shell uname) + CC = clang +ifeq ($(UNAME), Linux) CC_FLAGS = -Wfatal-errors -Wall -Wextra -Wpedantic -Wconversion -Wshadow -lm +else +CC_FLAGS = -Wfatal-errors -Wall -Wextra -Wpedantic -Wconversion -Wshadow +endif # Final binary BIN = cmain @@ -25,7 +31,7 @@ BIN = cmain BUILD_DIR = ./build # List of all .c source files. -CCS = main.c $(wildcard *.c) +CCS = $(wildcard *.c) # All .o files go to build dir. OBJ = $(CCS:%.c=$(BUILD_DIR)/%.o) diff --git a/C/main.c b/C/main.c index 359b10c..7ddbc75 100644 --- a/C/main.c +++ b/C/main.c @@ -18,20 +18,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "neural.h" -#include +#include "ttt.h" +#include "util.h" #include - -uint32_t P = 2147483647; -uint32_t A = 16807; -uint32_t current = 1; - -double Rand() { - current = current * A % P; - double result = (double)current / P; - return result; -} - -void print_network(const Network* network); +#include static uint32_t xor(uint32_t i, uint32_t j) { return i ^ j; } static uint32_t xnor(uint32_t i, uint32_t j) { return 1 - xor(i, j); } @@ -42,86 +32,65 @@ static uint32_t nand(uint32_t i, uint32_t j) { return 1 - and(i, j); } const int ITERS = 4000; -int main() { - Network network = {0}; - network_init(&network, 2, 2, 6, Rand); - Trainer trainer = {0}; - trainer_init(&trainer, &network); - double inputs[4][2] = { - {0, 0}, - {0, 1}, - {1, 0}, - {1, 1} - }; - double outputs[4][6] = { - { xor(0, 0), xnor(0, 0), or(0, 0), and(0, 0), nor(0, 0), nand(0, 0) }, - { xor(0, 1), xnor(0, 1), or(0, 1), and(0, 1), nor(0, 1), nand(0, 1) }, - { xor(1, 0), xnor(1, 0), or(1, 0), and(1, 0), nor(1, 0), nand(1, 0) }, - { xor(1, 1), xnor(1, 1), or(1, 1), and(1, 1), nor(1, 1), nand(1, 1) } - }; - - for (size_t i = 0; i < ITERS; i++) { - double* input = inputs[i % 4]; - double* output = outputs[i % 4]; - - trainer_train(&trainer, &network, input, output, 1.0); - } - +int logical_functions(void) { + Network network = {0}; + network_init(&network, 2, 2, 6, Rand); + Trainer trainer = {0}; + trainer_init(&trainer, &network); + double inputs[4][2] = { + {0, 0}, + {0, 1}, + {1, 0}, + {1, 1} + }; + double outputs[4][6] = { + { xor(0, 0), xnor(0, 0), or(0, 0), and(0, 0), nor(0, 0), nand(0, 0) }, + { xor(0, 1), xnor(0, 1), or(0, 1), and(0, 1), nor(0, 1), nand(0, 1) }, + { xor(1, 0), xnor(1, 0), or(1, 0), and(1, 0), nor(1, 0), nand(1, 0) }, + { xor(1, 1), xnor(1, 1), or(1, 1), and(1, 1), nor(1, 1), nand(1, 1) } + }; + + for (size_t i = 0; i < ITERS; i++) { + double* input = inputs[i % 4]; + double* output = outputs[i % 4]; + + trainer_train(&trainer, &network, input, output, 1.0); + } + + printf( + "Result after %d iterations\n" + " XOR XNOR OR AND NOR NAND\n", + ITERS); + for (size_t i = 0; i < 4; i++) { + double* input = inputs[i % 4]; + network_predict(&network, input); printf( - "Result after %d iterations\n XOR XNOR OR AND NOR NAND\n", - ITERS); - for (size_t i = 0; i < 4; i++) - { - double* input = inputs[i % 4]; - network_predict(&network, input); - printf( - "%.0f,%.0f = %.3f %.3f %.3f %.3f %.3f %.3f\n", - input[0], - input[1], - network.output[0], - network.output[1], - network.output[2], - network.output[3], - network.output[4], - network.output[5]); - } - - print_network(&network); - trainer_free(&trainer); - network_free(&network); - return 0; + "%.0f,%.0f = %.3f %.3f %.3f %.3f %.3f %.3f\n", + input[0], + input[1], + network.output[0], + network.output[1], + network.output[2], + network.output[3], + network.output[4], + network.output[5]); + } + + network_print(&network); + trainer_free(&trainer); + network_free(&network); + return 0; } -void print_network(const Network* network) { - printf("weights hidden:\n"); - for (size_t i = 0; i < network->n_inputs; i++) { - for (size_t j = 0; j < network->n_hidden; j++) { - printf(" %9.6f", network->weights_hidden[network->n_inputs * i + j]); - } - - printf("\n"); - } - - printf("biases hidden:\n"); - for (size_t i = 0; i < network->n_hidden; i++) { - printf(" %9.6f", network->biases_hidden[i]); - } - - printf("\n"); - - printf("weights output:\n"); - for (size_t i = 0; i < network->n_hidden; i++) { - for (size_t j = 0; j < network->n_outputs; j++) { - printf(" %9.6f", network->weights_output[i * network->n_outputs + j]); - } - - printf("\n"); - } - printf("biases output:\n"); - for (size_t i = 0; i < network->n_outputs; i++) { - printf(" %9.6f", network->biases_output[i]); - } +int main(int argc, char** argv) { + if (argc == 1) { + logical_functions(); + } else if (argc == 2 && strcmp("ttt", argv[1]) == 0) { + tic_tac_toe(); + } else { + printf("Usage:\n%s <> | ttt\n", argv[0]); + } - printf("\n"); + return 0; } diff --git a/C/neural.c b/C/neural.c index feb4f03..f9f604e 100644 --- a/C/neural.c +++ b/C/neural.c @@ -18,6 +18,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "neural.h" +#include #include #include @@ -25,120 +26,154 @@ static double sigmoid(double f) { return 1.0 / (1.0 + exp(-f)); } static double sigmoid_prim(double f) { return f * (1.0 - f); } Network* network_init( - Network* network, - uint32_t n_inputs, - uint32_t n_hidden, - uint32_t n_outputs, - RandFcn rand) { - network->n_inputs = n_inputs; - network->n_hidden = n_hidden; - network->n_outputs = n_outputs; - - network->weights_hidden = calloc( - n_inputs * n_hidden, - sizeof(*network->weights_hidden)); - network->biases_hidden = calloc( - n_hidden, - sizeof(*network->biases_hidden)); - network->weights_output = calloc( - n_hidden * n_outputs, - sizeof(*network->weights_output)); - network->biases_output = calloc( - n_outputs, - sizeof(*network->biases_output)); - network->hidden = calloc( - n_hidden, - sizeof(*network->hidden)); - network->output = calloc( - n_outputs, - sizeof(*network->output)); - - // initialize everything but the biases - for (size_t i = 0; i < n_inputs * n_hidden; i++) { - network->weights_hidden[i] = rand() - 0.5; - } - - for (size_t i = 0; i < n_hidden * n_outputs; i++) { - network->weights_output[i] = rand() - 0.5; - } - - return network; + Network* network, + uint32_t n_inputs, + uint32_t n_hidden, + uint32_t n_outputs, + RandFcn rand) { + network->n_inputs = n_inputs; + network->n_hidden = n_hidden; + network->n_outputs = n_outputs; + + network->weights_hidden = calloc( + n_inputs * n_hidden, + sizeof(*network->weights_hidden)); + network->biases_hidden = calloc( + n_hidden, + sizeof(*network->biases_hidden)); + network->weights_output = calloc( + n_hidden * n_outputs, + sizeof(*network->weights_output)); + network->biases_output = calloc( + n_outputs, + sizeof(*network->biases_output)); + network->hidden = calloc( + n_hidden, + sizeof(*network->hidden)); + network->output = calloc( + n_outputs, + sizeof(*network->output)); + + // initialize everything but the biases + for (size_t i = 0; i < n_inputs * n_hidden; i++) { + network->weights_hidden[i] = rand() - 0.5; + } + + for (size_t i = 0; i < n_hidden * n_outputs; i++) { + network->weights_output[i] = rand() - 0.5; + } + + return network; } void network_free(Network* network) { - free(network->weights_hidden); - free(network->biases_hidden); - free(network->weights_output); - free(network->biases_output); - free(network->hidden); - free(network->output); + free(network->weights_hidden); + free(network->biases_hidden); + free(network->weights_output); + free(network->biases_output); + free(network->hidden); + free(network->output); } void network_predict(Network* network, double* input) { - for (uint32_t c = 0; c < network->n_hidden; c++) { - double sum = 0; - for (uint32_t r = 0; r < network->n_inputs; r++) { - sum += input[r] * network->weights_hidden[r * network->n_hidden + c]; - } + for (uint32_t c = 0; c < network->n_hidden; c++) { + double sum = 0; + for (uint32_t r = 0; r < network->n_inputs; r++) { + sum += input[r] * network->weights_hidden[r * network->n_hidden + c]; + } + + network->hidden[c] = sigmoid(sum + network->biases_hidden[c]); + } + + for (uint32_t c = 0; c < network->n_outputs; c++) { + double sum = 0; + for (uint32_t r = 0; r < network->n_hidden; r++) { + sum += network->hidden[r] * network->weights_output[r * network->n_outputs + c]; + } + + network->output[c] = sigmoid(sum + network->biases_output[c]); + } +} - network->hidden[c] = sigmoid(sum + network->biases_hidden[c]); +void network_print(const Network* network) { + printf("weights hidden:\n"); + for (size_t i = 0; i < network->n_inputs; i++) { + for (size_t j = 0; j < network->n_hidden; j++) { + printf(" %9.6f", network->weights_hidden[network->n_inputs * i + j]); } - for (uint32_t c = 0; c < network->n_outputs; c++) { - double sum = 0; - for (uint32_t r = 0; r < network->n_hidden; r++) { - sum += network->hidden[r] * network->weights_output[r * network->n_outputs + c]; - } + printf("\n"); + } + + printf("biases hidden:\n"); + for (size_t i = 0; i < network->n_hidden; i++) { + printf(" %9.6f", network->biases_hidden[i]); + } + + printf("\n"); - network->output[c] = sigmoid(sum + network->biases_output[c]); + printf("weights output:\n"); + for (size_t i = 0; i < network->n_hidden; i++) { + for (size_t j = 0; j < network->n_outputs; j++) { + printf(" %9.6f", network->weights_output[i * network->n_outputs + j]); } + + printf("\n"); + } + + printf("biases output:\n"); + for (size_t i = 0; i < network->n_outputs; i++) { + printf(" %9.6f", network->biases_output[i]); + } + + printf("\n"); } /* trainer */ Trainer* trainer_init(Trainer* trainer, Network* network) { - trainer->grad_hidden = calloc(network->n_hidden, sizeof(*trainer->grad_hidden)); - trainer->grad_output = calloc(network->n_outputs, sizeof(*trainer->grad_output)); - return trainer; + trainer->grad_hidden = calloc(network->n_hidden, sizeof(*trainer->grad_hidden)); + trainer->grad_output = calloc(network->n_outputs, sizeof(*trainer->grad_output)); + return trainer; } void trainer_train(Trainer* trainer, Network* network, double* input, double* y, double lr) { - network_predict(network, input); - for (uint32_t c = 0; c < network->n_outputs; c++) { - trainer->grad_output[c] = (network->output[c] - y[c]) * sigmoid_prim(network->output[c]); - } - - for (uint32_t r = 0; r < network->n_hidden; r++) { - double sum = 0.0; - for (uint32_t c = 0; c < network->n_outputs; c++) { - sum += trainer->grad_output[c] * network->weights_output[r * network->n_outputs + c]; - } + network_predict(network, input); + for (uint32_t c = 0; c < network->n_outputs; c++) { + trainer->grad_output[c] = (network->output[c] - y[c]) * sigmoid_prim(network->output[c]); + } - trainer->grad_hidden[r] = sum * sigmoid_prim(network->hidden[r]); - } - - for (size_t r = 0; r < network->n_hidden; r++) { - for (size_t c = 0; c < network->n_outputs; c++) { - network->weights_output[r * network->n_outputs + c] -= lr * trainer->grad_output[c] * network->hidden[r]; - } + for (uint32_t r = 0; r < network->n_hidden; r++) { + double sum = 0.0; + for (uint32_t c = 0; c < network->n_outputs; c++) { + sum += trainer->grad_output[c] * network->weights_output[r * network->n_outputs + c]; } - for (size_t r = 0; r < network->n_inputs; r++) { - for (size_t c = 0; c < network->n_hidden; c++) { - network->weights_hidden[r * network->n_hidden + c] -= lr * trainer->grad_hidden[c] * input[r]; - } - } + trainer->grad_hidden[r] = sum * sigmoid_prim(network->hidden[r]); + } + for (size_t r = 0; r < network->n_hidden; r++) { for (size_t c = 0; c < network->n_outputs; c++) { - network->biases_output[c] -= lr * trainer->grad_output[c]; + network->weights_output[r * network->n_outputs + c] -= lr * trainer->grad_output[c] * network->hidden[r]; } + } + for (size_t r = 0; r < network->n_inputs; r++) { for (size_t c = 0; c < network->n_hidden; c++) { - network->biases_hidden[c] -= lr * trainer->grad_hidden[c]; + network->weights_hidden[r * network->n_hidden + c] -= lr * trainer->grad_hidden[c] * input[r]; } + } + + for (size_t c = 0; c < network->n_outputs; c++) { + network->biases_output[c] -= lr * trainer->grad_output[c]; + } + + for (size_t c = 0; c < network->n_hidden; c++) { + network->biases_hidden[c] -= lr * trainer->grad_hidden[c]; + } } void trainer_free(Trainer* trainer) { - free(trainer->grad_hidden); - free(trainer->grad_output); + free(trainer->grad_hidden); + free(trainer->grad_output); } diff --git a/C/neural.h b/C/neural.h index 2bca1f7..443aad3 100644 --- a/C/neural.h +++ b/C/neural.h @@ -23,30 +23,31 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include typedef struct Network { - double* weights_hidden; - double* biases_hidden; - double* weights_output; - double* biases_output; - double* hidden; - double* output; - uint32_t n_inputs; - uint32_t n_hidden; - uint32_t n_outputs; + double* weights_hidden; + double* biases_hidden; + double* weights_output; + double* biases_output; + double* hidden; + double* output; + uint32_t n_inputs; + uint32_t n_hidden; + uint32_t n_outputs; } Network; -typedef double (*RandFcn)(); +typedef double (*RandFcn)(void); Network* network_init( - Network* network, - uint32_t n_inputs, - uint32_t n_hidden, - uint32_t n_outputs, - RandFcn rand); + Network* network, + uint32_t n_inputs, + uint32_t n_hidden, + uint32_t n_outputs, + RandFcn rand); void network_free(Network* network); void network_predict(Network* network, double* input); +void network_print(const Network* network); typedef struct Trainer { - double* grad_hidden; - double* grad_output; + double* grad_hidden; + double* grad_output; } Trainer; Trainer* trainer_init(Trainer* trainer, Network* network); diff --git a/C/ttt.c b/C/ttt.c new file mode 100644 index 0000000..bdf2ad4 --- /dev/null +++ b/C/ttt.c @@ -0,0 +1,210 @@ +/* +Licensed under the MIT License given below. +Copyright 2023 Daniel Lidstrom +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the “Software”), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "ttt.h" +#include "neural.h" +#include "util.h" +#include +#include +#include + +typedef struct Board { + char squares[9]; + char turn; +} Board; + +char EMPTY = ' '; +char X = 'X'; +char O = 'O'; +const char* X_WON = "X won"; +const char* O_WON = "O won"; +const char* DRAW = "Draw"; +const int N_INPUTS = 18; + +void board_init(Board* board) { + memset(&board->squares, EMPTY, 9); + board->turn = X; +} + +void board_set_input_vector(Board* board, double* output) { + // X's point of view + for (int i = 0; i < 9; i++) { + output[i] = board->squares[i] == board->turn; + output[i + 9] = board->squares[i] != board->turn && board->squares[i] != EMPTY; + } +} + +/** + * |---|---|---| + * | X | X | O | 1 2 3 + * |---|---|---| + * | X | X | O | 4 5 6 + * |---|---|---| + * | X | X | O | 7 8 9 + * |---|---|---| + */ +void board_print(Board* board) { + double input_vector[N_INPUTS] = {0}; + board_set_input_vector(board, input_vector); + + printf( + "|---|---|---|\n" + "| %c | %c | %c | 1 2 3\n" + "|---|---|---|\n" + "| %c | %c | %c | 4 5 6\n" + "|---|---|---|\n" + "| %c | %c | %c | 7 8 9\n" + "|---|---|---|\n" + "Turn to move: %c\n" + "Network input: %.0f%.0f%.0f%.0f%.0f%.0f%.0f%.0f%.0f %.0f%.0f%.0f%.0f%.0f%.0f%.0f%.0f%.0f\n", + board->squares[0], board->squares[1], board->squares[2], + board->squares[3], board->squares[4], board->squares[5], + board->squares[6], board->squares[7], board->squares[8], + board->turn, + input_vector[0], input_vector[1], input_vector[2], + input_vector[3], input_vector[4], input_vector[5], + input_vector[6], input_vector[7], input_vector[8], + input_vector[9], input_vector[10], input_vector[11], + input_vector[12], input_vector[13], input_vector[14], + input_vector[15], input_vector[16], input_vector[17]); +} + +const char* board_game_over(Board* board) { + int filled = 1; + for (int i = 0; i < 9; i++) { + if (board->squares[i] == EMPTY) { + filled = 0; + break; + } + } + + // check diagonals + if ((board->squares[0] == X && board->squares[4] == X && board->squares[8] == X) + || (board->squares[2] == X && board->squares[4] == X && board->squares[6] == X)) { + return X_WON; + } + if ((board->squares[0] == O && board->squares[4] == O && board->squares[8] == O) + || (board->squares[2] == O && board->squares[4] == O && board->squares[6] == O)) { + return O_WON; + } + + for (int i = 0; i < 3; i++) { + // check rows + if (board->squares[i] == X && board->squares[i + 1] == X && board->squares[i + 2] == X) { + return X_WON; + } + if (board->squares[i] == O && board->squares[i + 1] == O && board->squares[i + 2] == O) { + return O_WON; + } + // check cols + if (board->squares[i] == X && board->squares[i + 3] == X && board->squares[i + 6] == X) { + return X_WON; + } + if (board->squares[i] == O && board->squares[i + 3] == O && board->squares[i + 6] == O) { + return O_WON; + } + } + + if (filled) return DRAW; + return NULL; +} + +int board_valid_move(Board* board, int square) { + return board->squares[square] == EMPTY; +} + +void board_play(Board* board, int square) { + board->squares[square] = board->turn; + if (board->turn == X) + board->turn = O; + else + board->turn = X; +} + +// ask for input, returns 0-8 +int read_input(void) { + char buffer[10]; + while (1) { + printf("Enter a number: "); + if (fgets(buffer, sizeof(buffer), stdin) == NULL) { + fputs("error: invalid input\n", stderr); + continue; + } + + if (strlen(buffer) != 2 || buffer[0] < '1' || buffer[0] > '9') { + printf("Please enter a single digit 1-9.\n"); + continue; + } + + break; + } + + return buffer[0] - '1'; +} + +typedef struct Sample { + double input_vector[N_INPUTS]; +} Sample; + +void train_network(Network* network) { + Trainer trainer = {0}; + trainer_init(&trainer, network); + + // run some games and learn the results + // we will collect last 1000 board positions seen + const int RUNS = 4000; + const int N = 1000; + Sample* samples = calloc(1000 * N_INPUTS, sizeof(*samples)); + Board board = {0}; + + // play game until finished, collect input vectors along the way + // once we have 1000 samples then start training network + // repeat play for how long? + board_init(&board); + const char* status = board_game_over(&board); + while (status == 0) { + status = board_game_over(&board); + } + + free(samples); +} + +void tic_tac_toe(void) { + Network network = {0}; + network_init(&network, 2, 2, 6, Rand); + + printf("Run tic-tac-toe\n"); + Board board = {0}; + board_init(&board); + + printf("Play until board is filled. Enter the number of the square.\n"); + board_print(&board); + while (board_game_over(&board) == 0) { + int input = read_input(); + if (board_valid_move(&board, input) == 0) { + printf("Invalid move. Pick an empty square, please.\n"); + continue; + } + + board_play(&board, input); + board_print(&board); + } + + printf("%s\n", board_game_over(&board)); +} diff --git a/C/ttt.h b/C/ttt.h new file mode 100644 index 0000000..0b93669 --- /dev/null +++ b/C/ttt.h @@ -0,0 +1,25 @@ +/* +Licensed under the MIT License given below. +Copyright 2023 Daniel Lidstrom +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the “Software”), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#if !defined(TTT_H) +#define TTT_H + +void tic_tac_toe(void); + +#endif diff --git a/C/util.c b/C/util.c new file mode 100644 index 0000000..11544c2 --- /dev/null +++ b/C/util.c @@ -0,0 +1,31 @@ +/* +Licensed under the MIT License given below. +Copyright 2023 Daniel Lidstrom +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the “Software”), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "util.h" +#include + +static uint32_t P = 2147483647; +static uint32_t A = 16807; +static uint32_t current = 1; + +double Rand(void) { + current = current * A % P; + double result = (double)current / P; + return result; +} diff --git a/C/util.h b/C/util.h new file mode 100644 index 0000000..8ad19cc --- /dev/null +++ b/C/util.h @@ -0,0 +1,25 @@ +/* +Licensed under the MIT License given below. +Copyright 2023 Daniel Lidstrom +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the “Software”), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#if !defined(UTIL_H) +#define UTIL_H + +double Rand(void); + +#endif