C: rational-numbers

This commit is contained in:
2021-08-21 15:06:04 +02:00
parent 4f882b01cc
commit 002ce9c313
5 changed files with 303 additions and 0 deletions

View File

@@ -0,0 +1,115 @@
#include "rational_numbers.h"
#include <stdlib.h>
#include <math.h>
#define N(r) ((r).numerator)
#define D(r) ((r).denominator)
/* Note. We should probably check for possible overflow in all
* functions below (not covered in exercise).
* To do this, a simple solution could be to make operations with
* long long (or some other method), and add a field in rational_t
* to express such overflow, division by zero, etc...
*/
/* Euclidean algorithm (by Donald Knuth) */
rational_t reduce(rational_t r)
{
int16_t a=abs(N(r)), b=abs(D(r)), t;
while (b != 0) {
t = b;
b = a % b;
a = t;
}
if (D(r) < 0)
a=-a;
return (rational_t) { N(r)/a, D(r)/a };
}
/* to avoid pow() for integers
* BUG: does not check for overflow
*/
static inline int power(int n, int p)
{
int res=n;
if (p==0)
return 1;
while (--p)
res*=n;
return res;
}
/* All formulas below come from https://en.wikipedia.org/wiki/Rational_number
*/
rational_t add(rational_t r1, rational_t r2)
{
return reduce((rational_t) {
N(r1) * D(r2) + N(r2) * D(r1),
D(r1) * D(r2)
});
}
rational_t subtract(rational_t r1, rational_t r2)
{
return reduce((rational_t) {
N(r1) * D(r2) - N(r2) * D(r1),
D(r1) * D(r2)
});
}
rational_t multiply(rational_t r1, rational_t r2)
{
return reduce((rational_t) {
N(r1) * N(r2),
D(r1) * D(r2)
});
}
rational_t divide(rational_t r1, rational_t r2)
{
return reduce((rational_t) {
N(r1) * D(r2),
D(r1) * N(r2)
});
}
rational_t absolute(rational_t r)
{
return (rational_t) {
abs(N(r)),
abs(D(r))
};
}
rational_t exp_rational(rational_t r, uint16_t n)
{
return reduce((rational_t) {
power(N(r), n),
power(D(r), n)
});
}
float exp_real(uint16_t x, rational_t r)
{
return powf((float)x, (float)N(r)/D(r));
}
/* See GNUmakefile below for explanation
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
*/
#ifdef UNIT_TEST
int main(int ac, char **av)
{
int arg=1;
rational_t r1, r2;
for (; arg<ac-1; ++arg, ++arg) {
r1.numerator=atoi(av[arg]);;
r1.denominator=atoi(av[arg+1]);;
r2=reduce(r1);
printf("reduce(%d, %d)=(%d, %d)\n", N(r1), D(r1), N(r2), D(r2));
}
}
#endif

View File

@@ -0,0 +1,33 @@
#ifndef RATIONAL_NUMBERS
#define RATIONAL_NUMBERS
#include <stdint.h>
typedef struct {
int16_t numerator;
int16_t denominator;
} rational_t;
rational_t add(rational_t r1, rational_t r2);
rational_t subtract(rational_t r1, rational_t r2);
rational_t multiply(rational_t r1, rational_t r2);
rational_t divide(rational_t r1, rational_t r2);
rational_t absolute(rational_t r);
rational_t exp_rational(rational_t r, uint16_t n);
float exp_real(uint16_t x, rational_t r);
rational_t reduce(rational_t r);
/* See GNUmakefile below for explanation
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
*/
#if defined UNIT_TEST || defined DEBUG
#include <stdio.h>
#include <stdlib.h>
#endif
#ifdef TESTALL
#undef TEST_IGNORE
#define TEST_IGNORE() {}
#endif
#endif