From c607b97732c9922aa6fef3a0fe1055b028d5f0c2 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Sun, 3 Mar 2024 17:14:11 -0500 Subject: Add Num.near() function --- builtins/nums.c | 36 ++++++++++++++++++++++++++++++++---- builtins/nums.h | 8 ++------ environment.c | 25 ++++++++++++++++++++++++- test/nums.tm | 5 +++++ 4 files changed, 63 insertions(+), 11 deletions(-) diff --git a/builtins/nums.c b/builtins/nums.c index 26bc1457..ec4c445b 100644 --- a/builtins/nums.c +++ b/builtins/nums.c @@ -1,8 +1,6 @@ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif #include #include +#include #include #include #include @@ -33,6 +31,21 @@ public bool Num__equal(const double *x, const double *y, const TypeInfo *type) { return *x == *y; } +public bool Num__near(double a, double b, double ratio, double absolute) { + if (ratio < 0) ratio = 0; + else if (ratio > 0) ratio = 1; + + if (a == b) return true; + + double diff = fabs(a - b); + if (diff < absolute) return true; + else if (isnan(diff)) return false; + + double epsilon = fabs(a * ratio) + fabs(b * ratio); + if (isinf(epsilon)) epsilon = DBL_MAX; + return (diff < epsilon); +} + public CORD Num__format(double f, int64_t precision) { return CORD_asprintf("%.*f", (int)precision, f); } @@ -86,7 +99,22 @@ public int32_t Num32__compare(const float *x, const float *y, const TypeInfo *ty public bool Num32__equal(const float *x, const float *y, const TypeInfo *type) { (void)type; return *x == *y; -} +} + +public bool Num32__near(float a, float b, float ratio, float absolute) { + if (ratio < 0) ratio = 0; + else if (ratio > 0) ratio = 1; + + if (a == b) return true; + + float diff = fabs(a - b); + if (diff < absolute) return true; + else if (isnan(diff)) return false; + + float epsilon = fabs(a * ratio) + fabs(b * ratio); + if (isinf(epsilon)) epsilon = FLT_MAX; + return (diff < epsilon); +} public CORD Num32__format(float f, int64_t precision) { return CORD_asprintf("%.*f", (int)precision, f); diff --git a/builtins/nums.h b/builtins/nums.h index e8fdceaa..a468e928 100644 --- a/builtins/nums.h +++ b/builtins/nums.h @@ -12,6 +12,7 @@ CORD Num__as_str(const double *f, bool colorize, const TypeInfo *type); int32_t Num__compare(const double *x, const double *y, const TypeInfo *type); bool Num__equal(const double *x, const double *y, const TypeInfo *type); +bool Num__near(double a, double b, double ratio, double absolute); CORD Num__format(double f, int64_t precision); CORD Num__scientific(double f, int64_t precision); double Num__mod(double num, double modulus); @@ -25,9 +26,6 @@ C(2_SQRTPI) C(E) C(PI_2) C(2_PI) C(1_PI) C(LN10) C(LN2) C(LOG2E) C(PI) C(PI_4) C const double Num__INF = INFINITY, Num__TAU = 2.*M_PI; #undef C double Num__random(void); -bool Num__finite(double n); -bool Num__isinf(double n); -bool Num__isnan(double n); #define F(name) double (*Num__##name)(double n) = name; double (*Num__abs)(double) = fabs; F(acos) F(acosh) F(asin) F(asinh) F(atan) F(atanh) F(cbrt) F(ceil) F(cos) F(cosh) F(erf) F(erfc) @@ -43,6 +41,7 @@ extern const TypeInfo Num; CORD Num32__as_str(const float *f, bool colorize, const TypeInfo *type); int32_t Num32__compare(const float *x, const float *y, const TypeInfo *type); bool Num32__equal(const float *x, const float *y, const TypeInfo *type); +bool Num32__near(float a, float b, float ratio, float absolute); CORD Num32__format(float f, int64_t precision); CORD Num32__scientific(float f, int64_t precision); float Num32__mod(float num, float modulus); @@ -55,9 +54,6 @@ C(2_SQRTPI) C(E) C(PI_2) C(2_PI) C(1_PI) C(LN10) C(LN2) C(LOG2E) C(PI) C(PI_4) C const float Num32__INF = INFINITY, Num32__TAU = 2.*M_PI; #undef C float Num32__random(void); -bool Num32__finite(float n); -bool Num32__isinf(float n); -bool Num32__isnan(float n); float Num32__nan(CORD tag); #define F(name) float (*Num32__##name)(float n) = name##f; float (*Num32__abs)(float) = fabsf; diff --git a/environment.c b/environment.c index e4b1c26d..f5b9c625 100644 --- a/environment.c +++ b/environment.c @@ -104,6 +104,7 @@ env_t *new_compilation_unit(void) #define F(name) {#name, "Num__"#name, "func(n:Num)->Num"} #define F2(name) {#name, "Num__"#name, "func(x:Num, y:Num)->Num"} {"Num", Type(NumType, .bits=64), "Num_t", "Num", $TypedArray(ns_entry_t, + {"near", "Num__near", "func(x:Num, y:Num, ratio=1e-9, min_epsilon=1e-9)->Bool"}, {"format", "Num__format", "func(n:Num, precision=0)->Str"}, {"scientific", "Num__scientific", "func(n:Num, precision=0)->Str"}, {"nan", "Num__nan", "func(tag=\"\")->Num"}, @@ -122,7 +123,29 @@ env_t *new_compilation_unit(void) #undef F2 #undef F #undef C - {"Num32", Type(NumType, .bits=32), "Num32_t", "Num32", {}}, +#define C(name) {#name, "Num32__"#name, "Num32"} +#define F(name) {#name, "Num32__"#name, "func(n:Num32)->Num32"} +#define F2(name) {#name, "Num32__"#name, "func(x:Num32, y:Num32)->Num32"} + {"Num32", Type(NumType, .bits=32), "Num32_t", "Num32", $TypedArray(ns_entry_t, + {"near", "Num32__near", "func(x:Num32, y:Num32, ratio=1e-9f32, min_epsilon=1e-9f32)->Bool"}, + {"format", "Num32__format", "func(n:Num32, precision=0)->Str"}, + {"scientific", "Num32__scientific", "func(n:Num32, precision=0)->Str"}, + {"nan", "Num32__nan", "func(tag=\"\")->Num32"}, + {"isinf", "Num32__isinf", "func(n:Num32)->Bool"}, + {"isfinite", "Num32__isfinite", "func(n:Num32)->Bool"}, + {"isnan", "Num32__isnan", "func(n:Num32)->Bool"}, + C(2_SQRTPI), C(E), C(PI_2), C(2_PI), C(1_PI), C(LN10), C(LN2), C(LOG2E), + C(PI), C(PI_4), C(SQRT2), C(SQRT1_2), C(INF), C(TAU), + {"random", "Num32__random", "func()->Num32"}, + F(abs), F(acos), F(acosh), F(asin), F(asinh), F(atan), F(atanh), F(cbrt), F(ceil), F(cos), F(cosh), F(erf), F(erfc), + F(exp), F(exp2), F(expm1), F(floor), F(j0), F(j1), F(log), F(log10), F(log1p), F(log2), F(logb), + F(rint), F(round), F(significand), F(sin), F(sinh), F(sqrt), + F(tan), F(tanh), F(tgamma), F(trunc), F(y0), F(y1), + F2(atan2), F2(copysign), F2(fdim), F2(hypot), F2(nextafter), F2(pow), F2(remainder), + )}, +#undef F2 +#undef F +#undef C {"Str", Type(StringType), "Str_t", "Str", $TypedArray(ns_entry_t, {"quoted", "Str__quoted", "func(s:Str, color=no)->Str"}, {"upper", "Str__upper", "func(s:Str)->Str"}, diff --git a/test/nums.tm b/test/nums.tm index c5b19325..d031bdeb 100644 --- a/test/nums.tm +++ b/test/nums.tm @@ -30,3 +30,8 @@ = yes >> nan == nan = no + +>> Num.PI:cos():near(-1) += yes +>> Num.PI:sin():near(0) += yes -- cgit v1.2.3