commit 5ec6c6b393a59ae9c4391c40da716c1451bf63f8
parent 859a5f67c167d89987dcf83f628748a8fc111880
Author: Demonstrandum <moi@knutsen.co>
Date: Mon, 29 Jun 2020 16:52:17 +0100
Fix factorial fiasco.
Diffstat:
4 files changed, 38 insertions(+), 39 deletions(-)
diff --git a/README.md b/README.md
@@ -30,7 +30,6 @@ sudo make install # Installs the program system wide.
- [ ] Throw errors on overflows until we implement bignums.
- [ ] Imaginary numbers (using `complex.h`).
- [ ] User defined functions.
- - [ ] Extend factorial to positive reals and complex values using Gamma function.
- [ ] Garbage collection.
- [ ] Numerical equation solver (polynomial, simultaneous, &c.).
- [ ] Add more functionality, notably for calculus.
diff --git a/src/builtin.c b/src/builtin.c
@@ -105,22 +105,34 @@ fsize nice_sin(fsize alpha)
return sin(alpha);
}
-#define gamma_upper_bound 1000
-#define gamma_resolution 1000000
-#define gamma_h gamma_upper_bound/gamma_resolution //upper bound / resolution
+fsize gamma_complete(fsize num) {
+ if (num == 0)
+ return INF;
-fsize gamma_integrad(float x, fsize num) {
- return pow(x, num) * exp(-x);
-}
+ fsize integral = 0;
+ fsize fractional = modfl(num, &integral);
-fsize gammae(fsize num) {
- fsize sum = 0;
+ if (fractional == 0) {
+ if (num < 0)
+ return INF;
+ fsize res = 1;
+ for (fsize i = num - 1; i > 1; --i)
+ res *= i;
+ return res;
+ }
- for (int i = 1; i < gamma_resolution; i++) {
- sum += gamma_integrad(i*gamma_h, num);
- }
+ if (num < 0) {
+ // Gamma(x) = (1/x) * Gamma(x + 1)
+ fsize acc = 1 / num;
+ fsize i = num + 1;
+ do {
+ acc *= 1 / i;
+ i += 1;
+ } while (i < 0);
- return 0.5 * gamma_h * (gamma_integrad(0, num) + gamma_integrad(gamma_upper_bound, num) + 2 * sum);
+ return acc * tgammal(i);
+ }
+ return tgammal(num);
}
MATH_WRAPPER(sin, nice_sin)
@@ -145,6 +157,7 @@ MATH_WRAPPER(atanh, atanhl)
// TODO: atan2, hypot
MATH_WRAPPER(ceil, ceil)
MATH_WRAPPER(floor, floor)
+MATH_WRAPPER(Gamma, gamma_complete)
DataValue *builtin_neg(DataValue input)
{
@@ -176,37 +189,15 @@ DataValue *builtin_factorial(DataValue input)
{
NumberNode *num = type_check("!", LHS, T_NUMBER, &input);
+ if (num == NULL)
+ return NULL;
+
NumberNode tmp = num_to_float(*num);
NumberNode *new_num = malloc(sizeof(NumberNode));
memcpy(new_num, &tmp, sizeof(NumberNode));
+ new_num->value.f = gamma_complete(new_num->value.f + 1);
DataValue *result = wrap_data(T_NUMBER, new_num);
- if (num == NULL)
- return NULL;
-
- fsize integral = 0;
- fsize fractional = modfl(num->value.f, &integral);
- if ((num->type == FLOAT && (num->value.f < 0))
- || (num->type == INT && num->value.i < 0)) {
- ERROR_TYPE = EXECUTION_ERROR;
- strcpy(ERROR_MSG,
- "factorial (`!') is only defined for positve real numbers.");
- } else if ((num->type == FLOAT && (fractional != 0))) {
- new_num->value.f = gammae(num->value.f);
- result->value = new_num;
- return result;
- }
-
- if (new_num->value.f == 0) {
- new_num->value.f = 1;
- result->value = new_num;
- return result;
- }
- ssize i = new_num->value.f - 1;
- while (i > 1) {
- new_num->value.f *= i;
- --i;
- }
result->value = new_num;
return result;
}
diff --git a/src/builtin.h b/src/builtin.h
@@ -36,6 +36,7 @@ DataValue *builtin_ceil(DataValue);
DataValue *builtin_floor(DataValue);
DataValue *builtin_factorial(DataValue);
DataValue *builtin_neg(DataValue);
+DataValue *builtin_Gamma(DataValue);
NumberNode *num_add(NumberNode, NumberNode);
NumberNode *num_sub(NumberNode, NumberNode);
@@ -83,5 +84,6 @@ static const struct _func_name_pair builtin_fns[] = {
{ "!", { builtin_factorial } },
FUNC_PAIR(neg),
{ "-", { builtin_neg } },
+ FUNC_PAIR(Gamma),
};
diff --git a/src/defaults.h b/src/defaults.h
@@ -7,11 +7,18 @@
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
+#include <math.h>
#include "error.h"
#define len(array) (sizeof(array) / sizeof((array)[0]))
+#ifdef INFINITY
+ #define INF INFINITY
+#else
+ #define INF (1.0 / 0.0)
+#endif
+
typedef uint8_t u8 ;
typedef uint16_t u16;
typedef uint32_t u32;