From 1c839dfedec07f70d5ce07a21028c3517ec94a30 Mon Sep 17 00:00:00 2001 From: Landon Curt Noll Date: Thu, 31 Aug 2023 22:33:41 -0700 Subject: [PATCH] add logn and error checking for invalue eps and epsilon values Add new logn(x, n [,eps]) builtin to compute logarithms to base n. Verify that eps arguments (error tolerance arguments that override the default epsilon value) to builtin functions have proper values. Previously the eps argument had little to no value checks for many builtin functions. Document in help files for builtin functions that take eps arguments, the LIMIT range for such eps values. --- CHANGES | 10 + cal/regress.cal | 44 ++- calcerr.tbl | 5 + func.c | 823 +++++++++++++++++++++++++++++++++++++++++++++--- help/abs | 4 +- help/acos | 6 +- help/acosh | 6 +- help/acot | 6 +- help/acoth | 6 +- help/acsc | 6 +- help/acsch | 6 +- help/arg | 2 +- help/asec | 6 +- help/asech | 6 +- help/asin | 6 +- help/asinh | 6 +- help/atan | 6 +- help/atan2 | 4 +- help/atanh | 6 +- help/config | 2 +- help/cos | 6 +- help/cosh | 8 +- help/cot | 6 +- help/coth | 6 +- help/csc | 6 +- help/csch | 6 +- help/d2g | 4 +- help/d2r | 6 +- help/epsilon | 6 +- help/exp | 5 +- help/g2d | 4 +- help/g2r | 6 +- help/gd | 6 +- help/hypot | 6 +- help/ln | 4 +- help/log | 6 +- help/log2 | 6 +- help/logn | 39 ++- help/ltol | 5 +- help/near | 6 +- help/pi | 6 +- help/polar | 4 +- help/power | 4 +- help/r2d | 6 +- help/r2g | 6 +- help/root | 4 +- help/sec | 6 +- help/sech | 6 +- help/sin | 6 +- help/sinh | 6 +- help/sqrt | 6 +- help/tan | 6 +- help/tanh | 6 +- qmath.h | 1 + qtrans.c | 105 +++++- 55 files changed, 1092 insertions(+), 199 deletions(-) diff --git a/CHANGES b/CHANGES index 87c9a96..3b84686 100644 --- a/CHANGES +++ b/CHANGES @@ -89,6 +89,16 @@ The following are the changes from calc version 2.14.3.5 to date: Setting an invalid epsilon via the epsilon(value) or confiv("epsilon", value) triggers an error. The epsilon value must be: 0 < epsilon < 1. + Add new logn(x, n [,eps]) builtin to compute logarithms to base n. + + Verify that eps arguments (error tolerance arguments that override + the default epsilon value) to builtin functions have proper values. + Previously the eps argument had little to no value checks for + many builtin functions. + + Document in help files for builtin functions that take eps arguments, + the LIMIT range for such eps values. + The following are the changes from calc version 2.14.3.4 to 2.14.3.5: diff --git a/cal/regress.cal b/cal/regress.cal index 3d0bb9b..54e5a10 100644 --- a/cal/regress.cal +++ b/cal/regress.cal @@ -3007,8 +3007,6 @@ define test_2600() strcat(str(tnum++), ': log2(2^500) == 500')); vrfy(log2(1/2^23209) == -23209, strcat(str(tnum++), ': log2(1/2^23209) == -23209')); - vrfy(isint(log2(1/2^23209)), - strcat(str(tnum++), ': isint(log2(1/2^23209))')); vrfy(round(log2(127),10) == 6.9886846868, strcat(str(tnum++), ': round(log2(127),10) == 6.9886846868')); @@ -3036,6 +3034,48 @@ define test_2600() vrfy(round(log2(17+0.3i),10) == 4.0876874474+0.0254566819i, strcat(str(tnum++), ': round(log2(17+0.3i),10) == 4.0876874474+0.0254566819i')); + vrfy(logn(2, 2) == 1, + strcat(str(tnum++), ': logn(2, 2) == 1')); + vrfy(logn(4, 2) == 2, + strcat(str(tnum++), ': logn(4, 2) == 2')); + vrfy(logn(1024, 2) == 10, + strcat(str(tnum++), ': logn(1024, 2) == 10')); + vrfy(logn(2^500, 2) == 500, + strcat(str(tnum++), ': logn(2^500, 2) == 500')); + vrfy(logn(1/2^23209, 2) == -23209, + strcat(str(tnum++), ': logn(1/2^23209, 2) == -23209')); + vrfy(round(logn(127, 1/13),10) == -1.8886092516, + strcat(str(tnum++), + ': round(logn(127, 1/13),10) == -1.8886092516')); + vrfy(round(logn(23209, sqrt(3)),10) == 18.299987206, + strcat(str(tnum++), + ': round(logn(23209, sqrt(3)),10) == 18.299987206')); + vrfy(round(logn(2, 42),10) == 0.1854490234, + strcat(str(tnum++), + ': round(logn(2, 42),10) == 0.1854490234')); + vrfy(round(logn(1024, 42),10) == 1.8544902342, + strcat(str(tnum++), + ': round(logn(1024, 42),10) == 1.8544902342')); + vrfy(round(logn(2^500, 42),10) == 92.7245117077, + strcat(str(tnum++), + ': round(logn(2^500, 42),10) == 92.7245117077')); + vrfy(round(logn(1/2^23209, 42),10) == -4304.0863844473, + strcat(str(tnum++), + ': round(logn(1/2^23209, 42),10) == -4304.0863844473')); + vrfy(logn(-1, 1i) == 2, + strcat(str(tnum++), ': logn(-1, 1i) == 2')); + vrfy(round(logn(22+3i, 3i),10) == 0.984899142-1.2848465788i, + strcat(str(tnum++), + ': round(logn(22+3i, 3i),10) == 0.984899142-1.2848465788i')); + vrfy(round(logn(22.2+3.3i, -4-3.3i),10) == 0.5456929478+0.9025545623i, + strcat(str(tnum++), + ': round(logn(22.2+3.3i, -4-3.3i),10) == 0.5456929478+0.9025545623i')); + vrfy(round(logn(-127, 7),10) == 2.4894197139+1.6144592571i, + strcat(str(tnum++), + ': round(logn(-127, 7),10) == 2.4894197139+1.6144592571i')); + vrfy(round(logn(-127, 7i),10) == 2.2963271277-0.2392040372i, + strcat(str(tnum++), + ': round(logn(-127, 7i),10) == 2.2963271277-0.2392040372i')); epsilon(i),; print tnum++: ': epsilon(i),;'; diff --git a/calcerr.tbl b/calcerr.tbl index f0c1f1b..5d98e8c 100644 --- a/calcerr.tbl +++ b/calcerr.tbl @@ -545,3 +545,8 @@ E_HM2H2 Invalid rounding arg 4 for hm2h E_LOG2_1 Bad epsilon argument for log2 E_LOG2_2 Non-numeric first argument for log2 E_LOG2_3 Cannot calculate log2 for this value +E_LOGN_1 Bad epsilon argument for logn +E_LOGN_2 Non-numeric first argument for logn +E_LOGN_3 Cannot calculate logn for this value +E_LOGN_4 Cannot calculate logn for this log base +E_LOGN_5 Non-numeric second argument for logn diff --git a/func.c b/func.c index ce08846..6dcd44a 100644 --- a/func.c +++ b/func.c @@ -232,6 +232,51 @@ struct builtin { #if !defined(FUNCLIST) +/* + * verify_eps - verify that the eps argument is a valid error value + * + * The eps argument, when given to a builtin function, overrides + * the global epsilon value. As such, the numeric value of eps must be: + * + * 0 < eps < 1 + * + * given: + * veps a eps VALUE passed to a builtin function + * + * returns: + * true veps is a non-NULL pointer to a VALUE, and + * VALUE type is V_NUM, + * eps value is 0 < eps < 1 + * false otherwise + */ +S_FUNC bool +verify_eps(VALUE *veps) +{ + NUMBER *eps; /* VALUE as a NUMBER */ + + /* + * firewall - must be a non-NULL VALUE ptr for a V_NUM + */ + if (veps == NULL) { + return false; + } + if (veps->v_type != V_NUM) { + return false; + } + + /* + * numeric value must be valid for an epsilon value + * + * 0 < eps < 1 + */ + eps = veps->v_num; + if (check_epsilon(eps) == false) { + return false; + } + return true; +} + + S_FUNC VALUE f_eval(VALUE *vp) { @@ -2064,12 +2109,22 @@ f_exp(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ eps = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_EXP1); + } eps = vals[1]->v_num; } + + /* + * compute e^x to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: q = qexp(vals[0]->v_num, eps); @@ -2107,12 +2162,22 @@ f_ln(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ err = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM) + if (verify_eps(vals[1]) == false) { return error_value(E_LN1); + } err = vals[1]->v_num; } + + /* + * compute natural logarithm to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: if (!qisneg(vals[0]->v_num) && @@ -2132,6 +2197,8 @@ f_ln(int count, VALUE **vals) default: return error_value(E_LN2); } + + /* determine if we will return a numeric or complex value */ result.v_type = V_COM; result.v_com = c; if (cisreal(c)) { @@ -2153,12 +2220,22 @@ f_log(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ err = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM) + if (verify_eps(vals[1]) == false) { return error_value(E_LOG1); + } err = vals[1]->v_num; } + + /* + * compute logarithm base 10 to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: if (!qisneg(vals[0]->v_num) && @@ -2181,6 +2258,8 @@ f_log(int count, VALUE **vals) if (c == NULL) { return error_value(E_LOG3); } + + /* determine if we will return a numeric or complex value */ result.v_type = V_COM; result.v_com = c; if (cisreal(c)) { @@ -2202,12 +2281,22 @@ f_log2(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ err = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM) + if (verify_eps(vals[1]) == false) { return error_value(E_LOG2_1); + } err = vals[1]->v_num; } + + /* + * compute base 2 logarithm to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: if (!qisneg(vals[0]->v_num) && @@ -2230,6 +2319,8 @@ f_log2(int count, VALUE **vals) if (c == NULL) { return error_value(E_LOG2_3); } + + /* determine if we will return a numeric or complex value */ result.v_type = V_COM; result.v_com = c; if (cisreal(c)) { @@ -2241,6 +2332,269 @@ f_log2(int count, VALUE **vals) } +S_FUNC VALUE +f_logn(int count, VALUE **vals) +{ + VALUE result; /* return value */ + COMPLEX ctmp; /* intermediate COMPLEX temporary value */ + COMPLEX *p_cval; /* pointer to a COMPLEX value */ + NUMBER *err; /* epsilon error value */ + bool ln_of_x_is_complex = false; /* taking to value of a COMPLEX x */ + COMPLEX *ln_x_c; /* ln(x) where ln_of_x_is_complex is true */ + NUMBER *ln_x_r; /* ln(x) where ln_of_x_is_complex is false */ + bool ln_of_n_is_complex = false; /* taking to value of a COMPLEX base n */ + COMPLEX *ln_n_c; /* ln(n) where ln_of_n_is_complex is true */ + NUMBER *ln_n_r; /* ln(n) where ln_of_n_is_complex is false */ + + /* initialize VALUE */ + result.v_subtype = V_NOSUBTYPE; + + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ + err = conf->epsilon; + if (count == 3) { + if (verify_eps(vals[2]) == false) { + return error_value(E_LOGN_1); + } + err = vals[2]->v_num; + } + + /* + * special case: x and n are both integer powers of 2 and n log 2 != 0 + * + * If this is the case, we return the integer formed by log2(n) / log2(x). + */ + ln_x_r = qalloc(); + ln_n_r = qalloc(); + if (vals[0]->v_type == V_NUM && qispowerof2(vals[0]->v_num, &ln_x_r) == true) { + if (vals[1]->v_type == V_NUM && qispowerof2(vals[1]->v_num, &ln_n_r) == true) { + if (!qiszero(ln_n_r)) { + result.v_num = qqdiv(ln_x_r, ln_n_r); + if (result.v_com == NULL) { + return error_value(E_LOGN_4); + } + result.v_type = V_NUM; + qfree(ln_x_r); + qfree(ln_n_r); + return result; + } else { + qfree(ln_x_r); + qfree(ln_n_r); + return error_value(E_LOGN_4); + } + } + } + qfree(ln_x_r); + qfree(ln_n_r); + + /* + * take the natural log of x (value) + * + * Look for the case where the natural log of x complex is a real. + */ + switch (vals[0]->v_type) { + case V_NUM: + if (qiszero(vals[0]->v_num)) { + return error_value(E_LOGN_3); + } + if (qisneg(vals[0]->v_num)) { + ctmp.real = vals[0]->v_num; + ctmp.imag = qlink(&_qzero_); + ctmp.links = 1; + ln_x_c = c_ln(&ctmp, err); + if (ln_x_c == NULL) { + return error_value(E_LOGN_3); + } + if (cisreal(ln_x_c)) { + ln_x_r = qcopy(ln_x_c->real); + comfree(ln_x_c); + } else { + ln_of_x_is_complex = true; + } + } else { + ln_x_r = qln(vals[0]->v_num, err); + if (ln_x_r == NULL) { + return error_value(E_LOGN_3); + } + } + break; + case V_COM: + if (ciszero(vals[0]->v_com)) { + return error_value(E_LOGN_3); + } + ln_x_c = c_ln(vals[0]->v_com, err); + if (ln_x_c == NULL) { + return error_value(E_LOGN_3); + } + if (cisreal(ln_x_c)) { + ln_x_r = qcopy(ln_x_c->real); + comfree(ln_x_c); + } else { + ln_of_x_is_complex = true; + } + break; + default: + return error_value(E_LOGN_2); + } + + /* + * take the natural log of n (base) + * + * Look for the case where the natural log of n complex is a real. + * Also report an error if the case where the natural log of n is zero. + */ + switch (vals[1]->v_type) { + case V_NUM: + if (qiszero(vals[1]->v_num)) { + return error_value(E_LOGN_4); + } + if (qisneg(vals[1]->v_num)) { + ctmp.real = vals[1]->v_num; + ctmp.imag = qlink(&_qzero_); + ctmp.links = 1; + ln_n_c = c_ln(&ctmp, err); + if (ln_n_c == NULL) { + return error_value(E_LOGN_4); + } + if (ciszero(ln_n_c)) { + comfree(ln_n_c); + return error_value(E_LOGN_4); + } + if (cisreal(ln_n_c)) { + ln_n_r = qcopy(ln_n_c->real); + comfree(ln_n_c); + } else { + ln_of_n_is_complex = true; + } + } else { + ln_n_r = qln(vals[1]->v_num, err); + if (ln_n_r == NULL) { + return error_value(E_LOGN_4); + } + if (qiszero(ln_n_r)) { + qfree(ln_n_r); + return error_value(E_LOGN_4); + } + } + break; + case V_COM: + if (ciszero(vals[1]->v_com)) { + return error_value(E_LOGN_4); + } + ln_n_c = c_ln(vals[1]->v_com, err); + if (ln_n_c == NULL) { + return error_value(E_LOGN_4); + } + if (ciszero(ln_n_c)) { + comfree(ln_n_c); + return error_value(E_LOGN_4); + } + if (cisreal(ln_n_c)) { + ln_n_r = qcopy(ln_n_c->real); + comfree(ln_n_c); + } else { + ln_of_n_is_complex = true; + } + break; + default: + return error_value(E_LOGN_5); + } + + /* + * compute ln(x) / ln(n) + */ + if (ln_of_x_is_complex == true) { + if (ln_of_n_is_complex == true) { + + /* + * case: ln(x) is COMPLEX, ln(n) is COMPLEX + */ + p_cval = c_div(ln_x_c, ln_n_c); + if (p_cval == NULL) { + return error_value(E_LOGN_3); + } + /* check if division is COMPLEX or NUMBER */ + if (cisreal(p_cval)) { + /* ln(x) / ln(n) was NUMBER, not COMPLEX */ + result.v_num = qlink(p_cval->real); + result.v_type = V_NUM; + comfree(p_cval); + } else { + /* ln(x) / ln(n) is COMPLEX */ + result.v_type = V_COM; + result.v_com = p_cval; + } + + } else { + + /* + * case: ln(x) is COMPLEX, ln(n) is NUMBER + */ + p_cval = c_divq(ln_x_c, ln_n_r); + if (p_cval == NULL) { + return error_value(E_LOGN_3); + } + /* check if division is COMPLEX or NUMBER */ + if (cisreal(p_cval)) { + /* ln(x) / ln(n) was NUMBER, not COMPLEX */ + result.v_num = qlink(p_cval->real); + result.v_type = V_NUM; + comfree(p_cval); + } else { + /* ln(x) / ln(n) is COMPLEX */ + result.v_type = V_COM; + result.v_com = p_cval; + } + } + + } else { + if (ln_of_n_is_complex == true) { + + /* + * case: ln(x) is NUMBER, ln(n) is COMPLEX + */ + /* convert ln_x_r into COMPLEX so we can divide */ + ctmp.real = ln_x_r; + ctmp.imag = qlink(&_qzero_); + ctmp.links = 1; + p_cval = c_div(&ctmp, ln_n_c); + if (result.v_com == NULL) { + return error_value(E_LOGN_3); + } + /* check if division is COMPLEX or NUMBER */ + if (cisreal(p_cval)) { + /* ln(x) / ln(n) was NUMBER, not COMPLEX */ + result.v_num = qlink(p_cval->real); + result.v_type = V_NUM; + comfree(p_cval); + } else { + /* ln(x) / ln(n) is COMPLEX */ + result.v_type = V_COM; + result.v_com = p_cval; + } + + } else { + + /* + * case: ln(x) is NUMBER, ln(n) is NUMBER + */ + result.v_num = qqdiv(ln_x_r, ln_n_r); + if (result.v_com == NULL) { + return error_value(E_LOGN_3); + } + /* ln(x) / ln(n) is NUMBER */ + result.v_type = V_NUM; + } + } + + /* return the resulting logarithm */ + return result; +} + + S_FUNC VALUE f_cos(int count, VALUE **vals) { @@ -2251,12 +2605,22 @@ f_cos(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ eps = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_COS1); + } eps = vals[1]->v_num; } + + /* + * compute cosinr to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: result.v_num = qcos(vals[0]->v_num, eps); @@ -2294,15 +2658,22 @@ f_d2r(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; - /* firewall */ + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ eps = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_D2R1); + } eps = vals[1]->v_num; } - /* calculate argument * (pi/180) */ + /* + * compute argument*(pi/180) to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: pidiv180 = qpidiv180(eps); @@ -2336,15 +2707,22 @@ f_r2d(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; - /* firewall */ + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ eps = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_R2D1); + } eps = vals[1]->v_num; } - /* calculate argument / (pi/180) */ + /* + * compute argument/(pi/180) to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: pidiv180 = qpidiv180(eps); @@ -2378,15 +2756,22 @@ f_g2r(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; - /* firewall */ + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ eps = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_G2R1); + } eps = vals[1]->v_num; } - /* calculate argument * (pi/200) */ + /* + * compute argument*(pi/200) to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: pidiv200 = qpidiv200(eps); @@ -2420,15 +2805,22 @@ f_r2g(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; - /* firewall */ + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ eps = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_R2G1); + } eps = vals[1]->v_num; } - /* calculate argument / (pi/200) */ + /* + * compute argument/(pi/200) to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: pidiv200 = qpidiv200(eps); @@ -2525,12 +2917,22 @@ f_sin(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ eps = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_SIN1); + } eps = vals[1]->v_num; } + + /* + * compute sine to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: result.v_num = qsin(vals[0]->v_num, eps); @@ -2567,12 +2969,21 @@ f_tan(int count, VALUE **vals) tmp1.v_subtype = V_NOSUBTYPE; tmp2.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ err = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_TAN1); + } err = vals[1]->v_num; } + /* + * compute tangent to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: result.v_num = qtan(vals[0]->v_num, err); @@ -2611,12 +3022,22 @@ f_sec(int count, VALUE **vals) result.v_subtype = V_NOSUBTYPE; tmp.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ err = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_SEC1); + } err = vals[1]->v_num; } + + /* + * compute secant to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: result.v_num = qsec(vals[0]->v_num, err); @@ -2650,12 +3071,22 @@ f_cot(int count, VALUE **vals) tmp1.v_subtype = V_NOSUBTYPE; tmp2.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ err = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_COT1); + } err = vals[1]->v_num; } + + /* + * compute cotangent to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: if (qiszero(vals[0]->v_num)) @@ -2697,12 +3128,22 @@ f_csc(int count, VALUE **vals) result.v_subtype = V_NOSUBTYPE; tmp.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ err = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_CSC1); + } err = vals[1]->v_num; } + + /* + * compute cosecant to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: if (qiszero(vals[0]->v_num)) @@ -2736,12 +3177,22 @@ f_sinh(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ eps = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_SINH1); + } eps = vals[1]->v_num; } + + /* + * compute hyperbolic sine to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: q = qsinh(vals[0]->v_num, eps); @@ -2779,12 +3230,22 @@ f_cosh(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ eps = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_COSH1); + } eps = vals[1]->v_num; } + + /* + * compute hyperbolic cosine to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: q = qcosh(vals[0]->v_num, eps); @@ -2824,12 +3285,22 @@ f_tanh(int count, VALUE **vals) tmp1.v_subtype = V_NOSUBTYPE; tmp2.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ err = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_TANH1); + } err = vals[1]->v_num; } + + /* + * compute hyperbolic tangent to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: result.v_num = qtanh(vals[0]->v_num, err); @@ -2870,12 +3341,22 @@ f_coth(int count, VALUE **vals) tmp1.v_subtype = V_NOSUBTYPE; tmp2.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ err = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_COTH1); + } err = vals[1]->v_num; } + + /* + * compute hyperbolic cotangent to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: if (qiszero(vals[0]->v_num)) @@ -2917,12 +3398,22 @@ f_sech(int count, VALUE **vals) result.v_subtype = V_NOSUBTYPE; tmp.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ err = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_SECH1); + } err = vals[1]->v_num; } + + /* + * compute hyperbolic secant to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: result.v_num = qsech(vals[0]->v_num, err); @@ -2955,12 +3446,22 @@ f_csch(int count, VALUE **vals) result.v_subtype = V_NOSUBTYPE; tmp.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ err = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_CSCH1); + } err = vals[1]->v_num; } + + /* + * compute hyperbolic cosecant to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: if (qiszero(vals[0]->v_num)) @@ -2994,12 +3495,22 @@ f_atan(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ err = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_ATAN1); + } err = vals[1]->v_num; } + + /* + * compute inverse tangent to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: result.v_num = qatan(vals[0]->v_num, err); @@ -3034,12 +3545,22 @@ f_acot(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ err = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_ACOT1); + } err = vals[1]->v_num; } + + /* + * compute inverse cotangent to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: result.v_num = qacot(vals[0]->v_num, err); @@ -3074,12 +3595,22 @@ f_asin(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ err = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_ASIN1); + } err = vals[1]->v_num; } + + /* + * compute inverse sine to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: result.v_num = qasin(vals[0]->v_num, err); @@ -3123,12 +3654,22 @@ f_acos(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ err = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_ACOS1); + } err = vals[1]->v_num; } + + /* + * compute inverse cosine to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: result.v_num = qacos(vals[0]->v_num, err); @@ -3173,12 +3714,22 @@ f_asec(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ err = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_ASEC1); + } err = vals[1]->v_num; } + + /* + * compute inverse secant to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: if (qiszero(vals[0]->v_num)) @@ -3227,12 +3778,22 @@ f_acsc(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ err = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_ACSC1); + } err = vals[1]->v_num; } + + /* + * compute inverse cosecant to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: if (qiszero(vals[0]->v_num)) @@ -3280,12 +3841,22 @@ f_asinh(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ err = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_ASINH1); + } err = vals[1]->v_num; } + + /* + * compute inverse hyperbolic sine to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: result.v_num = qasinh(vals[0]->v_num, err); @@ -3322,12 +3893,22 @@ f_acosh(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ err = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_ACOSH1); + } err = vals[1]->v_num; } + + /* + * compute inverse hyperbolic cosine to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: result.v_num = qacosh(vals[0]->v_num, err); @@ -3372,12 +3953,22 @@ f_atanh(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ err = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_ATANH1); + } err = vals[1]->v_num; } + + /* + * compute inverse hyperbolic tangent to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: result.v_num = qatanh(vals[0]->v_num, err); @@ -3424,12 +4015,22 @@ f_acoth(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ err = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_ACOTH1); + } err = vals[1]->v_num; } + + /* + * compute inverse hyperbolic cotangent to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: result.v_num = qacoth(vals[0]->v_num, err); @@ -3476,12 +4077,22 @@ f_asech(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ err = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_SECH1); + } err = vals[1]->v_num; } + + /* + * compute inverse hyperbolic secant to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: if (qiszero(vals[0]->v_num)) @@ -3530,12 +4141,22 @@ f_acsch(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ err = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_ACSCH1); + } err = vals[1]->v_num; } + + /* + * compute inverse hyperbolic cosecant to a given error tolerance + */ switch (vals[0]->v_type) { case V_NUM: if (qiszero(vals[0]->v_num)) @@ -3584,12 +4205,22 @@ f_gd(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ eps = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (verify_eps(vals[1]) == false) { return error_value(E_GD1); + } eps = vals[1]->v_num; } + + /* + * compute Gudermannian function to a given error tolerance + */ result.v_type = V_COM; switch (vals[0]->v_type) { case V_NUM: @@ -3633,12 +4264,22 @@ f_agd(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given as a NUMBER and != 0. + */ eps = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) { return error_value(E_AGD1); + } eps = vals[1]->v_num; } + + /* + * compute inverse Gudermannian function to a given error tolerance + */ result.v_type = V_COM; switch (vals[0]->v_type) { case V_NUM: @@ -3811,12 +4452,22 @@ f_arg(int count, VALUE **vals) /* initialize VALUE */ result.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given as a NUMBER and != 0. + */ err = conf->epsilon; if (count == 2) { - if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) + if (vals[1]->v_type != V_NUM || qiszero(vals[1]->v_num)) { return error_value(E_ARG1); + } err = vals[1]->v_num; } + + /* + * compute argument (the angle or phase) of a complex number to a given error tolerance + */ result.v_type = V_NUM; switch (vals[0]->v_type) { case V_NUM: @@ -3842,6 +4493,7 @@ f_arg(int count, VALUE **vals) S_FUNC NUMBER * f_legtoleg(NUMBER *val1, NUMBER *val2) { + /* qlegtoleg() performs the val2 != 0 check */ return qlegtoleg(val1, val2, false); } @@ -5099,12 +5751,30 @@ f_mmin(VALUE *v1, VALUE *v2) S_FUNC NUMBER * f_near(int count, NUMBER **vals) { - NUMBER *val; + NUMBER *err; /* epsilon error tolerance */ + FLAG near; /* qnear() return value */ + NUMBER *ret; /* return value as NUMBER */ - val = conf->epsilon; - if (count == 3) - val = vals[2]; - return itoq((long) qnear(vals[0], vals[1], val)); + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is in a valid range. + */ + err = conf->epsilon; + if (count == 3) { + if (check_epsilon(vals[2]) == false) { + math_error("Invalid value for near epsilon: must be: 0 < epsilon < 1"); + not_reached(); + } + err = vals[2]; + } + + /* + * compute compare nearness of two numbers to a given error tolerance + */ + near = qnear(vals[0], vals[1], err); + ret = itoq((long) near); + return ret; } @@ -5122,11 +5792,21 @@ S_FUNC NUMBER * f_cfappr(int count, NUMBER **vals) { long R; - NUMBER *q; + NUMBER *q; /* approximation limit */ - R = (count > 2) ? qtoi(vals[2]) : conf->cfappr; + /* + * determine epsilon or and approximation limit + * + * NOTE: q is not purely an err (epsilon) value. + * When q is >= 1, it is approximation limit. + * Moreover q can be < 0. No value check on q is needed. + */ q = (count > 1) ? vals[1] : conf->epsilon; + /* + * compute approximation using continued fractions + */ + R = (count > 2) ? qtoi(vals[2]) : conf->cfappr; return qcfappr(vals[0], q, R); } @@ -5198,6 +5878,11 @@ f_root(int count, VALUE **vals) err.v_subtype = V_NOSUBTYPE; result.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is != 0. + */ if (count > 2) { vp = vals[2]; } else { @@ -5205,6 +5890,13 @@ f_root(int count, VALUE **vals) err.v_type = V_NUM; vp = &err; } + if (vp->v_type != V_NUM || qiszero(vp->v_num)) { + return error_value(E_ROOT3); + } + + /* + * compute root of a number to a given error tolerance + */ rootvalue(vals[0], vals[1], vp, &result); return result; } @@ -5219,6 +5911,11 @@ f_power(int count, VALUE **vals) err.v_subtype = V_NOSUBTYPE; result.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is != 0. + */ if (count > 2) { vp = vals[2]; } else { @@ -5226,6 +5923,13 @@ f_power(int count, VALUE **vals) err.v_type = V_NUM; vp = &err; } + if ((vp->v_type != V_NUM) || qisneg(vp->v_num) || qiszero(vp->v_num)) { + return error_value(E_POWER3); + } + + /* + * compute evaluate a numerical power to a given error tolerance + */ powervalue(vals[0], vals[1], vp, &result); return result; } @@ -5241,17 +5945,30 @@ f_polar(int count, VALUE **vals) err.v_subtype = V_NOSUBTYPE; result.v_subtype = V_NOSUBTYPE; + /* + * set error tolerance for builtin function + * + * Use eps VALUE arg if given and value is != 0. + */ if (count > 2) { vp = vals[2]; + if ((vp->v_type != V_NUM) || qisneg(vp->v_num) || qiszero(vp->v_num)) { + return error_value(E_POLAR2); + } } else { err.v_num = conf->epsilon; err.v_type = V_NUM; vp = &err; } + if ((vp->v_type != V_NUM) || qisneg(vp->v_num) || qiszero(vp->v_num)) { + return error_value(E_POLAR2); + } + + /* + * compute complex number by modulus (radius) and argument (angle) to a given error tolerance + */ if ((vals[0]->v_type != V_NUM) || (vals[1]->v_type != V_NUM)) return error_value(E_POLAR1); - if ((vp->v_type != V_NUM) || qisneg(vp->v_num) || qiszero(vp->v_num)) - return error_value(E_POLAR2); c = c_polar(vals[0]->v_num, vals[1]->v_num, vp->v_num); result.v_com = c; result.v_type = V_COM; @@ -10317,6 +11034,8 @@ STATIC CONST struct builtin builtins[] = { "base 10 logarithm of value a within accuracy b"}, {"log2", 1, 2, 0, OP_NOP, {.null = NULL}, {.valfunc_cnt = f_log2}, "base 2 logarithm of value a within accuracy b"}, + {"logn", 2, 3, 0, OP_NOP, {.null = NULL}, {.valfunc_cnt = f_logn}, + "base b logarithm of value a within accuracy c"}, {"lowbit", 1, 1, 0, OP_LOWBIT, {.null = NULL}, {.null = NULL}, "low bit number in base 2 representation"}, {"ltol", 1, 2, FE, OP_NOP, {.numfunc_2 = f_legtoleg}, {.null = NULL}, diff --git a/help/abs b/help/abs index 6e99435..f57ade7 100644 --- a/help/abs +++ b/help/abs @@ -36,7 +36,7 @@ EXAMPLE 5 6.40312 6.4031242374 LIMITS - none + when x is complex, eps != 0 LINK LIBRARY NUMBER *qqabs(NUMBER *x) @@ -44,7 +44,7 @@ LINK LIBRARY SEE ALSO cmp, epsilon, hypot, norm, near, obj -## Copyright (C) 1999,2021 Landon Curt Noll +## Copyright (C) 1999,2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/acos b/help/acos index df3c51c..5d45833 100644 --- a/help/acos +++ b/help/acos @@ -6,7 +6,7 @@ SYNOPSIS TYPES x real, -1 <= x <= 1 - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real @@ -21,7 +21,7 @@ EXAMPLE 1.0472 1.0471975512 1.047197551196598 1.04719755119659774615 LIMITS - none + 0 < eps < 1 LINK LIBRARY NUMBER *qacos(NUMBER *x, NUMBER *eps) @@ -29,7 +29,7 @@ LINK LIBRARY SEE ALSO asin, atan, asec, acsc, acot, epsilon -## Copyright (C) 1999 Landon Curt Noll +## Copyright (C) 1999,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/acosh b/help/acosh index 6ef8a78..5e4151a 100644 --- a/help/acosh +++ b/help/acosh @@ -6,7 +6,7 @@ SYNOPSIS TYPES x real, x >= 1 - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return nonnegative real @@ -24,7 +24,7 @@ EXAMPLE 1.31696 1.3169578969 1.316957896924817 1.31695789692481670862 LIMITS - none + 0 < eps < 1 LINK LIBRARY NUMBER *qacosh(NUMBER *x, NUMBER *eps) @@ -32,7 +32,7 @@ LINK LIBRARY SEE ALSO asinh, atanh, asech, acsch, acoth, epsilon -## Copyright (C) 1999 Landon Curt Noll +## Copyright (C) 1999,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/acot b/help/acot index 1e6a201..a8d7c10 100644 --- a/help/acot +++ b/help/acot @@ -6,7 +6,7 @@ SYNOPSIS TYPES x real - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real @@ -21,7 +21,7 @@ EXAMPLE 0.46365 0.463647609 0.463647609000806 0.46364760900080611621 LIMITS - none + 0 < eps < 1 LINK LIBRARY NUMBER *qacot(NUMBER *x, NUMBER *eps) @@ -29,7 +29,7 @@ LINK LIBRARY SEE ALSO asin, acos, atan, asec, acsc, epsilon -## Copyright (C) 1999,2021 Landon Curt Noll +## Copyright (C) 1999,2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/acoth b/help/acoth index 7153ad9..6aec4e7 100644 --- a/help/acoth +++ b/help/acoth @@ -6,7 +6,7 @@ SYNOPSIS TYPES x real, with abs(x) > 1 - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real @@ -23,7 +23,7 @@ EXAMPLE 0.54931 0.5493061443 0.549306144334055 0.5493061443340548457 LIMITS - none + 0 < eps < 1 LINK LIBRARY NUMBER *qacoth(NUMBER *x, NUMBER *eps) @@ -31,7 +31,7 @@ LINK LIBRARY SEE ALSO asinh, acosh, atanh, asech, acsch, epsilon -## Copyright (C) 1999,2021 Landon Curt Noll +## Copyright (C) 1999,2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/acsc b/help/acsc index 73d54dd..b47a6f6 100644 --- a/help/acsc +++ b/help/acsc @@ -6,7 +6,7 @@ SYNOPSIS TYPES x real, with absolute value >= 1 - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real @@ -21,7 +21,7 @@ EXAMPLE 0.5236 0.5235987756 0.523598775598299 0.52359877559829887308 LIMITS - none + 0 < eps < 1 LINK LIBRARY NUMBER *qacsc(NUMBER *x, NUMBER *eps) @@ -29,7 +29,7 @@ LINK LIBRARY SEE ALSO asin, acos, atan, asec, acot, epsilon -## Copyright (C) 1999,2021 Landon Curt Noll +## Copyright (C) 1999,2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/acsch b/help/acsch index dd832f3..1639574 100644 --- a/help/acsch +++ b/help/acsch @@ -6,7 +6,7 @@ SYNOPSIS TYPES x nonzero real - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real @@ -23,7 +23,7 @@ EXAMPLE 0.48121 0.4812118251 0.481211825059603 0.4812118250596034475 LIMITS - none + 0 < eps < 1 LINK LIBRARY NUMBER *qacsch(NUMBER *x, NUMBER *eps) @@ -31,7 +31,7 @@ LINK LIBRARY SEE ALSO asinh, acosh, atanh, asech, acoth, epsilon -## Copyright (C) 1999,2021 Landon Curt Noll +## Copyright (C) 1999,2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/arg b/help/arg index 51bbf9c..12aaf05 100644 --- a/help/arg +++ b/help/arg @@ -24,7 +24,7 @@ EXAMPLE 56.3099 135 -135 LIMITS - none + eps != 0 LINK LIBRARY none diff --git a/help/asec b/help/asec index 0bd537e..cc6c797 100644 --- a/help/asec +++ b/help/asec @@ -6,7 +6,7 @@ SYNOPSIS TYPES x real, with absolute value >= 1 - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real @@ -21,7 +21,7 @@ EXAMPLE 1.0472 1.0471975512 1.047197551196598 1.04719755119659774615 LIMITS - none + 0 < eps < 1 LINK LIBRARY NUMBER *qasec(NUMBER *x, NUMBER *eps) @@ -29,7 +29,7 @@ LINK LIBRARY SEE ALSO asin, acos, atan, acsc, acot, epsilon -## Copyright (C) 1999,2021 Landon Curt Noll +## Copyright (C) 1999,2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/asech b/help/asech index 7ee8051..6f65c3e 100644 --- a/help/asech +++ b/help/asech @@ -6,7 +6,7 @@ SYNOPSIS TYPES x real, 0 < x <= 1 - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real @@ -23,7 +23,7 @@ EXAMPLE 1.31696 1.3169578969 1.316957896924817 1.31695789692481670862 LIMITS - none + 0 < eps < 1 LINK LIBRARY NUMBER *qasech(NUMBER *x, NUMBER *eps) @@ -31,7 +31,7 @@ LINK LIBRARY SEE ALSO asinh, acosh, atanh, acsch, acoth, epsilon -## Copyright (C) 1999 Landon Curt Noll +## Copyright (C) 1999,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/asin b/help/asin index c45482b..a08b604 100644 --- a/help/asin +++ b/help/asin @@ -6,7 +6,7 @@ SYNOPSIS TYPES x real, -1 <= x <= 1 - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real @@ -21,7 +21,7 @@ EXAMPLE 0.5236 0.5235987756 0.523598775598299 0.52359877559829887308 LIMITS - none + 0 < eps < 1 LINK LIBRARY NUMBER *qasin(NUMBER *q, NUMBER *epsilon) @@ -29,7 +29,7 @@ LINK LIBRARY SEE ALSO acos, atan, asec, acsc, acot, epsilon -## Copyright (C) 1999,2021 Landon Curt Noll +## Copyright (C) 1999,2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/asinh b/help/asinh index 2dc6829..37fec39 100644 --- a/help/asinh +++ b/help/asinh @@ -6,7 +6,7 @@ SYNOPSIS TYPES x real - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real @@ -23,7 +23,7 @@ EXAMPLE 1.44363 1.4436354752 1.44363547517881 1.44363547517881034249 LIMITS - none + 0 < eps < 1 LINK LIBRARY NUMBER *qasinh(NUMBER *x, NUMBER *eps) @@ -31,7 +31,7 @@ LINK LIBRARY SEE ALSO acosh, atanh, asech, acsch, acoth, epsilon -## Copyright (C) 1999 Landon Curt Noll +## Copyright (C) 1999,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/atan b/help/atan index 0e8f08f..70fc6c1 100644 --- a/help/atan +++ b/help/atan @@ -6,7 +6,7 @@ SYNOPSIS TYPES x real - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real @@ -21,7 +21,7 @@ EXAMPLE 1.10715 1.1071487178 1.107148717794091 1.10714871779409050302 LIMITS - none + 0 < eps < 1 LINK LIBRARY NUMBER *qatan(NUMBER *x, NUMBER *eps) @@ -29,7 +29,7 @@ LINK LIBRARY SEE ALSO asin, acos, asec, acsc, acot, epsilon -## Copyright (C) 1999 Landon Curt Noll +## Copyright (C) 1999,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/atan2 b/help/atan2 index 3cc02cc..7298b6d 100644 --- a/help/atan2 +++ b/help/atan2 @@ -28,7 +28,7 @@ EXAMPLE 0 ~0.52359877559829887307 ~0.31038740713235146535 LIMITS - none + eps != 0 LINK LIBRARY NUMBER *qatan2(NUMBER *y, *x, *acc) @@ -36,7 +36,7 @@ LINK LIBRARY SEE ALSO acos, asin, atan, cos, epsilon, sin, tan -## Copyright (C) 1999,2021 Landon Curt Noll +## Copyright (C) 1999,2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/atanh b/help/atanh index d5dd2d9..3401b22 100644 --- a/help/atanh +++ b/help/atanh @@ -6,7 +6,7 @@ SYNOPSIS TYPES x real - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real @@ -23,7 +23,7 @@ EXAMPLE 0.54931 0.5493061443 0.549306144334055 0.5493061443340548457 LIMITS - none + 0 < eps < 1 LINK LIBRARY NUMBER *qatanh(NUMBER *x, NUMBER *eps) @@ -31,7 +31,7 @@ LINK LIBRARY SEE ALSO asinh, acosh, asech, acsch, acoth, epsilon -## Copyright (C) 1999,2021 Landon Curt Noll +## Copyright (C) 1999,2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/config b/help/config index 247077b..8987676 100644 --- a/help/config +++ b/help/config @@ -1034,7 +1034,7 @@ EXAMPLE 3.141592653589793238462643383279502884197169399375105820974944592307816406 LIMITS - none + 0 < epsilon < 1 LINK LIBRARY none diff --git a/help/cos b/help/cos index 8ae6dcc..2376cb3 100644 --- a/help/cos +++ b/help/cos @@ -6,7 +6,7 @@ SYNOPSIS TYPES x number (real or complex) - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return number @@ -26,7 +26,7 @@ EXAMPLE 0.5 0 -1 LIMITS - none + 0 < eps < 1 LINK LIBRARY NUMBER *qcos(NUMBER *x, NUMBER *eps) @@ -35,7 +35,7 @@ LINK LIBRARY SEE ALSO sin, tan, sec, csc, cot, epsilon -## Copyright (C) 1999,2021 Landon Curt Noll +## Copyright (C) 1999,2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/cosh b/help/cosh index 17d734b..8703116 100644 --- a/help/cosh +++ b/help/cosh @@ -6,13 +6,13 @@ SYNOPSIS TYPES x real - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real DESCRIPTION Calculate the cosh of x to the nearest or next to nearest multiple of - epsilon, with absolute error less than .75 * abs(eps). + epsilon, with absolute error less than .75 * eps. cosh(x) = (exp(x) + exp(-x))/2 @@ -21,7 +21,7 @@ EXAMPLE 1.54308 1.5430806348 1.543080634815244 1.54308063481524377848 LIMITS - none + 0 < eps < 1 LINK LIBRARY NUMBER *qcosh(NUMBER *x, NUMBER *eps) @@ -29,7 +29,7 @@ LINK LIBRARY SEE ALSO sinh, tanh, sech, csch, coth, epsilon -## Copyright (C) 1999 Landon Curt Noll +## Copyright (C) 1999,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/cot b/help/cot index aa44934..d6a47c2 100644 --- a/help/cot +++ b/help/cot @@ -6,7 +6,7 @@ SYNOPSIS TYPES x nonzero real - acc nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real @@ -19,7 +19,7 @@ EXAMPLE 0.64209 0.6420926159 0.642092615934331 0.64209261593433070301 LIMITS - none + 0 < eps < 1 LINK LIBRARY NUMBER *qcot(NUMBER *x, NUMBER *eps) @@ -27,7 +27,7 @@ LINK LIBRARY SEE ALSO sin, cos, tan, sec, csc, epsilon -## Copyright (C) 1999,2021 Landon Curt Noll +## Copyright (C) 1999,2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/coth b/help/coth index 093ed3e..1524ca3 100644 --- a/help/coth +++ b/help/coth @@ -6,7 +6,7 @@ SYNOPSIS TYPES x nonzero real - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real @@ -21,7 +21,7 @@ EXAMPLE 1.31304 1.3130352855 1.313035285499331 1.31303528549933130364 LIMITS - none + 0 < eps < 1 LINK LIBRARY NUMBER *qcoth(NUMBER *x, NUMBER *eps) @@ -29,7 +29,7 @@ LINK LIBRARY SEE ALSO sinh, cosh, tanh, sech, csch, epsilon -## Copyright (C) 1999 Landon Curt Noll +## Copyright (C) 1999,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/csc b/help/csc index 2e17d98..9c93928 100644 --- a/help/csc +++ b/help/csc @@ -6,7 +6,7 @@ SYNOPSIS TYPES x real - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real @@ -19,7 +19,7 @@ EXAMPLE 1.1884 1.1883951058 1.188395105778121 1.18839510577812121626 LIMITS - none + 0 < eps < 1 LINK LIBRARY NUMBER *qcsc(NUMBER *x, NUMBER *eps) @@ -27,7 +27,7 @@ LINK LIBRARY SEE ALSO sin, cos, tan, sec, cot, epsilon -## Copyright (C) 1999 Landon Curt Noll +## Copyright (C) 1999,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/csch b/help/csch index 9259331..f61b2ef 100644 --- a/help/csch +++ b/help/csch @@ -6,7 +6,7 @@ SYNOPSIS TYPES x nonzero real - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real @@ -21,7 +21,7 @@ EXAMPLE 0.85092 0.8509181282 0.850918128239322 0.85091812823932154513 LIMITS - none + 0 < eps < 1 LINK LIBRARY NUMBER *qcsch(NUMBER *x, NUMBER *eps) @@ -29,7 +29,7 @@ LINK LIBRARY SEE ALSO sinh, cosh, tanh, sech, coth, epsilon -## Copyright (C) 1999,2021 Landon Curt Noll +## Copyright (C) 1999,2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/d2g b/help/d2g index 3962c5f..7eae474 100644 --- a/help/d2g +++ b/help/d2g @@ -6,7 +6,7 @@ SYNOPSIS TYPES x number (real or complex) - eps nonzero real, defaults to epsilon() + eps eps value is ignored return number @@ -32,7 +32,7 @@ SEE ALSO d2r, r2d, g2r, r2g, g2d, sin, cos, tan, sec, csc, cot, epsilon -## Copyright (C) 2021 Landon Curt Noll +## Copyright (C) 2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/d2r b/help/d2r index 78f715f..e1f343a 100644 --- a/help/d2r +++ b/help/d2r @@ -6,7 +6,7 @@ SYNOPSIS TYPES x number (real or complex) - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return number @@ -27,7 +27,7 @@ EXAMPLE 0.5 0.5 1 LIMITS - eps > 0 + 0 < eps < 1 LINK LIBRARY NUMBER *qpidiv180(NUMBER *eps) @@ -36,7 +36,7 @@ SEE ALSO r2d, g2r, r2g, d2g, g2d, sin, cos, tan, sec, csc, cot, epsilon -## Copyright (C) 2021 Landon Curt Noll +## Copyright (C) 2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/epsilon b/help/epsilon index 5f0aa7e..6fc7a5d 100644 --- a/help/epsilon +++ b/help/epsilon @@ -5,7 +5,7 @@ SYNOPSIS epsilon([eps]) TYPES - eps real number greater than 0 and less than 1 + eps 0 < real < 1, defaults to epsilon() return real number greater than 0 and less than 1 @@ -72,7 +72,7 @@ EXAMPLE 3.141592653589793238462643383279502884197169399375105820974944592307816406 LIMITS - none + 0 < eps < 1 LINK LIBRARY void setepsilon(NUMBER *eps) @@ -81,7 +81,7 @@ LINK LIBRARY SEE ALSO config, display, fprintf, printf, strprintf -## Copyright (C) 1999,2018,2021 Landon Curt Noll +## Copyright (C) 1999,2018,2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/exp b/help/exp index d35bdf8..6d12322 100644 --- a/help/exp +++ b/help/exp @@ -6,7 +6,7 @@ SYNOPSIS TYPES x real or complex - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real or complex @@ -32,6 +32,7 @@ EXAMPLE LIMITS x < 693093 + 0 < eps < 1 LINK LIBRARY NUMBER *qexp(NUMBER *x, NUMBER *eps) @@ -40,7 +41,7 @@ LINK LIBRARY SEE ALSO ln, cosh, sinh, tanh -## Copyright (C) 1999,2021 Landon Curt Noll +## Copyright (C) 1999,2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/g2d b/help/g2d index a051370..fcbdc83 100644 --- a/help/g2d +++ b/help/g2d @@ -6,7 +6,7 @@ SYNOPSIS TYPES x number (real or complex) - eps nonzero real, defaults to epsilon() + eps eps value is ignored return number @@ -32,7 +32,7 @@ SEE ALSO d2r, r2d, g2r, r2g, d2g, sin, cos, tan, sec, csc, cot, epsilon -## Copyright (C) 2021 Landon Curt Noll +## Copyright (C) 2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/g2r b/help/g2r index ef590d4..0768392 100644 --- a/help/g2r +++ b/help/g2r @@ -6,7 +6,7 @@ SYNOPSIS TYPES x number (real or complex) - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return number @@ -27,7 +27,7 @@ EXAMPLE 0.5 0.5 1 LIMITS - eps > 0 + 0 < eps < 1 LINK LIBRARY NUMBER *qpidiv200(NUMBER *eps) @@ -36,7 +36,7 @@ SEE ALSO d2r, r2d, r2g, d2g, g2d, sin, cos, tan, sec, csc, cot, epsilon -## Copyright (C) 2021 Landon Curt Noll +## Copyright (C) 2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/gd b/help/gd index 398e5f1..2731766 100644 --- a/help/gd +++ b/help/gd @@ -6,7 +6,7 @@ SYNOPSIS TYPES z number (real or complex) - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return number or "Log of zero or infinity" error value @@ -42,7 +42,7 @@ EXAMPLE 1.42291+0.22751i 1.4229114625+0.2275106584i LIMITS - none + 0 < eps < 1 LINK LIBRARY COMPLEX *c_gd(COMPLEX *x, NUMBER *eps) @@ -50,7 +50,7 @@ LINK LIBRARY SEE ALSO agd, exp, ln, sin, sinh, etc. -## Copyright (C) 1999,2021 Landon Curt Noll +## Copyright (C) 1999,2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/hypot b/help/hypot index e12d2a2..f29b9c4 100644 --- a/help/hypot +++ b/help/hypot @@ -6,7 +6,7 @@ SYNOPSIS TYPES x, y real - eps nonzero real + eps nonzero real, defaults to epsilon() return real @@ -19,7 +19,7 @@ EXAMPLE 5 3.605551 LIMITS - none + eps != 0 LINK LIBRARY NUMBER *qhypot(NUMBER *q1, *q2, *epsilon) @@ -27,7 +27,7 @@ LINK LIBRARY SEE ALSO ltol -## Copyright (C) 1999 Landon Curt Noll +## Copyright (C) 1999,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/ln b/help/ln index 58d1597..98eb4b7 100644 --- a/help/ln +++ b/help/ln @@ -6,7 +6,7 @@ SYNOPSIS TYPES x nonzero real or complex - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real or complex @@ -25,7 +25,7 @@ EXAMPLE LIMITS x != 0 - eps > 0 + 0 < eps < 1 LINK LIBRARY NUMBER *qln(NUMBER *x, NUMBER *eps) diff --git a/help/log b/help/log index 90ceafb..5cd23d3 100644 --- a/help/log +++ b/help/log @@ -6,7 +6,7 @@ SYNOPSIS TYPES x nonzero real or complex - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real or complex @@ -29,7 +29,7 @@ EXAMPLE LIMITS x != 0 - eps > 0 + 0 < eps < 1 LINK LIBRARY NUMBER *qlog(NUMBER *x, NUMBER *eps) @@ -38,7 +38,7 @@ LINK LIBRARY SEE ALSO ilog, ilogn, ilog10, ilog2, ln, log2, logn -## Copyright (C) 2006 Landon Curt Noll +## Copyright (C) 2006,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/log2 b/help/log2 index 21c8569..913b94e 100644 --- a/help/log2 +++ b/help/log2 @@ -6,7 +6,7 @@ SYNOPSIS TYPES x nonzero real or complex - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real or complex @@ -17,7 +17,7 @@ DESCRIPTION When x is an integer power of 2, log2(x) will return an integer regardless of the value of eps or epsilon(). - If y is a positive integer, log(x, 2^-y) will usually be correct + If y is a positive integer, log2(x, 2^-y) will usually be correct to the y-th decimal place. EXAMPLE @@ -41,7 +41,7 @@ EXAMPLE LIMITS x != 0 - eps > 0 + 0 < eps < 1 LINK LIBRARY NUMBER *qlog2(NUMBER *x, NUMBER *eps) diff --git a/help/logn b/help/logn index 6f6a0a6..4b51c89 100644 --- a/help/logn +++ b/help/logn @@ -7,7 +7,7 @@ SYNOPSIS TYPES x nonzero real or complex n nonzero real or complex - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real or complex @@ -17,26 +17,45 @@ DESCRIPTION The base, n, must not be 0 nor 1. - If y is a positive integer, log(x, n^-y) will usually be correct + When x = 2^a is an integer power of 2 and when n = 2^b is an + integer power of 2, then log2(x, n) will return a/b + regardless of the value of eps or epsilon(). + + If y is a positive integer, logn(x, n, m^-y) will usually be correct to the y-th decimal place. EXAMPLE - ; print logn(15.625, 2.5), logn(15.625, 2.5, 1e-25) - ~3.00000000000000000001 3 + ; print logn(2, 2), logn(4, 2), logn(1024, 2), logn(2^500, 2), logn(1/2^23209, 2) + 1 2 10 500 -23209 - ; print logn(127, 1/13), log(23209, sqrt(3)), logn(2^17-19, 17) - ~-1.88860925162778125111 6 ~4.15900804831225415076 + ; print logn(2, 42), logn(1024, 42), logn(2^500, 42), logn(1/2^23209, 42) + 0.18544902341536890054 1.85449023415368900542 92.72451170768445027095 -4304.08638444729681267682 + + ; print logn(127, 1/13), logn(23209, sqrt(3)), logn(2^17-19, 17) + -1.88860925162778125111 18.29998720595030380546 4.15900804831225415076 ; print logn(-1, 1i), logn(2+3i, 3i+2), logn(2+3i, 3i) - 2 1 ~0.80360095345990217753-~0.25441159318835790311i + 2 1 0.80360095345990217753-0.25441159318835790311i - ; print logn(22+3i, 3i, 1e-50) - ~0.98489914201047045408-~1.28484657882287682702i + ; print logn(22+3i, 3i), logn(22+3i, 3i, 1e-50) + 0.98489914201047045409-1.28484657882287682702i 0.98489914201047045408-1.28484657882287682702i + + ; print logn(-127, 7), logn(-127i, 7i) + 2.48941971386002223933+1.61445925708078115429i 1.11272593230445294959-1.70545496954177392315i + + ; print logn(2+3i, 4), logn(-2+3i, 4i) + 0.92510992953527304010+0.70893581537286099830i 1.17764179178059522911+0.22287007593665359808i + + ; print logn(2-3i, 4), logn(-2-3i, 4i) + 0.92510992953527304010-0.70893581537286099830i -0.36752510241663632776-1.14080522421220596732i + + ; print logn(17+0.3i, 17, 1e-75), logn(-17-0.3i, 17i, 1e-75) + 1.00005495001021376506+0.00622799102938744640i 0.29734185630294053511-1.26746929577868497155i LIMITS x != 0 n != 0 && n != 1 - eps > 0 + 0 < eps < 1 LINK LIBRARY NUMBER *qlogn(NUMBER *x, NUMBER *n, NUMBER *eps) diff --git a/help/ltol b/help/ltol index 49d8550..0c45093 100644 --- a/help/ltol +++ b/help/ltol @@ -7,7 +7,7 @@ SYNOPSIS TYPES x real - eps nonzero real + eps nonzero real, defaults to epsilon() return real @@ -21,6 +21,7 @@ EXAMPLE LIMITS abs(x) <= 1 + eps != 0 LINK LIBRARY NUMBER *qlegtoleg(NUMBER *q1, *epsilon, BOOL wantneg) @@ -28,7 +29,7 @@ LINK LIBRARY SEE ALSO hypot -## Copyright (C) 1999,2021 Landon Curt Noll +## Copyright (C) 1999,2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/near b/help/near index 765cb20..2f81c6c 100644 --- a/help/near +++ b/help/near @@ -7,7 +7,7 @@ SYNOPSIS TYPES x real y real - eps real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return -1, 0 or 1 @@ -22,7 +22,7 @@ EXAMPLE -1 1 LIMITS - eps >= 0 + 0 < eps < 1 LINK LIBRARY FLAG qnear(NUMBER *x, NUMBER *y, NUMBER *eps) @@ -30,7 +30,7 @@ LINK LIBRARY SEE ALSO epsilon, abs -## Copyright (C) 1999 Landon Curt Noll +## Copyright (C) 1999,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/pi b/help/pi index 7a7f20a..f77b0a2 100644 --- a/help/pi +++ b/help/pi @@ -5,7 +5,7 @@ SYNOPSIS pi([eps]) TYPES - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real @@ -18,7 +18,7 @@ EXAMPLE 3.14159 3.1415926536 3.141592653589793 3.14159265358979323846 LIMITS - eps > 0 + 0 < eps < 1 LINK LIBRARY NUMBER *qpi(NUMBER *eps) @@ -26,7 +26,7 @@ LINK LIBRARY SEE ALSO atan2 -## Copyright (C) 1999-2006 Landon Curt Noll +## Copyright (C) 1999-2006,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/polar b/help/polar index 3c2e39f..50519ae 100644 --- a/help/polar +++ b/help/polar @@ -26,7 +26,7 @@ EXAMPLE 1.41421+1.41421i 2i -1.414215+1.41421i LIMITS - none + eps != 0 LINK LIBRARY COMPLEX *c_polar(NUMBER *r, NUMBER *t, NUMBER *eps); @@ -34,7 +34,7 @@ LINK LIBRARY SEE ALSO abs, arg, re, im -## Copyright (C) 1999,2021 Landon Curt Noll +## Copyright (C) 1999,2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/power b/help/power index 0f09f3e..0a94590 100644 --- a/help/power +++ b/help/power @@ -45,7 +45,7 @@ LIMITS except in the case of y = 0; power(0, 0, eps) is the multiple of eps nearest 1. - eps > 0 + eps != 0 LINK LIBRARY void powervalue(VALUE *x, VALUE *y, VALUE *eps, VALUE *result) @@ -55,7 +55,7 @@ LINK LIBRARY SEE ALSO root -## Copyright (C) 1999,2021 Landon Curt Noll +## Copyright (C) 1999,2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/r2d b/help/r2d index 5718375..78ec638 100644 --- a/help/r2d +++ b/help/r2d @@ -6,7 +6,7 @@ SYNOPSIS TYPES x number (real or complex) - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return number @@ -25,7 +25,7 @@ EXAMPLE 180+~229.18311805232928350739i 60+180, 36+900i LIMITS - eps > 0 + 0 < eps < 1 LINK LIBRARY NUMBER *qpidiv180(NUMBER *eps) @@ -34,7 +34,7 @@ SEE ALSO d2r, g2r, r2g, d2g, g2d, sin, cos, tan, sec, csc, cot, epsilon -## Copyright (C) 2021 Landon Curt Noll +## Copyright (C) 2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/r2g b/help/r2g index 250928b..6fa4af5 100644 --- a/help/r2g +++ b/help/r2g @@ -6,7 +6,7 @@ SYNOPSIS TYPES x number (real or complex) - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return number @@ -25,7 +25,7 @@ EXAMPLE 200+~254.64790894703253723043i 50+200i 40+1000i LIMITS - eps > 0 + 0 < eps < 1 LINK LIBRARY NUMBER *qpidiv200(NUMBER *eps) @@ -34,7 +34,7 @@ SEE ALSO d2r, r2d, g2r, d2g, g2d, sin, cos, tan, sec, csc, cot, epsilon -## Copyright (C) 2021 Landon Curt Noll +## Copyright (C) 2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/root b/help/root index 7d2ae9e..56c88ba 100644 --- a/help/root +++ b/help/root @@ -42,7 +42,7 @@ EXAMPLE LIMITS n >= 0 - eps > 0 + eps != 0 LINK LIBRARY void rootvalue(VALUE *x, VALUE *n, VALUE *eps, VALUE *result) @@ -52,7 +52,7 @@ LINK LIBRARY SEE ALSO power -## Copyright (C) 1999,2021 Landon Curt Noll +## Copyright (C) 1999,2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/sec b/help/sec index 51e3d3e..eb7696e 100644 --- a/help/sec +++ b/help/sec @@ -6,7 +6,7 @@ SYNOPSIS TYPES x real - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real @@ -20,7 +20,7 @@ EXAMPLE LIMITS unlike sin and cos, x must be real - eps > 0 + 0 < eps < 1 LINK LIBRARY NUMBER *qsec(NUMBER *x, NUMBER *eps) @@ -28,7 +28,7 @@ LINK LIBRARY SEE ALSO sin, cos, tan, csc, cot, epsilon -## Copyright (C) 1999 Landon Curt Noll +## Copyright (C) 1999,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/sech b/help/sech index 5eecec2..72fe724 100644 --- a/help/sech +++ b/help/sech @@ -6,7 +6,7 @@ SYNOPSIS TYPES x real - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real @@ -22,7 +22,7 @@ EXAMPLE LIMITS unlike sin and cos, x must be real - eps > 0 + 0 < eps < 1 LINK LIBRARY NUMBER *qsech(NUMBER *x, NUMBER *eps) @@ -30,7 +30,7 @@ LINK LIBRARY SEE ALSO sinh, cosh, tanh, csch, coth, epsilon -## Copyright (C) 1999,2021 Landon Curt Noll +## Copyright (C) 1999,2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/sin b/help/sin index 3fa044b..97b102e 100644 --- a/help/sin +++ b/help/sin @@ -6,7 +6,7 @@ SYNOPSIS TYPES x number (real or complex) - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return number @@ -26,7 +26,7 @@ EXAMPLE 0.5 1 0 LIMITS - eps > 0 + 0 < eps < 1 LINK LIBRARY NUMBER *qsin(NUMBER *x, NUMBER *eps) @@ -35,7 +35,7 @@ LINK LIBRARY SEE ALSO cos, tan, sec, csc, cot, epsilon -## Copyright (C) 1999,2021 Landon Curt Noll +## Copyright (C) 1999,2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/sinh b/help/sinh index df117d4..62bf93c 100644 --- a/help/sinh +++ b/help/sinh @@ -6,7 +6,7 @@ SYNOPSIS TYPES x real - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real @@ -22,7 +22,7 @@ EXAMPLE LIMITS unlike sin and cos, x must be real - eps > 0 + 0 < eps < 1 LINK LIBRARY NUMBER *qsinh(NUMBER *x, NUMBER *eps) @@ -30,7 +30,7 @@ LINK LIBRARY SEE ALSO cosh, tanh, sech, csch, coth, epsilon -## Copyright (C) 1999 Landon Curt Noll +## Copyright (C) 1999,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/sqrt b/help/sqrt index bf31195..1e187ae 100644 --- a/help/sqrt +++ b/help/sqrt @@ -15,7 +15,7 @@ TYPES For other argument types: x real or complex - eps nonzero real + eps 0 < real < 1, defaults to epsilon() z integer return real or complex @@ -119,7 +119,7 @@ EXAMPLE 0 0.0002 LIMITS - none + 0 < eps < 1 LINK LIBRARY COMPLEX *c_sqrt(COMPLEX *x, NUMBER *ep, long z) @@ -130,7 +130,7 @@ LINK LIBRARY SEE ALSO appr, epsilon -## Copyright (C) 1999,2021 Landon Curt Noll +## Copyright (C) 1999,2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/tan b/help/tan index 43f1b98..d66166d 100644 --- a/help/tan +++ b/help/tan @@ -6,7 +6,7 @@ SYNOPSIS TYPES x real - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real @@ -20,7 +20,7 @@ EXAMPLE LIMITS unlike sin and cos, x must be real - eps > 0 + 0 < eps < 1 LINK LIBRARY NUMBER *qtan(NUMBER *x, NUMBER *eps) @@ -28,7 +28,7 @@ LINK LIBRARY SEE ALSO sin, cos, sec, csc, cot, epsilon -## Copyright (C) 1999 Landon Curt Noll +## Copyright (C) 1999,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/tanh b/help/tanh index 246c197..85c12b1 100644 --- a/help/tanh +++ b/help/tanh @@ -6,7 +6,7 @@ SYNOPSIS TYPES x real - eps nonzero real, defaults to epsilon() + eps 0 < real < 1, defaults to epsilon() return real @@ -22,7 +22,7 @@ EXAMPLE LIMITS unlike sin and cos, x must be real - eps > 0 + 0 < eps < 1 LINK LIBRARY NUMBER *qtanh(NUMBER *x, NUMBER *eps) @@ -30,7 +30,7 @@ LINK LIBRARY SEE ALSO sinh, cosh, sech, csch, coth, epsilon -## Copyright (C) 1999,2021 Landon Curt Noll +## Copyright (C) 1999,2021,2023 Landon Curt Noll ## ## Calc is open software; you can redistribute it and/or modify it under ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/qmath.h b/qmath.h index 5b95cc2..99c02aa 100644 --- a/qmath.h +++ b/qmath.h @@ -189,6 +189,7 @@ E_FUNC NUMBER *qexp(NUMBER *q, NUMBER *epsilon); E_FUNC NUMBER *qln(NUMBER *q, NUMBER *epsilon); E_FUNC NUMBER *qlog(NUMBER *q, NUMBER *epsilon); E_FUNC NUMBER *qlog2(NUMBER *q, NUMBER *epsilon); +E_FUNC NUMBER *qlogn(NUMBER *q, NUMBER *n, NUMBER *epsilon); E_FUNC NUMBER *qtan(NUMBER *q, NUMBER *epsilon); E_FUNC NUMBER *qsec(NUMBER *q, NUMBER *epsilon); E_FUNC NUMBER *qcot(NUMBER *q, NUMBER *epsilon); diff --git a/qtrans.c b/qtrans.c index dcef696..c977739 100644 --- a/qtrans.c +++ b/qtrans.c @@ -49,6 +49,8 @@ STATIC NUMBER *ln_10 = NULL; STATIC NUMBER *ln_10_epsilon = NULL; STATIC NUMBER *ln_2 = NULL; STATIC NUMBER *ln_2_epsilon = NULL; +STATIC NUMBER *ln_n = NULL; +STATIC NUMBER *ln_n_epsilon = NULL; /* * cache pi @@ -1049,10 +1051,14 @@ qln(NUMBER *q, NUMBER *epsilon) NUMBER *qtmp, *res; bool neg; - if (qiszero(q) || qiszero(epsilon)) { + if (qiszero(q)) { math_error("logarithm of 0"); not_reached(); } + if (qiszero(epsilon)) { + math_error("Zero epsilon value for ln"); + not_reached(); + } if (qisunit(q)) return qlink(&_qzero_); q = qqabs(q); /* Ignore sign of q */ @@ -1161,10 +1167,14 @@ qlog(NUMBER *q, NUMBER *epsilon) NUMBER *ret; /* base 10 logarithm of x */ /* firewall */ - if (qiszero(q) || qiszero(epsilon)) { + if (qiszero(q)) { math_error("logarithm of 0"); not_reached(); } + if (qiszero(epsilon)) { + math_error("Zero epsilon value for log"); + not_reached(); + } /* * shortcut for small integer powers of 10 @@ -1238,10 +1248,14 @@ qlog2(NUMBER *q, NUMBER *epsilon) NUMBER *ret; /* base 2 logarithm of x */ /* firewall */ - if (qiszero(q) || qiszero(epsilon)) { + if (qiszero(q)) { math_error("logarithm of 0"); not_reached(); } + if (qiszero(epsilon)) { + math_error("Zero epsilon value for log2"); + not_reached(); + } /* * special case: q is integer power of 2 @@ -1256,7 +1270,7 @@ qlog2(NUMBER *q, NUMBER *epsilon) * compute ln(c) first */ ln_q = qln(q, epsilon); - /* quick return for log(1) == 0 */ + /* quick return for ln(1) == 0 */ if (qiszero(ln_q)) { return ln_q; } @@ -1295,6 +1309,89 @@ qlog2(NUMBER *q, NUMBER *epsilon) } +/* + * Calculate the base n logarithm + * + * logn(q, n) = ln(q) / ln(n) + */ +NUMBER * +qlogn(NUMBER *q, NUMBER *n, NUMBER *epsilon) +{ + int need_new_ln_n = true; /* false => use cached ln_n value */ + NUMBER *ln_q; /* ln(x) */ + NUMBER *ret; /* base 2 logarithm of x */ + + /* firewall */ + if (qiszero(q)) { + math_error("logarithm of 0"); + not_reached(); + } + if (qiszero(epsilon)) { + math_error("Zero epsilon value for logn"); + not_reached(); + } + if (qiszero(n)) { + math_error("invalid logarithm base of 0 for logn"); + not_reached(); + } + if (qisone(n)) { + math_error("invalid logarithm base of 1 for logn"); + not_reached(); + } + + /* + * special case: q is integer power of 2 + */ + ret = qalloc(); + if (qispowerof2(q, &ret)) { + return ret; + } + /* XXX - deal with n is integer power of 2 - XXX */ + qfree(ret); + + /* + * compute ln(q) first + */ + ln_q = qln(q, epsilon); + /* quick return for ln(1) == 0 */ + if (qiszero(ln_q)) { + return ln_q; + } + + /* + * save epsilon for ln(n) if needed + */ + if (ln_n_epsilon == NULL) { + /* first time call */ + ln_n_epsilon = qcopy(epsilon); + } else if (qcmp(ln_n_epsilon, epsilon) == true) { + /* replaced cached value with epsilon arg */ + qfree(ln_n_epsilon); + ln_n_epsilon = qcopy(epsilon); + } else if (ln_n != NULL) { + /* the previously computed ln(2) is OK to use */ + need_new_ln_n = false; + } + + /* + * compute ln(n) if needed + */ + if (need_new_ln_n == true) { + if (ln_n != NULL) { + qfree(ln_n); + } + ln_n = qln(&_qtwo_, ln_n_epsilon); + } + + /* + * return ln(q) / ln(2) + */ + ret = qqdiv(ln_q, ln_n); + qfree(ln_q); + return ret; +} + + /* * Calculate the result of raising one number to the power of another. * The result is calculated to the nearest or next to nearest multiple of