You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
106 lines
2.8 KiB
106 lines
2.8 KiB
5 years ago
|
#include <stdlib.h>
|
||
|
#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
#include <err.h>
|
||
|
#include <openssl/bn.h>
|
||
|
|
||
|
struct thread_params {
|
||
|
char *begin;
|
||
|
char *end;
|
||
|
BIGNUM *results[2];
|
||
|
};
|
||
|
|
||
|
void *thread(void *arg)
|
||
|
{
|
||
|
struct thread_params *params = arg;
|
||
|
char *line = params->begin;
|
||
|
BIGNUM *cur = NULL;
|
||
|
while (line && line < params->end && *line) {
|
||
|
BN_dec2bn(&cur, line);
|
||
|
BN_div_word(cur, 3);
|
||
|
BN_sub_word(cur, 2);
|
||
|
BN_add(params->results[0], params->results[0], cur);
|
||
|
while (!BN_is_negative(cur) && !BN_is_zero(cur)) {
|
||
|
BN_add(params->results[1], params->results[1], cur);
|
||
|
BN_div_word(cur, 3);
|
||
|
BN_sub_word(cur, 2);
|
||
|
}
|
||
|
line = strchr(line, '\n');
|
||
|
if (line) line++;
|
||
|
}
|
||
|
BN_free(cur);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
int main(int argc, char *argv[])
|
||
|
{
|
||
|
long jobs = 8;
|
||
|
if (argc <= 1) return EXIT_FAILURE;
|
||
|
if (argc > 2) jobs = strtol(argv[2], NULL, 0);
|
||
|
|
||
|
FILE *f = fopen(argv[1], "r");
|
||
|
if (!f) err(EXIT_FAILURE, "fopen");
|
||
|
fseek(f, 0, SEEK_END);
|
||
|
long f_len = ftell(f);
|
||
|
fseek(f, 0, SEEK_SET);
|
||
|
char *file = malloc(f_len + 1);
|
||
|
if (!file) err(EXIT_FAILURE, "malloc");
|
||
|
if (fread(file, f_len, 1, f) != 1) err(EXIT_FAILURE, "fread");
|
||
|
file[f_len] = '\0';
|
||
|
fclose(f);
|
||
|
|
||
|
unsigned lines = 0;
|
||
|
for (char *c = file; *c; c++) if (*c == '\n') lines++;
|
||
|
if (file[f_len - 1] != '\n') lines++;
|
||
|
|
||
|
unsigned lines_per_job = lines / jobs;
|
||
|
|
||
|
struct thread_params params[jobs];
|
||
|
pthread_t threads[jobs];
|
||
|
char *begin = file;
|
||
|
char *end = begin;
|
||
|
for (unsigned i = 0; i < jobs; i++) {
|
||
|
params[i].results[0] = BN_new();
|
||
|
params[i].results[1] = BN_new();
|
||
|
|
||
|
if (i == jobs - 1) {
|
||
|
end = file + strlen(file);
|
||
|
} else {
|
||
|
for (unsigned i = 0; i < lines_per_job; i++) {
|
||
|
end = strchr(end, '\n');
|
||
|
if (!end) {
|
||
|
end = file + strlen(file);
|
||
|
break;
|
||
|
}
|
||
|
end++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
params[i].begin = begin;
|
||
|
params[i].end = end;
|
||
|
begin = end;
|
||
|
|
||
|
pthread_create(&threads[i], NULL, thread, ¶ms[i]);
|
||
|
}
|
||
|
|
||
|
BIGNUM *result_p1 = BN_new();
|
||
|
BIGNUM *result_p2 = BN_new();
|
||
|
for (unsigned i = 0; i < jobs; i++) {
|
||
|
pthread_join(threads[i], NULL);
|
||
|
BN_add(result_p1, result_p1, params[i].results[0]);
|
||
|
BN_add(result_p2, result_p2, params[i].results[1]);
|
||
|
BN_free(params[i].results[0]);
|
||
|
BN_free(params[i].results[1]);
|
||
|
}
|
||
|
|
||
|
char *result_p1_str = BN_bn2dec(result_p1);
|
||
|
char *result_p2_str = BN_bn2dec(result_p2);
|
||
|
BN_free(result_p1);
|
||
|
BN_free(result_p2);
|
||
|
printf("Part 1: %s\n", result_p1_str);
|
||
|
printf("Part 2: %s\n", result_p2_str);
|
||
|
OPENSSL_free(result_p1_str);
|
||
|
OPENSSL_free(result_p2_str);
|
||
|
free(file);
|
||
|
}
|