diff --git a/CHANGES b/CHANGES index b56b723..17873c4 100644 --- a/CHANGES +++ b/CHANGES @@ -128,7 +128,13 @@ The following are the changes from calc version 2.14.3.5 to date: Added c_to_q(COMPLEX *c, bool cfree) to make is easier to convert a COMPLEX value that is real (imag part is 0) into a NUMBER and - optionally free the COMPLEX value. + optionally free the COMPLEX value. The func.c code now uses c_to_q(). + + Added new vercos(x, [,eps]) for versed cosine and covercos(x, [,eps]) + for inverse versed cosine. + + Added new avercos(x, [,eps]) for inverse versed cosine and acovercos(x, [,eps]) + for inverse coversed cosine. 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 73a71f6..3f39acd 100644 --- a/cal/regress.cal +++ b/cal/regress.cal @@ -3506,9 +3506,9 @@ define test_trig() /* test 3401-3407 */ tnum = test3400(1, 3401); vrfy(tnum++ == 3407, '3407: tnum == 3407'); + pi = pi(1e-20); /* test versed trigonometric sine */ - pi = pi(1e-20); vrfy(round(versin(0.2, 1e-10), 10) == 0.0199334222, strcat(str(tnum++), ': round(versin(0.2, 1e-10), 10) == 0.0199334222')); @@ -3533,8 +3533,20 @@ define test_trig() strcat(str(tnum++), ': round(versin(2 + 3i, 1e-10), 10) == 5.189625691+9.1092278938i')); + /* test inverse versed trigonometric sine */ + vrfy(round(aversin(0.5, 1e-10), 10) == 1.0471975512, + strcat(str(tnum++), + ': round(aversin(0.5, 1e-10), 10) == 1.0471975512')); + vrfy(aversin(0) == 0, + strcat(str(tnum++), ': aversin(0) == 0')); + vrfy(round(aversin(-5, 1e-10), 10) == 2.4778887303i, + strcat(str(tnum++), + ': round(aversin(-5, 1e-10), 10) == 2.4778887303i')); + vrfy(round(aversin(2 + 3i, 1e-10), 10) == 1.8783999763+1.8641615439i, + strcat(str(tnum++), + ': round(aversin(2 + 3i, 1e-10), 10) == 1.8783999763+1.8641615439i')); + /* test coversed trigonometric sine */ - pi = pi(1e-20); vrfy(round(coversin(0.2, 1e-10), 10) == 0.8013306692, strcat(str(tnum++), ': round(coversin(0.2, 1e-10), 10) == 0.8013306692')); @@ -3559,19 +3571,6 @@ define test_trig() strcat(str(tnum++), ': round(coversin(2 + 3i, 1e-10), 10) == -8.1544991469+4.16890696i')); - /* test inverse versed trigonometric sine */ - vrfy(round(aversin(0.5, 1e-10), 10) == 1.0471975512, - strcat(str(tnum++), - ': round(aversin(0.5, 1e-10), 10) == 1.0471975512')); - vrfy(aversin(0) == 0, - strcat(str(tnum++), ': aversin(0) == 0')); - vrfy(round(aversin(-5, 1e-10), 10) == 2.4778887303i, - strcat(str(tnum++), - ': round(aversin(-5, 1e-10), 10) == 2.4778887303i')); - vrfy(round(aversin(2 + 3i, 1e-10), 10) == 1.8783999763+1.8641615439i, - strcat(str(tnum++), - ': round(aversin(2 + 3i, 1e-10), 10) == 1.8783999763+1.8641615439i')); - /* test inverse coversed trigonometric sine */ vrfy(round(acoversin(0.5, 1e-10), 10) == 0.5235987756, strcat(str(tnum++), @@ -3585,6 +3584,82 @@ define test_trig() strcat(str(tnum++), ': round(acoversin(2 + 3i, 1e-10), 10) == -0.3076036495-1.8641615442i')); + /* test versed trigonometric cosine */ + vrfy(round(vercos(0.2, 1e-10), 10) == 1.9800665778, + strcat(str(tnum++), + ': round(vercos(0.2, 1e-10), 10) == 1.9800665778')); + vrfy(round(vercos(3/7, 1e-10), 10) == 1.9095603517, + strcat(str(tnum++), + ': round(vercos(3/7, 1e-10), 10) == 1.9095603517')); + vrfy(round(vercos(-31, 1e-10), 10) == 1.9147423578, + strcat(str(tnum++), + ': round(vercos(-31, 1e-10), 10) == 1.9147423578')); + vrfy(vercos(pi/3, 1e-10) == 1.5, + strcat(str(tnum++), ': vercos(pi/3, 1e-10) == 1.5')); + vrfy(vercos(pi/2, 1e-10) == 1, + strcat(str(tnum++), ': vercos(pi/2, 1e-10) == 1')); + vrfy(vercos(pi, 1e-10) == 0, + strcat(str(tnum++), ': vercos(pi, 1e-10) == 0')); + vrfy(vercos(3*pi/2, 1e-10) == 1, + strcat(str(tnum++), ': vercos(3*pi/2, 1e-10) == 1')); + vrfy(round(vercos(1, 1e-10), 10) == 1.5403023059, + strcat(str(tnum++), + ': round(vercos(1, 1e-10), 10) == 1.5403023059')); + vrfy(round(vercos(2 + 3i, 1e-10), 10) == -3.189625691-9.1092278938i, + strcat(str(tnum++), + ': round(vercos(2 + 3i, 1e-10), 10) == -3.189625691-9.1092278938i')); + + /* test inverse versed trigonometric cosine */ + vrfy(round(avercos(0.5, 1e-10), 10) == 2.0943951024, + strcat(str(tnum++), + ': round(avercos(0.5, 1e-10), 10) == 2.0943951024')); + vrfy(avercos(2) == 0, + strcat(str(tnum++), ': avercos(2) == 0')); + vrfy(round(avercos(-5, 1e-10), 10) == 3.1415926536-2.4778887303i, + strcat(str(tnum++), + ': round(avercos(-5, 1e-10), 10) == 3.1415926536-2.4778887303i')); + vrfy(round(avercos(2 + 3i, 1e-10), 10) == 1.2631926773-1.8641615442i, + strcat(str(tnum++), + ': round(avercos(2 + 3i, 1e-10), 10) == 1.2631926773-1.8641615442i')); + + /* test coversed trigonometric cosine */ + vrfy(round(covercos(0.2, 1e-10), 10) == 1.1986693308, + strcat(str(tnum++), + ': round(covercos(0.2, 1e-10), 10) == 1.1986693308')); + vrfy(round(covercos(3/7, 1e-10), 10) == 1.415571855, + strcat(str(tnum++), + ': round(covercos(3/7, 1e-10), 10) == 1.415571855')); + vrfy(round(covercos(-31, 1e-10), 10) == 1.4040376453, + strcat(str(tnum++), + ': round(covercos(-31, 1e-10), 10) == 1.4040376453')); + vrfy(covercos(pi/6, 1e-10) == 1.5, + strcat(str(tnum++), ': covercos(pi/6, 1e-10) == 1.5')); + vrfy(covercos(pi/2, 1e-10) == 2, + strcat(str(tnum++), ': covercos(pi/2, 1e-10) == 2')); + vrfy(covercos(pi, 1e-10) == 1, + strcat(str(tnum++), ': covercos(pi, 1e-10) == 1')); + vrfy(covercos(3*pi/2, 1e-10) == 0, + strcat(str(tnum++), ': covercos(3*pi/2, 1e-10) == 0')); + vrfy(round(covercos(1, 1e-10), 10) == 1.8414709848, + strcat(str(tnum++), + ': round(covercos(1, 1e-10), 10) == 1.8414709848')); + vrfy(round(covercos(2 + 3i, 1e-10), 10) == 10.1544991469-4.16890696i, + strcat(str(tnum++), + ': round(covercos(2 + 3i, 1e-10), 10) == 10.1544991469-4.16890696i')); + + /* test inverse coversed trigonometric cosine */ + vrfy(round(acovercos(0.5, 1e-10), 10) == 0.5235987756, + strcat(str(tnum++), + ': round(acovercos(0.5, 1e-10), 10) == 0.5235987756')); + vrfy(acovercos(1) == 0, + strcat(str(tnum++), ': acovercos(1) == 0')); + vrfy(round(acovercos(-5, 1e-10), 10) == -1.5707963268+2.4778887303i, + strcat(str(tnum++), + ': round(acovercos(-5, 1e-10), 10) == -1.5707963268+2.4778887303i')); + vrfy(round(acovercos(2 + 3i, 1e-10), 10) == 0.3076036495+1.8641615442i, + strcat(str(tnum++), + ': round(acovercos(2 + 3i, 1e-10), 10) == 0.3076036495+1.8641615442i')); + print strcat(str(tnum++), ': Ending test_trig'); } print '051: parsed test_trig()'; diff --git a/calcerr.tbl b/calcerr.tbl index 446c75b..43de54e 100644 --- a/calcerr.tbl +++ b/calcerr.tbl @@ -562,3 +562,15 @@ E_COVERSIN3 Too-large im(argument) for coversin E_ACOVERSIN1 Bad epsilon for acoversin E_ACOVERSIN2 Bad first argument for acoversin E_ACOVERSIN3 Too-large im(argument) for acoversin +E_VERCOS1 Bad epsilon for vercos +E_VERCOS2 Bad first argument for vercos +E_VERCOS3 Too-large im(argument) for vercos +E_AVERCOS1 Bad epsilon for avercos +E_AVERCOS2 Bad first argument for avercos +E_AVERCOS3 Too-large im(argument) for avercos +E_COVERCOS1 Bad epsilon for covercos +E_COVERCOS2 Bad first argument for covercos +E_COVERCOS3 Too-large im(argument) for covercos +E_ACOVERCOS1 Bad epsilon for acovercos +E_ACOVERCOS2 Bad first argument for acovercos +E_ACOVERCOS3 Too-large im(argument) for acovercos diff --git a/cmath.h b/cmath.h index 9febb79..3660428 100644 --- a/cmath.h +++ b/cmath.h @@ -127,6 +127,10 @@ E_FUNC COMPLEX *c_versin(COMPLEX *c, NUMBER *epsilon); E_FUNC COMPLEX *c_aversin(COMPLEX *c, NUMBER *epsilon); E_FUNC COMPLEX *c_coversin(COMPLEX *c, NUMBER *epsilon); E_FUNC COMPLEX *c_acoversin(COMPLEX *c, NUMBER *epsilon); +E_FUNC COMPLEX *c_vercos(COMPLEX *c, NUMBER *epsilon); +E_FUNC COMPLEX *c_avercos(COMPLEX *c, NUMBER *epsilon); +E_FUNC COMPLEX *c_covercos(COMPLEX *c, NUMBER *epsilon); +E_FUNC COMPLEX *c_acovercos(COMPLEX *c, NUMBER *epsilon); diff --git a/comfunc.c b/comfunc.c index b994f2b..8a7e9a3 100644 --- a/comfunc.c +++ b/comfunc.c @@ -1428,7 +1428,7 @@ c_aversin(COMPLEX *c, NUMBER *epsilon) * * This uses the formula: * - * coversin(x) = 1 - sin(x) + * coversin(x) = 1 - cos(x) * * given: * q complex value to pass to the trig function @@ -1517,3 +1517,195 @@ c_acoversin(COMPLEX *c, NUMBER *epsilon) */ return r; } + + +/* + * c_vercos - versed sine for COMPLEX values + * + * This uses the formula: + * + * vercos(x) = 1 + cos(x) + * + * given: + * q complex value to pass to the trig function + * epsilon error tolerance / precision for trig calculation + * + * returns: + * complex value result of trig function on q with error epsilon + */ +COMPLEX * +c_vercos(COMPLEX *c, NUMBER *epsilon) +{ + COMPLEX *r; /* return COMPLEX value */ + COMPLEX *ctmp; /* complex cos(c) */ + + /* + * firewall + */ + if (c == NULL) { + math_error("%s: c is NULL", __func__); + not_reached(); + } + if (check_epsilon(epsilon) == false) { + math_error("Invalid epsilon arg for %s", __func__); + not_reached(); + } + + /* + * calculate complex trig function value + */ + ctmp = c_cos(c, epsilon); + if (ctmp == NULL) { + math_error("Failed to compute complex cos for complex vercos"); + not_reached(); + } + r = c_add(&_cone_, ctmp); + + /* + * return complex 1 + cos(x) + */ + comfree(ctmp); + return r; +} + + +/* + * c_avercos - inverse versed sine for COMPLEX values + * + * This uses the formula: + * + * avercos(x) = acos(x - 1) + * + * given: + * q complex value to pass to the trig function + * epsilon error tolerance / precision for trig calculation + * + * returns: + * complex value result of trig function on q with error epsilon + */ +COMPLEX * +c_avercos(COMPLEX *c, NUMBER *epsilon) +{ + COMPLEX *r; /* inverse trig value result */ + COMPLEX *x; /* argument to inverse trig function */ + + /* + * firewall + */ + if (c == NULL) { + math_error("%s: c is NULL", __func__); + not_reached(); + } + if (check_epsilon(epsilon) == false) { + math_error("Invalid epsilon arg for %s", __func__); + not_reached(); + } + + /* + * calculate complex inverse trig function value + */ + x = c_sub(c, &_cone_); + r = c_acos(x, epsilon); + comfree(x); + + /* + * return complex acos(1 - x) + */ + return r; +} + + +/* + * c_covercos - coversed sine for COMPLEX values + * + * This uses the formula: + * + * covercos(x) = 1 + sin(x) + * + * given: + * q complex value to pass to the trig function + * epsilon error tolerance / precision for trig calculation + * + * returns: + * complex value result of trig function on q with error epsilon + */ +COMPLEX * +c_covercos(COMPLEX *c, NUMBER *epsilon) +{ + COMPLEX *r; /* return COMPLEX value */ + COMPLEX *ctmp; /* complex sin(c) */ + + /* + * firewall + */ + if (c == NULL) { + math_error("%s: c is NULL", __func__); + not_reached(); + } + if (check_epsilon(epsilon) == false) { + math_error("Invalid epsilon arg for %s", __func__); + not_reached(); + } + + /* + * calculate complex trig function value + */ + ctmp = c_sin(c, epsilon); + if (ctmp == NULL) { + math_error("Failed to compute complex sin for complex covercos"); + not_reached(); + } + r = c_add(&_cone_, ctmp); + + /* + * return complex 1 + sin(x) + */ + comfree(ctmp); + return r; +} + + +/* + * c_acovercos - inverse versed sine for COMPLEX values + * + * This uses the formula: + * + * acovercos(x) = asin(x - 1) + * + * given: + * q complex value to pass to the trig function + * epsilon error tolerance / precision for trig calculation + * + * returns: + * complex value result of trig function on q with error epsilon + */ +COMPLEX * +c_acovercos(COMPLEX *c, NUMBER *epsilon) +{ + COMPLEX *r; /* inverse trig value result */ + COMPLEX *x; /* argument to inverse trig function */ + + /* + * firewall + */ + if (c == NULL) { + math_error("%s: c is NULL", __func__); + not_reached(); + } + if (check_epsilon(epsilon) == false) { + math_error("Invalid epsilon arg for %s", __func__); + not_reached(); + } + + /* + * calculate complex inverse trig function value + */ + x = c_sub(c, &_cone_); + r = c_asin(x, epsilon); + comfree(x); + + /* + * return complex asin(x - 1) + */ + return r; +} diff --git a/func.c b/func.c index faa4513..ac8ba8f 100644 --- a/func.c +++ b/func.c @@ -10841,6 +10841,286 @@ f_acoversin(int count, VALUE **vals) } +/* + * f_vercos - versed cosine + */ +S_FUNC VALUE +f_vercos(int count, VALUE **vals) +{ + VALUE result; + COMPLEX *c; + NUMBER *eps; + + /* 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 (verify_eps(vals[1]) == false) { + return error_value(E_VERCOS1); + } + eps = vals[1]->v_num; + } + + /* + * compute trig function to a given error tolerance + */ + switch (vals[0]->v_type) { + case V_NUM: + result.v_num = qvercos(vals[0]->v_num, eps); + result.v_type = V_NUM; + break; + case V_COM: + c = c_vercos(vals[0]->v_com, eps); + if (c == NULL) { + return error_value(E_VERCOS3); + } + result.v_com = c; + result.v_type = V_COM; + + /* + * case: complex trig function returned real, convert result to NUMBER + */ + if (cisreal(c)) { + result.v_num = c_to_q(c, true); + result.v_type = V_NUM; + } + break; + default: + return error_value(E_VERCOS2); + } + return result; +} + + +/* + * f_avercos - inverse versed cosine + */ +S_FUNC VALUE +f_avercos(int count, VALUE **vals) +{ + VALUE arg1; /* 1st arg if it is a COMPLEX value */ + VALUE result; /* value to return */ + COMPLEX *c; /* COMPLEX trig result */ + NUMBER *eps; /* epsilon error tolerance */ + + /* 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 (verify_eps(vals[1]) == false) { + return error_value(E_AVERCOS1); + } + eps = vals[1]->v_num; + } + + /* + * compute inverse trig function to a given error tolerance + */ + arg1 = *vals[0]; + if (arg1.v_type == V_NUM) { + + /* try to compute result using real triv function */ + result.v_num = qavercos_or_NULL(arg1.v_num, eps); + + /* + * case: trig function returned a NUMBER + */ + if (result.v_num != NULL) { + result.v_type = V_NUM; + + /* + * case: trig function returned NULL - need to try COMPLEX trig function + */ + } else { + /* convert NUMBER argument from NUMBER to COMPLEX */ + arg1.v_com = qqtoc(arg1.v_num, &_qzero_); + arg1.v_type = V_COM; + } + } + if (arg1.v_type == V_COM) { + + /* + * case: argument was COMPLEX or + * trig function returned NULL and argument was converted to COMPLEX + */ + c = c_avercos(arg1.v_com, eps); + if (c == NULL) { + return error_value(E_AVERCOS3); + } + result.v_com = c; + result.v_type = V_COM; + + /* + * case: complex trig function returned real, convert result to NUMBER + */ + if (cisreal(c)) { + result.v_num = c_to_q(c, true); + result.v_type = V_NUM; + } + } + if (arg1.v_type != V_NUM && arg1.v_type != V_COM) { + + /* + * case: argument type is not valid for this function + */ + return error_value(E_AVERCOS2); + } + return result; +} + + +/* + * f_covercos - coversed cosine + */ +S_FUNC VALUE +f_covercos(int count, VALUE **vals) +{ + VALUE result; + COMPLEX *c; + NUMBER *eps; + + /* 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 (verify_eps(vals[1]) == false) { + return error_value(E_COVERCOS1); + } + eps = vals[1]->v_num; + } + + /* + * compute trig function to a given error tolerance + */ + switch (vals[0]->v_type) { + case V_NUM: + result.v_num = qcovercos(vals[0]->v_num, eps); + result.v_type = V_NUM; + break; + case V_COM: + c = c_covercos(vals[0]->v_com, eps); + if (c == NULL) { + return error_value(E_COVERCOS3); + } + result.v_com = c; + result.v_type = V_COM; + + /* + * case: complex trig function returned real, convert result to NUMBER + */ + if (cisreal(c)) { + result.v_num = c_to_q(c, true); + result.v_type = V_NUM; + } + break; + default: + return error_value(E_COVERCOS2); + } + return result; +} + + +/* + * f_acovercos - inverse coversed cosine + */ +S_FUNC VALUE +f_acovercos(int count, VALUE **vals) +{ + VALUE arg1; /* 1st arg if it is a COMPLEX value */ + VALUE result; /* value to return */ + COMPLEX *c; /* COMPLEX trig result */ + NUMBER *eps; /* epsilon error tolerance */ + + /* 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 (verify_eps(vals[1]) == false) { + return error_value(E_ACOVERCOS1); + } + eps = vals[1]->v_num; + } + + /* + * compute inverse trig function to a given error tolerance + */ + arg1 = *vals[0]; + if (arg1.v_type == V_NUM) { + + /* try to compute result using real triv function */ + result.v_num = qacovercos_or_NULL(arg1.v_num, eps); + + /* + * case: trig function returned a NUMBER + */ + if (result.v_num != NULL) { + result.v_type = V_NUM; + + /* + * case: trig function returned NULL - need to try COMPLEX trig function + */ + } else { + /* convert NUMBER argument from NUMBER to COMPLEX */ + arg1.v_com = qqtoc(arg1.v_num, &_qzero_); + arg1.v_type = V_COM; + } + } + if (arg1.v_type == V_COM) { + + /* + * case: argument was COMPLEX or + * trig function returned NULL and argument was converted to COMPLEX + */ + c = c_acovercos(arg1.v_com, eps); + if (c == NULL) { + return error_value(E_ACOVERCOS3); + } + result.v_com = c; + result.v_type = V_COM; + + /* + * case: complex trig function returned real, convert result to NUMBER + */ + if (cisreal(c)) { + result.v_num = c_to_q(c, true); + result.v_type = V_NUM; + } + } + if (arg1.v_type != V_NUM && arg1.v_type != V_COM) { + + /* + * case: argument type is not valid for this function + */ + return error_value(E_ACOVERCOS2); + } + return result; +} + + #endif /* !FUNCLIST */ @@ -10893,6 +11173,8 @@ STATIC CONST struct builtin builtins[] = { "inverse cotangent of a within accuracy b"}, {"acoth", 1, 2, 0, OP_NOP, {.null = NULL}, {.valfunc_cnt = f_acoth}, "inverse hyperbolic cotangent of a within accuracy b"}, + {"acovercos", 1, 2, 0, OP_NOP, {.null = NULL}, {.valfunc_cnt = f_acovercos}, + "inverse coversed cosine of a within accuracy b"}, {"acoversin", 1, 2, 0, OP_NOP, {.null = NULL}, {.valfunc_cnt = f_acoversin}, "inverse coversed sine of a within accuracy b"}, {"acsc", 1, 2, 0, OP_NOP, {.null = NULL}, {.valfunc_cnt = f_acsc}, @@ -10925,6 +11207,8 @@ STATIC CONST struct builtin builtins[] = { "angle to point (b,a) within accuracy c"}, {"atanh", 1, 2, 0, OP_NOP, {.null = NULL}, {.valfunc_cnt = f_atanh}, "inverse hyperbolic tangent of a within accuracy b"}, + {"avercos", 1, 2, 0, OP_NOP, {.null = NULL}, {.valfunc_cnt = f_avercos}, + "inverse versed cosine of a within accuracy b"}, {"aversin", 1, 2, 0, OP_NOP, {.null = NULL}, {.valfunc_cnt = f_aversin}, "inverse versed sine of a within accuracy b"}, {"avg", 0, IN, 0, OP_NOP, {.null = NULL}, {.valfunc_cnt = f_avg}, @@ -10988,6 +11272,8 @@ STATIC CONST struct builtin builtins[] = { "hyperbolic cotangent of a within accuracy b"}, {"count", 2, 2, 0, OP_NOP, {.null = NULL}, {.valfunc_2 = f_count}, "count listr/matrix elements satisfying some condition"}, + {"covercos", 1, 2, 0, OP_NOP, {.null = NULL}, {.valfunc_cnt = f_covercos}, + "coversed cosine of value a within accuracy b"}, {"coversin", 1, 2, 0, OP_NOP, {.null = NULL}, {.valfunc_cnt = f_coversin}, "coversed sine of value a within accuracy b"}, {"cp", 2, 2, 0, OP_NOP, {.null = NULL}, {.valfunc_2 = f_cp}, @@ -11547,6 +11833,8 @@ STATIC CONST struct builtin builtins[] = { "unget char read from file"}, {"usertime", 0, 0, 0, OP_NOP, {.numfunc_0 = f_usertime}, {.null = NULL}, "user mode CPU time in seconds"}, + {"vercos", 1, 2, 0, OP_NOP, {.null = NULL}, {.valfunc_cnt = f_vercos}, + "versed cosine of value a within accuracy b"}, {"versin", 1, 2, 0, OP_NOP, {.null = NULL}, {.valfunc_cnt = f_versin}, "versed sine of value a within accuracy b"}, {"version", 0, 0, 0, OP_NOP, {.null = NULL}, {.valfunc_0 = f_version}, diff --git a/help/acos b/help/acos index 376de6b..0694ff2 100644 --- a/help/acos +++ b/help/acos @@ -36,8 +36,8 @@ LINK LIBRARY SEE ALSO sin, cos, tan, cot, sec, csc asin, atan, acot, asec, acsc - versin, coversin - aversin. acoversin + versin, coversin, vercos, avercos + aversin, acoversin, covercos, acovercos epsilon ## Copyright (C) 1999,2023 Landon Curt Noll diff --git a/help/acot b/help/acot index 17aa53a..a72e991 100644 --- a/help/acot +++ b/help/acot @@ -34,8 +34,8 @@ LINK LIBRARY SEE ALSO sin, cos, tan, cot, sec, csc asin, acos, atan, asec, acsc - versin, coversin - aversin. acoversin + versin, coversin, vercos, avercos + aversin, acoversin, covercos, acovercos epsilon ## Copyright (C) 1999,2021,2023 Landon Curt Noll diff --git a/help/acovercos b/help/acovercos new file mode 100644 index 0000000..1c1fbdb --- /dev/null +++ b/help/acovercos @@ -0,0 +1,62 @@ +NAME + acovercos - inverse coversed trigonometric cosine + +SYNOPSIS + acovercos(x [,eps]) + +TYPES + x number (real or complex) + eps 0 < real < 1, defaults to epsilon() + + return number + +DESCRIPTION + Calculate the inverse coversed trigonometric cosine of x to a multiple of eps with error less in + absolute value than .75 * eps. + + This function is sometimes called acvc, or arccovercos, is equivalent to: + + acovercos(x) = asin(x - 1) + +EXAMPLE + ; print acovercos(.5, 1e-5), acovercos(.5, 1e-10), acovercos(.5, 1e-15), acovercos(.5, 1e-20) + 0.5236 0.5235987756 0.523598775598299 0.52359877559829887308 + + ; print acovercos(1), acovercos(-5), acovercos(2 + 3i) + 0 -1.57079632679489661923+2.47788873028847500485i 0.30760364953071124992+1.86416154415788242834i + +LIMITS + 0 < eps < 1 + +LINK LIBRARY + NUMBER *qacovercos(NUMBER *x, NUMBER *eps) + COMPLEX *c_acovercos(COMPLEX *x, NUMBER *eps) + +SEE ALSO + sin, cos, tan, cot, sec, csc + asin, acos, atan, acot, asec, acsc + versin, coversin, vercos, avercos + aversin, acoversin, covercos, acovercos + epsilon + +## Copyright (C) 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 +## as published by the Free Software Foundation. +## +## Calc is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +## or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +## Public License for more details. +## +## A copy of version 2.1 of the GNU Lesser General Public License is +## distributed with calc under the filename COPYING-LGPL. You should have +## received a copy with calc; if not, write to Free Software Foundation, Inc. +## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +## +## Under source code control: 2023/09/05 23:30:08 +## File existed as early as: 2023 +## +## chongo /\oo/\ http://www.isthe.com/chongo/ +## Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/ diff --git a/help/acoversin b/help/acoversin index 1728af6..0f13fd5 100644 --- a/help/acoversin +++ b/help/acoversin @@ -11,11 +11,10 @@ TYPES return number DESCRIPTION - Calculate the inverse coversed sine of x to a multiple of eps with error less in + Calculate the inverse coversed trigonometric sine of x to a multiple of eps with error less in absolute value than .75 * eps. - The coversed sine function is sometimes called covers, or acosiv, or acvs, - may be defined as: + This function is sometimes called acovers, or acvs, or arccoversin, is equivalent to: acoversin(x) = asin(1 - x) @@ -36,8 +35,8 @@ LINK LIBRARY SEE ALSO sin, cos, tan, cot, sec, csc asin, acos, atan, acot, asec, acsc - versin, coversin - aversin + versin, coversin, vercos, avercos + aversin, acoversin, covercos, acovercos epsilon ## Copyright (C) 2023 Landon Curt Noll diff --git a/help/acsc b/help/acsc index 5537b46..874bfdb 100644 --- a/help/acsc +++ b/help/acsc @@ -34,8 +34,8 @@ LINK LIBRARY SEE ALSO sin, cos, tan, cot, sec, csc asin, acos, atan, acot, asec - versin, coversin - aversin. acoversin + versin, coversin, vercos, avercos + aversin, acoversin, covercos, acovercos epsilon ## Copyright (C) 1999,2021,2023 Landon Curt Noll diff --git a/help/asec b/help/asec index 5e9915a..d196094 100644 --- a/help/asec +++ b/help/asec @@ -34,8 +34,8 @@ LINK LIBRARY SEE ALSO sin, cos, tan, cot, sec, csc asin, acos, atan, acot, acsc - versin, coversin - aversin. acoversin + versin, coversin, vercos, avercos + aversin, acoversin, covercos, acovercos epsilon ## Copyright (C) 1999,2021,2023 Landon Curt Noll diff --git a/help/asin b/help/asin index 24b64fe..7238d75 100644 --- a/help/asin +++ b/help/asin @@ -36,8 +36,8 @@ LINK LIBRARY SEE ALSO sin, cos, tan, cot, sec, csc acos, atan, acot, asec, acsc - versin, coversin - aversin. acoversin + versin, coversin, vercos, avercos + aversin, acoversin, covercos, acovercos epsilon ## Copyright (C) 1999,2021,2023 Landon Curt Noll diff --git a/help/atan b/help/atan index e83f0a1..362227c 100644 --- a/help/atan +++ b/help/atan @@ -34,8 +34,8 @@ LINK LIBRARY SEE ALSO sin, cos, tan, cot, sec, csc asin, acos, acot, asec, acsc - versin, coversin - aversin. acoversin + versin, coversin, vercos, avercos + aversin, acoversin, covercos, acovercos epsilon ## Copyright (C) 1999,2023 Landon Curt Noll diff --git a/help/avercos b/help/avercos new file mode 100644 index 0000000..31e4dab --- /dev/null +++ b/help/avercos @@ -0,0 +1,63 @@ +NAME + avercos - inverse versed trigonometric cosine + +SYNOPSIS + avercos(x [,eps]) + +TYPES + x number (real or complex) + eps 0 < real < 1, defaults to epsilon() + + return real + +DESCRIPTION + Returns the inverse versed trigonometric cosine of x to a multiple of eps with error less in + absolute value than .75 * eps. + + This function is sometimes called averc, or arcvercos, is equivalent to: + + avercos(x) = acos(x - 1) + +EXAMPLE + ; print avercos(.5, 1e-5), avercos(.5, 1e-10), avercos(.5, 1e-15), avercos(.5, 1e-20) + 2.0944 2.0943951024 2.094395102393195 2.09439510239319549231 + + ; print avercos(2), avercos(-5), avercos(2 + 3i) + 0 3.14159265358979323846-2.47788873028847500481i 1.26319267726418536931-1.86416154415788242834i + +LIMITS + 0 < eps < 1 + +LINK LIBRARY + NUMBER *qavercos_or_NULL(NUMBER *q, NUMBER *epsilon); + NUMBER *qavercos(NUMBER *q, NUMBER *epsilon); + COMPLEX *c_avercos(COMPLEX *c, NUMBER *epsilon); + +SEE ALSO + sin, cos, tan, cot, sec, csc + asin, acos, atan, acot, asec, acsc + versin, coversin, vercos, avercos + aversin, acoversin, covercos, acovercos + epsilon + +## Copyright (C) 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 +## as published by the Free Software Foundation. +## +## Calc is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +## or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +## Public License for more details. +## +## A copy of version 2.1 of the GNU Lesser General Public License is +## distributed with calc under the filename COPYING-LGPL. You should have +## received a copy with calc; if not, write to Free Software Foundation, Inc. +## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +## +## Under source code control: 2023/09/05 23:40:24 +## File existed as early as: 2023 +## +## chongo /\oo/\ http://www.isthe.com/chongo/ +## Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/ diff --git a/help/aversin b/help/aversin index 789d9b4..85c4b27 100644 --- a/help/aversin +++ b/help/aversin @@ -11,11 +11,10 @@ TYPES return real DESCRIPTION - Returns the inverse versed sine of x to a multiple of eps with error less in + Returns the inverse versed trigonometric sine of x to a multiple of eps with error less in absolute value than .75 * eps. - The inverse versed sine function is sometimes called avers, sometimes called aver, - may be defined as: + This function is sometimes called avers, or arcversin, is equivalent to: aversin(x) = acos(1 - x) diff --git a/help/cos b/help/cos index 09b24a4..de40711 100644 --- a/help/cos +++ b/help/cos @@ -35,8 +35,8 @@ LINK LIBRARY SEE ALSO sin, tan, cot, sec, csc asin, acos, atan, acot, asec, acsc - versin, coversin - aversin. acoversin + versin, coversin, vercos, avercos + aversin, acoversin, covercos, acovercos epsilon ## Copyright (C) 1999,2021,2023 Landon Curt Noll diff --git a/help/cot b/help/cot index c323652..6f92ea8 100644 --- a/help/cot +++ b/help/cot @@ -28,8 +28,8 @@ LINK LIBRARY SEE ALSO sin, cos, tan, sec, csc asin, acos, atan, acot, asec, acsc - versin, coversin - aversin. acoversin + versin, coversin, vercos, avercos + aversin, acoversin, covercos, acovercos epsilon ## Copyright (C) 1999,2021,2023 Landon Curt Noll diff --git a/help/covercos b/help/covercos new file mode 100644 index 0000000..e08806d --- /dev/null +++ b/help/covercos @@ -0,0 +1,69 @@ +NAME + covercos - coversed trigonometric cosine + +SYNOPSIS + covercos(x [,eps]) + +TYPES + x number (real or complex) + eps 0 < real < 1, defaults to epsilon() + + return number + +DESCRIPTION + Calculate the coversed trigonometric cosine of x to a multiple of eps with error less in + absolute value than .75 * eps. + + This function is sometimes called cvc, is equivalent to: + + covercos(x) = 1 + sin(x) + +EXAMPLE + ; print covercos(0.2), covercos(3/7), covercos(-31) + 1.19866933079506121546 1.41557185499305200807 1.40403764532306500605 + + ; print covercos(1, 1e-5), covercos(1, 1e-10), covercos(1, 1e-15), covercos(1, 1e-20) + 1.84147 1.8414709848 1.841470984807896 1.84147098480789650665 + + ; print covercos(2 + 3i, 1e-5), covercos(2 + 3i, 1e-10) + 10.1545-4.16891i 10.1544991469-4.16890696i + + ; pi = pi(1e-20) + ; print covercos(pi/6, 1e-10), covercos(pi/2, 1e-10), covercos(pi, 1e-10), covercos(3*pi/2, 1e-10) + 1.5 2 1 0 + +LIMITS + 0 < eps < 1 + +LINK LIBRARY + NUMBER *qcovercos(NUMBER *x, NUMBER *eps) + COMPLEX *c_covercos(COMPLEX *x, NUMBER *eps) + +SEE ALSO + sin, cos, tan, cot, sec, csc + asin, acos, atan, acot, asec, acsc + versin, coversin, vercos, avercos + aversin, acoversin, covercos, acovercos + epsilon + +## Copyright (C) 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 +## as published by the Free Software Foundation. +## +## Calc is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +## or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +## Public License for more details. +## +## A copy of version 2.1 of the GNU Lesser General Public License is +## distributed with calc under the filename COPYING-LGPL. You should have +## received a copy with calc; if not, write to Free Software Foundation, Inc. +## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +## +## Under source code control: 2023/09/05 23:31:08 +## File existed as early as: 2023 +## +## chongo /\oo/\ http://www.isthe.com/chongo/ +## Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/ diff --git a/help/coversin b/help/coversin index 5d10830..a0d5b51 100644 --- a/help/coversin +++ b/help/coversin @@ -11,11 +11,10 @@ TYPES return number DESCRIPTION - Calculate the coversed sine of x to a multiple of eps with error less in + Calculate the coversed trigonometric sine of x to a multiple of eps with error less in absolute value than .75 * eps. - The coversed sine function is sometimes called covers, or cosiv, or cvs, - may be defined as: + This function is sometimes called covers, or cvs, is equivalent to: coversin(x) = 1 - sin(x) @@ -43,8 +42,8 @@ LINK LIBRARY SEE ALSO sin, cos, tan, cot, sec, csc asin, acos, atan, acot, asec, acsc - versin - aversin. acoversin + versin, coversin, vercos, avercos + aversin, acoversin, covercos, acovercos epsilon ## Copyright (C) 2023 Landon Curt Noll diff --git a/help/csc b/help/csc index 3e15fb4..bff3620 100644 --- a/help/csc +++ b/help/csc @@ -27,8 +27,8 @@ LINK LIBRARY SEE ALSO sin, cos, tan, cot, sec asin, acos, atan, acot, asec, acsc - versin, coversin - aversin. acoversin + versin, coversin, vercos, avercos + aversin, acoversin, covercos, acovercos epsilon ## Copyright (C) 1999,2023 Landon Curt Noll diff --git a/help/sec b/help/sec index 07ce615..c8b839d 100644 --- a/help/sec +++ b/help/sec @@ -28,8 +28,8 @@ LINK LIBRARY SEE ALSO sin, cos, tan, cot, csc asin, acos, atan, acot, asec, acsc - versin, coversin - aversin. acoversin + versin, coversin, vercos, avercos + aversin, acoversin, covercos, acovercos epsilon ## Copyright (C) 1999,2023 Landon Curt Noll diff --git a/help/sin b/help/sin index 1a71755..abfaebe 100644 --- a/help/sin +++ b/help/sin @@ -35,8 +35,8 @@ LINK LIBRARY SEE ALSO cos, tan, cot, sec, csc asin, acos, atan, acot, asec, acsc - versin, coversin - aversin. acoversin + versin, coversin, vercos, avercos + aversin, acoversin, covercos, acovercos epsilon ## Copyright (C) 1999,2021,2023 Landon Curt Noll diff --git a/help/tan b/help/tan index 5310a1f..efbd1b2 100644 --- a/help/tan +++ b/help/tan @@ -29,8 +29,8 @@ LINK LIBRARY SEE ALSO sin, cos, cot, sec, csc asin, acos, atan, acot, asec, acsc - versin, coversin - aversin. acoversin + versin, coversin, vercos, avercos + aversin, acoversin, covercos, acovercos epsilon ## Copyright (C) 1999,2023 Landon Curt Noll diff --git a/help/vercos b/help/vercos new file mode 100644 index 0000000..16077df --- /dev/null +++ b/help/vercos @@ -0,0 +1,69 @@ +NAME + vercos - versed trigonometric cosine + +SYNOPSIS + vercos(x [,eps]) + +TYPES + x number (real or complex) + eps 0 < real < 1, defaults to epsilon() + + return number + +DESCRIPTION + Calculate the versed trigonometric cosine of x to a multiple of eps with error less in + absolute value than .75 * eps. + + This function is sometimes called verc, is equivalent to: + + vercos(x) = 1 + cos(x) + +EXAMPLE + ; print vercos(0.2), vercos(3/7), vercos(-31) + 1.98006657784124163112 1.90956035167416667403 1.91474235780453127896 + + ; print vercos(1, 1e-5), vercos(1, 1e-10), vercos(1, 1e-15), vercos(1, 1e-20) + 1.5403 1.5403023059 1.54030230586814 1.5403023058681397174 + + ; print vercos(2 + 3i, 1e-5), vercos(2 + 3i, 1e-10) + -3.18963-9.10923i -3.189625691-9.1092278938i + + ; pi = pi(1e-20) + ; print vercos(pi/3, 1e-10), vercos(pi/2, 1e-10), vercos(pi, 1e-10), vercos(3*pi/2, 1e-10) + 1.5 1 0 1 + +LIMITS + 0 < eps < 1 + +LINK LIBRARY + NUMBER *qvercos(NUMBER *x, NUMBER *eps) + COMPLEX *c_vercos(COMPLEX *x, NUMBER *eps) + +SEE ALSO + sin, cos, tan, cot, sec, csc + asin, acos, atan, acot, asec, acsc + versin, coversin, vercos, avercos + aversin, acoversin, covercos, acovercos + epsilon + +## Copyright (C) 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 +## as published by the Free Software Foundation. +## +## Calc is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +## or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +## Public License for more details. +## +## A copy of version 2.1 of the GNU Lesser General Public License is +## distributed with calc under the filename COPYING-LGPL. You should have +## received a copy with calc; if not, write to Free Software Foundation, Inc. +## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +## +## Under source code control: 2023/09/05 23:25:28 +## File existed as early as: 2023 +## +## chongo /\oo/\ http://www.isthe.com/chongo/ +## Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/ diff --git a/help/versin b/help/versin index 388cdda..2195d07 100644 --- a/help/versin +++ b/help/versin @@ -11,11 +11,10 @@ TYPES return number DESCRIPTION - Calculate the versed sine of x to a multiple of eps with error less in + Calculate the versed trigonometric sine of x to a multiple of eps with error less in absolute value than .75 * eps. - The versed sine function is sometimes called vers, sometimes called ver, - may be defined as: + This function is sometimes called vers, is equivalent to: versin(x) = 1 - cos(x) @@ -43,8 +42,8 @@ LINK LIBRARY SEE ALSO sin, cos, tan, cot, sec, csc asin, acos, atan, acot, asec, acsc - coversin - aversin. acoversin + versin, coversin, vercos, avercos + aversin, acoversin, covercos, acovercos epsilon ## Copyright (C) 2023 Landon Curt Noll diff --git a/qmath.h b/qmath.h index bf946ab..9daa909 100644 --- a/qmath.h +++ b/qmath.h @@ -232,6 +232,12 @@ E_FUNC NUMBER *qaversin(NUMBER *q, NUMBER *epsilon); E_FUNC NUMBER *qcoversin(NUMBER *q, NUMBER *epsilon); E_FUNC NUMBER *qacoversin_or_NULL(NUMBER *q, NUMBER *epsilon); E_FUNC NUMBER *qacoversin(NUMBER *q, NUMBER *epsilon); +E_FUNC NUMBER *qvercos(NUMBER *q, NUMBER *epsilon); +E_FUNC NUMBER *qavercos_or_NULL(NUMBER *q, NUMBER *epsilon); +E_FUNC NUMBER *qavercos(NUMBER *q, NUMBER *epsilon); +E_FUNC NUMBER *qcovercos(NUMBER *q, NUMBER *epsilon); +E_FUNC NUMBER *qacovercos_or_NULL(NUMBER *q, NUMBER *epsilon); +E_FUNC NUMBER *qacovercos(NUMBER *q, NUMBER *epsilon); /* diff --git a/qtrans.c b/qtrans.c index 8db8a02..e2c7e4f 100644 --- a/qtrans.c +++ b/qtrans.c @@ -2293,3 +2293,320 @@ qacoversin(NUMBER *q, NUMBER *epsilon) */ return res; } + + +/* + * qvercos - versed sine for NUMBER values + * + * This uses the formula: + * + * vercos(x) = 1 + cos(x) + * + * given: + * q real value to pass to the trig function + * epsilon error tolerance / precision for trig calculation + * + * returns: + * real value result of trig function on q with error epsilon + */ +NUMBER * +qvercos(NUMBER *q, NUMBER *epsilon) +{ + NUMBER *sin, *cos, *res; + NUMBER *vercos; + long n; + + /* + * firewall + */ + if (q == NULL) { + math_error("q is NULL for %s", __func__); + not_reached(); + } + if (check_epsilon(epsilon) == false) { + math_error("Invalid epsilon arg for %s", __func__); + not_reached(); + } + + /* + * calculate trig function value + */ + n = -qilog2(epsilon); + qsincos(q, n + 2, &sin, &cos); + qfree(sin); + vercos = qqadd(&_qone_, cos); + qfree(cos); + + /* + * round value to nearest epsilon + */ + res = qmappr(vercos, epsilon, 24); + qfree(vercos); + + /* + * return 1 + cos(x) + */ + return res; +} + + +/* + * qavercos_or_NULL - inverse versed sine for NUMBER values + * + * This uses the formula: + * + * avercos(x) = acos(x - 1) + * + * given: + * q real value to pass to the trig function + * epsilon error tolerance / precision for trig calculation + * + * returns: + * != NULL ==> real value result of trig function on q with error epsilon, + * NULL ==> trig function value cannot be expressed as a NUMBER + * + * NOTE: If this function returns NULL, consider calling the equivalent + * COMPLEX function from comfunc.c. See the help file for the + * related builtin for details. + */ +NUMBER * +qavercos_or_NULL(NUMBER *q, NUMBER *epsilon) +{ + NUMBER *res; /* inverse trig value result */ + NUMBER *x; /* argument to inverse trig function */ + + /* + * firewall + */ + if (q == NULL) { + math_error("q is NULL for %s", __func__); + not_reached(); + } + if (check_epsilon(epsilon) == false) { + math_error("Invalid epsilon arg for %s", __func__); + not_reached(); + } + + /* + * calculate inverse trig function value + */ + x = qsub(q, &_qone_); + res = qacos(x, epsilon); + qfree(x); + if (res == NULL) { + return NULL; + } + + /* + * return acos(x - 1) + */ + return res; +} + + +/* + * qavercos - inverse versed sine for NUMBER values + * + * This uses the formula: + * + * avercos(x) = acos(x - 1) + * + * given: + * q real value to pass to the trig function + * epsilon error tolerance / precision for trig calculation + * + * returns: + * real value result of trig function on q with error epsilon + */ +NUMBER * +qavercos(NUMBER *q, NUMBER *epsilon) +{ + NUMBER *res; /* inverse trig value result */ + + /* + * firewall + */ + if (q == NULL) { + math_error("q is NULL for %s", __func__); + not_reached(); + } + if (check_epsilon(epsilon) == false) { + math_error("Invalid epsilon arg for %s", __func__); + not_reached(); + } + + /* + * calculate inverse trig function value + */ + res = qavercos_or_NULL(q, epsilon); + if (res == NULL) { + math_error("cannot compute inverse cos for avercos"); + not_reached(); + } + + /* + * return acos(x - 1) + */ + return res; +} + + +/* + * qcovercos - coversed sine for NUMBER values + * + * This uses the formula: + * + * covercos((x) = 1 + sin(x) + * + * given: + * q real value to pass to the trig function + * epsilon error tolerance / precision for trig calculation + * + * returns: + * real value result of trig function on q with error epsilon + */ +NUMBER * +qcovercos(NUMBER *q, NUMBER *epsilon) +{ + NUMBER *sin, *cos, *res; + NUMBER *covercos; + long n; + + /* + * firewall + */ + if (q == NULL) { + math_error("q is NULL for %s", __func__); + not_reached(); + } + if (check_epsilon(epsilon) == false) { + math_error("Invalid epsilon arg for %s", __func__); + not_reached(); + } + + /* + * calculate trig function value + */ + n = -qilog2(epsilon); + if (qiszero(q) || n < 0) + return qlink(&_qzero_); + qsincos(q, n + 2, &sin, &cos); + qfree(cos); + covercos = qqadd(&_qone_, sin); + qfree(sin); + + /* + * round value to nearest epsilon + */ + res = qmappr(covercos, epsilon, 24); + qfree(covercos); + + /* + * return 1 + sin(x) + */ + return res; +} + + +/* + * qacovercos_or_NULL - inverse coversed sine for NUMBER values + * + * This uses the formula: + * + * acovercos(x) = asin(x - 1) + * + * given: + * q real value to pass to the trig function + * epsilon error tolerance / precision for trig calculation + * + * returns: + * real value result of trig function on q with error epsilon + * + * returns: + * != NULL ==> real value result of trig function on q with error epsilon, + * NULL ==> trig function value cannot be expressed as a NUMBER + * + * NOTE: If this function returns NULL, consider calling the equivalent + * COMPLEX function from comfunc.c. See the help file for the + * related builtin for details. + */ +NUMBER * +qacovercos_or_NULL(NUMBER *q, NUMBER *epsilon) +{ + NUMBER *res; /* inverse trig value result */ + NUMBER *x; /* argument to inverse trig function */ + + /* + * firewall + */ + if (q == NULL) { + math_error("q is NULL for %s", __func__); + not_reached(); + } + if (check_epsilon(epsilon) == false) { + math_error("Invalid epsilon arg for %s", __func__); + not_reached(); + } + + /* + * calculate inverse trig function value + */ + x = qsub(&_qone_, q); + res = qasin(x, epsilon); + qfree(x); + if (res == NULL) { + return NULL; + } + + /* + * return asin(x - 1) + */ + return res; +} + + +/* + * qacovercos - inverse coversed sine for NUMBER values + * + * This uses the formula: + * + * acovercos(x) = asin(x - 1) + * + * given: + * q real value to pass to the trig function + * epsilon error tolerance / precision for trig calculation + * + * returns: + * real value result of trig function on q with error epsilon + */ +NUMBER * +qacovercos(NUMBER *q, NUMBER *epsilon) +{ + NUMBER *res; /* inverse trig value result */ + + /* + * firewall + */ + if (q == NULL) { + math_error("q is NULL for %s", __func__); + not_reached(); + } + if (check_epsilon(epsilon) == false) { + math_error("Invalid epsilon arg for %s", __func__); + not_reached(); + } + + /* + * calculate inverse trig function value + */ + res = qacovercos_or_NULL(q, epsilon); + if (res == NULL) { + math_error("cannot compute inverse sin for acovercos"); + not_reached(); + } + + /* + * return asin(x - 1) + */ + return res; +}