From 50adda02cbe86828d1b1dbaf0462c0685a52baa3 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Fri, 28 Jun 2024 22:47:58 +0200 Subject: [PATCH] Add math.min and math.max --- src/be_mathlib.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++ tests/math.be | 25 ++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/src/be_mathlib.c b/src/be_mathlib.c index 17fbfe1..0cef918 100644 --- a/src/be_mathlib.c +++ b/src/be_mathlib.c @@ -303,6 +303,61 @@ static int m_rand(bvm *vm) be_return(vm); } +/* check that all arguments are either int or real, and return true if at least one is real */ +static int m_check_int_or_has_real(bvm *vm) +{ + int argc = be_top(vm); + int has_real = 0; + for (int i = 1; i <= argc; ++i) { + if (be_isreal(vm, i)) { + has_real = 1; + } else if (!be_isint(vm, i)) { + be_raise(vm, "type_error", "arguments must be numbers"); + } + } + return has_real; +} + +static int m_min_max(bvm *vm, int is_min) { + int argc = be_top(vm); + if (argc > 0) { + /* see if at least one argument is float, else they are all ints */ + int has_real = m_check_int_or_has_real(vm); + if (has_real) { + breal bound = be_toreal(vm, 1); + for (int i = 2; i <= argc; ++i) { + breal x = be_toreal(vm, i); + if (is_min ? (x < bound) : (x > bound)) { + bound = x; + } + } + be_pushreal(vm, bound); + } else { + bint bound = be_toint(vm, 1); + for (int i = 2; i <= argc; ++i) { + bint x = be_toint(vm, i); + if (is_min ? (x < bound) : (x > bound)) { + bound = x; + } + } + be_pushint(vm, bound); + } + be_return(vm); + } + be_return_nil(vm); + +} + +int m_min(bvm *vm) +{ + return m_min_max(vm, 1); +} + +int m_max(bvm *vm) +{ + return m_min_max(vm, 0); +} + #if !BE_USE_PRECOMPILED_OBJECT be_native_module_attr_table(math) { be_native_module_function("isnan", m_isnan), @@ -330,6 +385,8 @@ be_native_module_attr_table(math) { be_native_module_function("pow", m_pow), be_native_module_function("srand", m_srand), be_native_module_function("rand", m_rand), + be_native_module_function("min", m_min), + be_native_module_function("max", m_max), be_native_module_real("pi", M_PI), be_native_module_real("nan", NAN), be_native_module_real("inf", INFINITY), @@ -366,6 +423,8 @@ module math (scope: global, depend: BE_USE_MATH_MODULE) { pow, func(m_pow) srand, func(m_srand) rand, func(m_rand) + min, func(m_min) + max, func(m_max) pi, real(M_PI) nan, real(NAN) inf, real(INFINITY) diff --git a/tests/math.be b/tests/math.be index 6ad8b01..9cc39a2 100644 --- a/tests/math.be +++ b/tests/math.be @@ -58,3 +58,28 @@ assert(math.round(-3.6) == -4) assert(math.round() == 0) +#- min and max -# +def assert_error(f, error_type) + try + f() + assert(false, 'unexpected execution flow') + except .. as e, m + assert(e == error_type) + end +end + +assert(math.min() == nil) +assert(math.min(0) == 0) +assert(math.min(0,2,10,56) == 0) +assert(math.min(4, 2, -10, 3) == -10) +assert(math.min(4, 2) == 2) + +# result is int unless one of the parameters is real +assert(type(math.min(4, 2, -10, 3)) == 'int') +assert(type(math.min(4, 2, -10.0, 3)) == 'real') + +assert(math.min(-3.4, 5) == -3.4) + +# test invalid parameters +assert_error(def () return math.min(4, nil) end, 'type_error') +assert_error(def () return math.min(4, "", 4.5) end, 'type_error')