Skip to content

Instantly share code, notes, and snippets.

@zed
Last active December 31, 2015 09:59
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zed/7970320 to your computer and use it in GitHub Desktop.
Save zed/7970320 to your computer and use it in GitHub Desktop.
/** Find least common multiple (LCM) of series of numbers.
It accepts input on stdin (one integer per line) and writes the
final result to stdout.
Result is always positive.
It uses gmplib (-lgmp) to support arbitrary precision integer arithmetic.
http://stackoverflow.com/questions/20581925/how-to-avoid-overflow-error-when-finding-lcm-for-series-of-large-integers
*/
/* for getline() */
#if !defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 200809L
#define _POSIX_C_SOURCE 200809L
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <gmp.h>
static char *argv0 = NULL; /* for error reporting */
static void report_error(const char* format, ...) {
/*NOTE: multiple writes to stderr (no multiprocessing) */
va_list ap;
if (argv0)
fprintf(stderr, "%s: ", argv0);
fputs("error: ", stderr);
va_start(ap, format);
vfprintf(stderr, format, ap);
va_end(ap);
fputs("\n", stderr);
}
/** Parse token as decimal integer.
Result must be initialized.
On error: report it and return -1
*/
static int parse_mpz(char* token, mpz_t result) {
const int rc = mpz_set_str(result, token, 10);
if (rc == -1)
report_error("failed to parse '%s' as an integer", token);
return rc;
}
int main(int argc, char*argv[]) {
int error_happened = 1; /* assume by default that error happened */
size_t capacity = 13; /* 10 digits + newline + '\0' */
char* token = malloc(capacity);
ssize_t len = -1;
int have_read_first_number = 0;
FILE *fp = stdin; /* file to read input from */
mpz_t result, arg;
mpz_inits(result, arg, NULL);
mpz_set_ui(arg, 1u);
/* set global argv0 for error reporting */
argv0 = argv[0];
if (argc > 1) { /* read from file if given */
if ((fp = fopen(argv[1], "r")) == NULL) {
report_error("failed to open '%s' file", argv[1]);
goto cleanup;
}
}
/* read decimal integers: one per line */
while((len = getline(&token, &capacity, fp)) > 0) {
if (!have_read_first_number) { /* read the first integer */
if (parse_mpz(token, result) == -1) {
goto cleanup;
}
have_read_first_number = 1; /* successfully read first integer */
}
else { /* read the rest of the numbers */
if (parse_mpz(token, arg) == -1) {
goto cleanup;
}
}
/* lcm(a, b, c, d) = lcm(lcm(lcm(a, b), c), d) */
mpz_lcm(result, result, arg);
}
/* print results */
if (!feof(fp)) {
report_error("not all input is read");
}
else if (!have_read_first_number) {
report_error("no numbers read");
}
else if (mpz_out_str(stdout, 10, result) == 0) {
report_error("can't print result");
}
else { /* success */
puts("");
error_happened = 0;
}
cleanup:
mpz_clear(arg);
mpz_clear(result); /* cleanup */
if (fp && fp != stdin)
fclose(fp);
free(token);
/* fall through */
return error_happened ? EXIT_FAILURE : EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment