Skip to content

Commit

Permalink
Refactor to have libegc (#7)
Browse files Browse the repository at this point in the history
* Replicate computation of egyptian fractions

* rename egc.c -> main.c

* Rename lib

* Integrate lib

* Adapt linter checks

* Check cppcheck version

* Check help for cppcheck version 2.7

* Try to snap install cppcheck =2.14

* Remove -y from snap install

* Remove redundant cppcheck commands in workflow
  • Loading branch information
cpmachado authored Oct 29, 2024
1 parent 6604fcc commit 8127700
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 83 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
with:
python-version: '3.9'
- run: pip install cpplint===1.6.1
- run: sudo apt install cppcheck -y
- run: sudo snap install cppcheck
- run: make lint
dist:
runs-on: ubuntu-latest
Expand Down
1 change: 1 addition & 0 deletions CPPLINT.cfg
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
set noparent
filter=-build/include_subdir,-build/header_guard
29 changes: 24 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ BIN_DIR = $(BUILD_DIR)/bin
DIST_DIR = $(BUILD_DIR)/dist
DIST_BASE_DIR = $(DIST_DIR)/egc-$(VERSION)

LIBEGC_SRC_DIR = src/egc
LIBEGC_OBJ_DIR = $(BUILD_DIR)/obj/egc
LIBEGC_SRC = $(wildcard $(LIBEGC_SRC_DIR)/*.c)
LIBEGC_OBJ = $(patsubst $(LIBEGC_SRC_DIR)/%.c,$(LIBEGC_OBJ_DIR)/%.o, $(LIBEGC_SRC))
LIBEGC_BIN = $(BUILD_DIR)/libegc.a

SRC = $(wildcard $(SRC_DIR)/*.c)
OBJ = $(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR)/%.o, $(SRC))
BIN = $(BIN_DIR)/egc
Expand All @@ -36,8 +42,8 @@ clean:
@rm -rf $(BUILD_DIR)

lint:
@cppcheck $(SRC_DIR)
@cpplint --recursive $(SRC_DIR)
@cppcheck --check-level=exhaustive $(SRC_DIR) include
@cpplint --recursive $(SRC_DIR) include

options:
@echo "egc compilation flags"
Expand All @@ -46,6 +52,9 @@ options:
@echo "CFLAGS = $(CFLAGS)"
@echo "CPPFLAGS = $(CPPFLAGS)"
@echo "LDFLAGS = $(LDFLAGS)"
@echo "LIBEGC_SRC = $(LIBEGC_SRC)"
@echo "LIBEGC_OBJ = $(LIBEGC_OBJ)"
@echo "LIBEGC_BIN = $(LIBEGC_BIN)"
@echo "SRC = $(SRC)"
@echo "OBJ = $(OBJ)"
@echo "BIN = $(BIN)"
Expand All @@ -67,16 +76,26 @@ uninstall:
@echo removing executable file from $(PREFIX)/bin
@rm -f $(PREFIX)/bin/egc

$(BUILD_DIR):
mkdir -p $(BUILD_DIR)

$(OBJ_DIR):
mkdir -p $(OBJ_DIR)

$(LIBEGC_OBJ_DIR):
mkdir -p $(LIBEGC_OBJ_DIR)

$(BIN_DIR):
mkdir -p $(BIN_DIR)

$(BIN): $(OBJ) | $(BIN_DIR)
$(LIBEGC_BIN): $(LIBEGC_OBJ) | $(BUILD_DIR)
ar rcs $@ $^

$(BIN): $(OBJ) $(LIBEGC_BIN) | $(BIN_DIR)
$(CC) -o $@ $^ $(LDFLAGS)

$(LIBEGC_OBJ_DIR)/%.o: $(LIBEGC_SRC_DIR)/%.c | $(LIBEGC_OBJ_DIR)
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR)
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<

$(OBJ_DIR)/egc.o: $(SRC_DIR)/egc.c
13 changes: 13 additions & 0 deletions include/egc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/* Copyright 2024 cpmachado */

#define MAX_FRACTIONS_EGYPTIAN 100

typedef struct Fraction {
int64_t num, den;
} Fraction;

typedef struct EgyptianFraction {
int64_t dens[MAX_FRACTIONS_EGYPTIAN], n;
} EgyptianFraction;

int64_t computeEgyptianFraction(Fraction *fraction, EgyptianFraction *egyptian);
48 changes: 48 additions & 0 deletions src/egc/egc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/* Copyright 2024 cpmachado */

#include <stdint.h>
#include <stdio.h>

#include "egc.h"

int64_t gcd(int64_t a, int64_t b) {
int64_t c;
while (b > 0) {
if (a > b) {
c = a;
a = b;
b = c % a;
} else {
b = b % a;
}
}
return a;
}

int64_t computeEgyptianFraction(Fraction *fraction,
EgyptianFraction *egyptian) {
int64_t num = fraction->num, den = fraction->den;
int64_t i, gcd_val, n;

for (i = 0; num > 1; i++) {
gcd_val = gcd(num, den);
num /= gcd_val;
den /= gcd_val;
n = den / num + (den % num > 0);
egyptian->dens[i] = n;
if (INT64_MAX / n < num) {
fprintf(stderr, "Overflow detected: (num, n) = (%ld, %ld)\n", num, n);
return -1;
}
num = num * n - den;
if (INT64_MAX / n < den) {
fprintf(stderr, "Overflow detected: (den, n) = (%ld, %ld)\n", den, n);
return -1;
}
den = den * n;
}
egyptian->dens[i] = den;
i++;
egyptian->n = i;
return i;
}
108 changes: 31 additions & 77 deletions src/egc.c → src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include <string.h>
#include <unistd.h>

#include "egc.h"

#ifndef VERSION
#define VERSION "unknown"
#endif
Expand All @@ -23,18 +25,16 @@ void version(void);

int64_t readPositiveInt64(void);

void csvOutput(int64_t *s, int64_t n);

void simpleOutput(int64_t *s, int64_t n);
void csvOutput(EgyptianFraction *s);

void straightOutput(int64_t *s, int64_t n);
void simpleOutput(EgyptianFraction *s);

int32_t computeUnitaryFractions(int64_t num, int64_t den, int64_t *s);
void straightOutput(EgyptianFraction *s);

int32_t main(int32_t argc, char **argv) {
int64_t s[BUFSIZ];
int64_t n = 0;
int64_t num = -1, den = -1;
Fraction fraction = {.num = -1, .den = -1};
EgyptianFraction egyptian;
int32_t csv = 0, straight = 0;
int opt;

Expand Down Expand Up @@ -63,15 +63,15 @@ int32_t main(int32_t argc, char **argv) {
straight = 1;
break;
case 'n':
num = strtoll(optarg, NULL, 10);
fraction.num = strtoll(optarg, NULL, 10);
if (errno) {
fprintf(stderr, "%s", strerror(errno));
usage();
exit(EXIT_FAILURE);
}
break;
case 'd':
den = strtoll(optarg, NULL, 10);
fraction.den = strtoll(optarg, NULL, 10);
if (errno) {
fprintf(stderr, "%s", strerror(errno));
usage();
Expand All @@ -84,27 +84,30 @@ int32_t main(int32_t argc, char **argv) {
exit(EXIT_FAILURE);
}
}
if (num <= 0) {
if (fraction.num <= 0) {
printf("numerator: ");
num = readPositiveInt64();
fraction.num = readPositiveInt64();
}
if (den <= 0) {
if (fraction.den <= 0) {
printf("denominator: ");
den = readPositiveInt64();
fraction.den = readPositiveInt64();
}

if (num > den || num <= 0) {
if (fraction.num > fraction.den || fraction.num <= 0) {
fprintf(stderr, "r not in ]0, 1[\n");
exit(EXIT_FAILURE);
}

n = computeUnitaryFractions(num, den, s);
if ((n = computeEgyptianFraction(&fraction, &egyptian)) <= 0) {
fprintf(stderr, "Failed computeEgyptianFration with code %ld\n", n);
exit(EXIT_FAILURE);
}
if (csv) {
csvOutput(s, n);
csvOutput(&egyptian);
} else if (straight) {
straightOutput(s, n);
straightOutput(&egyptian);
} else {
simpleOutput(s, n);
simpleOutput(&egyptian);
}
return 0;
}
Expand All @@ -129,55 +132,6 @@ void version(void) {
": cpmachado\n");
}

int64_t gcdInt64(int64_t a, int64_t b) {
int64_t c;
while (b > 0) {
if (a > b) {
c = a;
a = b;
b = c % a;
} else {
b = b % a;
}
}
return a;
}

int32_t computeUnitaryFractions(int64_t num, int64_t den, int64_t *s) {
int64_t n, i;

s[0] = 0;

for (i = 1; num > 1; i++) {
/* normalise denominator and numerator */
n = gcdInt64(num, den);
num = num / n;
den = den / n;

/* The real n */
n = den / num + (den % num > 0);
s[i] = n;
if (INT64_MAX / n < num) {
fprintf(stderr, "Overflow detected\n");
printf("num = %ld, n = %ld\n", num, n);
exit(EXIT_FAILURE);
}
num = num * n - den;
if (INT64_MAX / n < den) {
fprintf(stderr, "Overflow detected\n");
printf("den = %ld, n = %ld\n", den, n);
exit(EXIT_FAILURE);
}
den = den * n;
}

if (num > 0) {
s[i] = den;
i++;
}
return i;
}

int64_t readPositiveInt64() {
char buf[BUFSIZ];
int64_t n;
Expand All @@ -195,30 +149,30 @@ int64_t readPositiveInt64() {
return n;
}

void csvOutput(int64_t *s, int64_t n) {
void csvOutput(EgyptianFraction *s) {
int64_t i;

printf("i,n_i\n");

for (i = 1; i < n; i++) {
printf("%ld,%ld\n", i, s[i]);
for (i = 0; i < s->n; i++) {
printf("%ld,%ld\n", i, s->dens[i]);
}
}

void simpleOutput(int64_t *s, int64_t n) {
void simpleOutput(EgyptianFraction *s) {
int64_t i;

for (i = 1; i < n; i++) {
printf("%ld\n", s[i]);
for (i = 0; i < s->n; i++) {
printf("%ld\n", s->dens[i]);
}
}

void straightOutput(int64_t *s, int64_t n) {
void straightOutput(EgyptianFraction *s) {
int64_t i;

for (i = 1; i < n; i++) {
printf("(%ld, %ld)", i, s[i]);
if (i < n - 1) {
for (i = 0; i < s->n; i++) {
printf("(%ld, %ld)", i, s->dens[i]);
if (i < s->n - 1) {
putchar(',');
}
}
Expand Down

0 comments on commit 8127700

Please sign in to comment.