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