add cmappr() and missing complex tan, cot, sec, csc in liblcac

Added complex multiple approximation function to commath.c so
that users of libcalc may directly round complex number to
nearest multiple of a given real number:

    E_FUNC COMPLEX *cmappr(COMPLEX *c, NUMBER *e, long rnd, bool cfree);

For example:

    COMPLEX *c;             /* complex number to round to nearest epsilon */
    NUMBER *eps;            /* epsilon rounding precision */
    COMPLEX *res;           /* c rounded to nearest epsilon */
    long rnd = 24L;         /* a common rounding mode */
    bool ok_to_free;        /* true ==> free c, false ==> do not free c */

    ...

    res = cmappr(c, eps, ok_to_free);

The complex trigonometric functions tan, cot, sec, csc were implemented
in func.c as calls to complex sin and complex cos.  We added the
direct calls to comfunc.c so that users of libcalc may
call them directly:

    E_FUNC COMPLEX *c_tan(COMPLEX *c, NUMBER *eps);
    E_FUNC COMPLEX *c_cot(COMPLEX *c, NUMBER *eps);
    E_FUNC COMPLEX *c_sec(COMPLEX *c, NUMBER *eps);
    E_FUNC COMPLEX *c_cot(COMPLEX *c, NUMBER *eps);
This commit is contained in:
Landon Curt Noll
2023-09-10 22:54:50 -07:00
parent a722b5cca7
commit bf730f5518
11 changed files with 559 additions and 106 deletions

28
CHANGES
View File

@@ -185,6 +185,34 @@ The following are the changes from calc version 2.14.3.5 to date:
Expanded the calc regression test suite test 34dd to test various Expanded the calc regression test suite test 34dd to test various
real and complex values for sin, cos, tan, cot, sec, csc. real and complex values for sin, cos, tan, cot, sec, csc.
Added complex multiple approximation function to commath.c so
that users of libcalc may directly round complex number to
nearest multiple of a given real number:
E_FUNC COMPLEX *cmappr(COMPLEX *c, NUMBER *e, long rnd, bool cfree);
For example:
COMPLEX *c; /* complex number to round to nearest epsilon */
NUMBER *eps; /* epsilon rounding precision */
COMPLEX *res; /* c rounded to nearest epsilon */
long rnd = 24L; /* a common rounding mode */
bool ok_to_free; /* true ==> free c, false ==> do not free c */
...
res = cmappr(c, eps, ok_to_free);
The complex trigonometric functions tan, cot, sec, csc were
implemented in func.c as calls to complex sin and complex cos.
We added the following direct calls to comfunc.c so that users
of libcalc may call them directly:
E_FUNC COMPLEX *c_tan(COMPLEX *c, NUMBER *eps);
E_FUNC COMPLEX *c_cot(COMPLEX *c, NUMBER *eps);
E_FUNC COMPLEX *c_sec(COMPLEX *c, NUMBER *eps);
E_FUNC COMPLEX *c_cot(COMPLEX *c, NUMBER *eps);
The following are the changes from calc version 2.14.3.4 to 2.14.3.5: The following are the changes from calc version 2.14.3.4 to 2.14.3.5:

View File

@@ -4112,10 +4112,10 @@ define test_error()
n = 8191; n = 8191;
print '3727: n = 8191'; print '3727: n = 8191';
/* test 3728 removed due to non-portable strerror() output */ /* test 3728 removed due to non-portable strerror() output */
vrfy(tan(2e9i) == error(10435), '3729: tan(2e9i) == error(10435)'); vrfy(tan(2e9i) == error(10537), '3729: tan(2e9i) == error(10537)');
vrfy(cot(2e9i) == error(10437), '3730: cot(2e9i) == error(10437)'); vrfy(cot(2e9i) == error(10539), '3730: cot(2e9i) == error(10539)');
vrfy(sec(2e9i) == error(10439), '3731: sec(2e9i) == error(10439)'); vrfy(sec(2e9i) == error(10540), '3731: sec(2e9i) == error(10540)');
vrfy(csc(2e9i) == error(10440), '3732: csc(2e9i) == error(10440)'); vrfy(csc(2e9i) == error(10542), '3732: csc(2e9i) == error(10542)');
/* errmax and errcount should be bumped up the 148 errors above */ /* errmax and errcount should be bumped up the 148 errors above */
vrfy(errcount() == ecnt, '3733: errcount() == ecnt'); vrfy(errcount() == ecnt, '3733: errcount() == ecnt');

View File

@@ -472,12 +472,12 @@ E_ISSPACE Bad argument for isspace
E_ISXDIGIT Bad argument for isxdigit E_ISXDIGIT Bad argument for isxdigit
E_STRTOUPPER Bad argument type for strtoupper E_STRTOUPPER Bad argument type for strtoupper
E_STRTOLOWER Bad argument type for strtolower E_STRTOLOWER Bad argument type for strtolower
E_TAN3 Invalid value for calculating the sin numerator for tan E_TAN3 UNUSED ERROR: Invalid value for calculating the sin numerator for tan
E_TAN4 Invalid value for calculating the cos denominator for tan E_TAN4 UNUSED ERROR: Invalid value for calculating the cos denominator for tan
E_COT3 Invalid value for calculating the sin numerator for cot E_COT3 UNUSED ERROR: Invalid value for calculating the sin numerator for cot
E_COT4 Invalid value for calculating the cos denominator for cot E_COT4 UNUSED ERROR: Invalid value for calculating the cos denominator for cot
E_SEC3 Invalid value for calculating the cos reciprocal for sec E_SEC3 UNUSED ERROR: Invalid value for calculating the cos reciprocal for sec
E_CSC3 Invalid value for calculating the sin reciprocal for csc E_CSC3 UNUSED ERROR: Invalid value for calculating the sin reciprocal for csc
E_TANH3 Invalid value for calculating the sinh numerator for tanh E_TANH3 Invalid value for calculating the sinh numerator for tanh
E_TANH4 Invalid value for calculating the cosh denominator for tanh E_TANH4 Invalid value for calculating the cosh denominator for tanh
E_COTH3 Invalid value for calculating the sinh numerator for coth E_COTH3 Invalid value for calculating the sinh numerator for coth
@@ -574,3 +574,9 @@ E_COVERCOS3 Too-large im(argument) for covercos
E_ACOVERCOS1 Bad epsilon for acovercos E_ACOVERCOS1 Bad epsilon for acovercos
E_ACOVERCOS2 Bad first argument for acovercos E_ACOVERCOS2 Bad first argument for acovercos
E_ACOVERCOS3 Too-large im(argument) for acovercos E_ACOVERCOS3 Too-large im(argument) for acovercos
E_TAN5 Invalid complex argument for tan
E_COT5 Invalid zero argument for cot
E_COT6 Invalid complex argument for cot
E_SEC5 Invalid complex argument for sec
E_CSC5 Invalid zero argument for cot
E_CSC6 Invalid complex argument for csc

View File

@@ -48,6 +48,7 @@ typedef struct {
/* /*
* Input, output, and conversion routines. * Input, output, and conversion routines.
*/ */
E_FUNC COMPLEX *cmappr(COMPLEX *c, NUMBER *e, long rnd, bool cfree);
E_FUNC COMPLEX *comalloc(void); E_FUNC COMPLEX *comalloc(void);
E_FUNC COMPLEX *qqtoc(NUMBER *q1, NUMBER *q2); E_FUNC COMPLEX *qqtoc(NUMBER *q1, NUMBER *q2);
E_FUNC void comfree(COMPLEX *c); E_FUNC void comfree(COMPLEX *c);
@@ -107,9 +108,13 @@ E_FUNC COMPLEX *c_polar(NUMBER *q1, NUMBER *q2, NUMBER *epsilon);
E_FUNC COMPLEX *c_rel(COMPLEX *c1, COMPLEX *c2); E_FUNC COMPLEX *c_rel(COMPLEX *c1, COMPLEX *c2);
E_FUNC COMPLEX *c_asin(COMPLEX *c, NUMBER *epsilon); E_FUNC COMPLEX *c_asin(COMPLEX *c, NUMBER *epsilon);
E_FUNC COMPLEX *c_acos(COMPLEX *c, NUMBER *epsilon); E_FUNC COMPLEX *c_acos(COMPLEX *c, NUMBER *epsilon);
E_FUNC COMPLEX *c_tan(COMPLEX *c, NUMBER *epsilon);
E_FUNC COMPLEX *c_atan(COMPLEX *c, NUMBER *epsilon); E_FUNC COMPLEX *c_atan(COMPLEX *c, NUMBER *epsilon);
E_FUNC COMPLEX *c_cot(COMPLEX *c, NUMBER *epsilon);
E_FUNC COMPLEX *c_acot(COMPLEX *c, NUMBER *epsilon); E_FUNC COMPLEX *c_acot(COMPLEX *c, NUMBER *epsilon);
E_FUNC COMPLEX *c_sec(COMPLEX *c, NUMBER *epsilon);
E_FUNC COMPLEX *c_asec(COMPLEX *c, NUMBER *epsilon); E_FUNC COMPLEX *c_asec(COMPLEX *c, NUMBER *epsilon);
E_FUNC COMPLEX *c_csc(COMPLEX *c, NUMBER *epsilon);
E_FUNC COMPLEX *c_acsc(COMPLEX *c, NUMBER *epsilon); E_FUNC COMPLEX *c_acsc(COMPLEX *c, NUMBER *epsilon);
E_FUNC COMPLEX *c_asinh(COMPLEX *c, NUMBER *epsilon); E_FUNC COMPLEX *c_asinh(COMPLEX *c, NUMBER *epsilon);
E_FUNC COMPLEX *c_acosh(COMPLEX *c, NUMBER *epsilon); E_FUNC COMPLEX *c_acosh(COMPLEX *c, NUMBER *epsilon);

320
comfunc.c
View File

@@ -878,6 +878,96 @@ c_acosh(COMPLEX *c, NUMBER *epsilon)
} }
/*
* c_tan - complex trigonometric tangent
*
* This uses the formula:
*
* tan(x) = sin(x) / cos(x)
*
* given:
* c argument to the trigonometric function
* epsilon precision of the trigonometric calculation
*
* returns:
* != NULL ==> allocated pointer to COMPLEX result
* NULL ==> invalid trigonometric argument
*
* NOTE: When the trigonometric result is returned as non-NULL result,
* the value may be a real value. The caller may wish to:
*
* COMPLEX *c; (* return result of this function *)
* NUMBER *q; (* COMPLEX result when c is a real number *)
*
* if (c == NULL) {
* math_error("... some error message");
* not_reached();
* }
* if (cisreal(c)) {
* q = c_to_q(c, ok_to_free);
* }
*/
COMPLEX *
c_tan(COMPLEX *c, NUMBER *epsilon)
{
COMPLEX *denom; /* trigonometric identity numerator */
COMPLEX *numer; /* trigonometric identity denominator */
COMPLEX *res; /* trigonometric result */
/*
* firewall - check args
*/
if (c == NULL) {
return NULL;
}
if (check_epsilon(epsilon) == false) {
return NULL;
}
/*
* evaluate the cos(x) denominator
*
* Return NULL if cos(x) failed or we otherwise divide by zero.
*/
denom = c_cos(c, epsilon);
if (denom == NULL || ciszero(denom)) {
return NULL;
}
/*
* evaluate the sin(x) numerator
*
* Return NULL if sin(x) failed.
*/
numer = c_sin(c, epsilon);
if (numer == NULL) {
comfree(denom);
return NULL;
}
/*
* catch the special case of numerator of 0
*/
if (ciszero(numer)) {
comfree(denom);
comfree(numer);
return clink(&_czero_);
}
/*
* compute the trigonometric function value
*/
res = c_div(numer, denom);
comfree(denom);
comfree(numer);
/*
* return the trigonometric result
*/
return res;
}
COMPLEX * COMPLEX *
c_atan(COMPLEX *c, NUMBER *epsilon) c_atan(COMPLEX *c, NUMBER *epsilon)
{ {
@@ -900,6 +990,96 @@ c_atan(COMPLEX *c, NUMBER *epsilon)
} }
/*
* c_cot - complex trigonometric cotangent
*
* This uses the formula:
*
* cot(x) = cos(x) / sin(x)
*
* given:
* c argument to the trigonometric function
* epsilon precision of the trigonometric calculation
*
* returns:
* != NULL ==> allocated pointer to COMPLEX result
* NULL ==> invalid trigonometric argument
*
* NOTE: When the trigonometric result is returned as non-NULL result,
* the value may be a real value. The caller may wish to:
*
* COMPLEX *c; (* return result of this function *)
* NUMBER *q; (* COMPLEX result when c is a real number *)
*
* if (c == NULL) {
* math_error("... some error message");
* not_reached();
* }
* if (cisreal(c)) {
* q = c_to_q(c, ok_to_free);
* }
*/
COMPLEX *
c_cot(COMPLEX *c, NUMBER *epsilon)
{
COMPLEX *denom; /* trigonometric identity numerator */
COMPLEX *numer; /* trigonometric identity denominator */
COMPLEX *res; /* trigonometric result */
/*
* firewall - check args
*/
if (c == NULL) {
return NULL;
}
if (check_epsilon(epsilon) == false) {
return NULL;
}
/*
* evaluate the sin(x) denominator
*
* Return NULL if sin(x) failed or we otherwise divide by zero.
*/
denom = c_sin(c, epsilon);
if (denom == NULL || ciszero(denom)) {
return NULL;
}
/*
* evaluate the cos(x) numerator
*
* Return NULL if cos(x) failed.
*/
numer = c_cos(c, epsilon);
if (numer == NULL) {
comfree(denom);
return NULL;
}
/*
* catch the special case of numerator of 0
*/
if (ciszero(numer)) {
comfree(denom);
comfree(numer);
return clink(&_czero_);
}
/*
* compute the trigonometric function value
*/
res = c_div(numer, denom);
comfree(denom);
comfree(numer);
/*
* return the trigonometric result
*/
return res;
}
COMPLEX * COMPLEX *
c_acot(COMPLEX *c, NUMBER *epsilon) c_acot(COMPLEX *c, NUMBER *epsilon)
{ {
@@ -921,6 +1101,75 @@ c_acot(COMPLEX *c, NUMBER *epsilon)
return tmp1; return tmp1;
} }
/*
* c_sec - complex trigonometric tangent
*
* This uses the formula:
*
* sec(x) = 1 / cos(x)
*
* given:
* c argument to the trigonometric function
* epsilon precision of the trigonometric calculation
*
* returns:
* != NULL ==> allocated pointer to COMPLEX result
* NULL ==> invalid trigonometric argument
*
* NOTE: When the trigonometric result is returned as non-NULL result,
* the value may be a real value. The caller may wish to:
*
* COMPLEX *c; (* return result of this function *)
* NUMBER *q; (* COMPLEX result when c is a real number *)
*
* if (c == NULL) {
* math_error("... some error message");
* not_reached();
* }
* if (cisreal(c)) {
* q = c_to_q(c, ok_to_free);
* }
*/
COMPLEX *
c_sec(COMPLEX *c, NUMBER *epsilon)
{
COMPLEX *denom; /* trigonometric identity numerator */
COMPLEX *res; /* trigonometric result */
/*
* firewall - check args
*/
if (c == NULL) {
return NULL;
}
if (check_epsilon(epsilon) == false) {
return NULL;
}
/*
* evaluate the cos(x) denominator
*
* Return NULL if cos(x) failed or we otherwise divide by zero.
*/
denom = c_cos(c, epsilon);
if (denom == NULL || ciszero(denom)) {
return NULL;
}
/*
* compute the trigonometric function value
*/
res = c_div(&_cone_, denom);
comfree(denom);
/*
* return the trigonometric result
*/
return res;
}
COMPLEX * COMPLEX *
c_asec(COMPLEX *c, NUMBER *epsilon) c_asec(COMPLEX *c, NUMBER *epsilon)
{ {
@@ -932,6 +1181,75 @@ c_asec(COMPLEX *c, NUMBER *epsilon)
return tmp2; return tmp2;
} }
/*
* c_sec - complex trigonometric cosecant
*
* This uses the formula:
*
* csc(x) = 1 / sin(x)
*
* given:
* c argument to the trigonometric function
* epsilon precision of the trigonometric calculation
*
* returns:
* != NULL ==> allocated pointer to COMPLEX result
* NULL ==> invalid trigonometric argument
*
* NOTE: When the trigonometric result is returned as non-NULL result,
* the value may be a real value. The caller may wish to:
*
* COMPLEX *c; (* return result of this function *)
* NUMBER *q; (* COMPLEX result when c is a real number *)
*
* if (c == NULL) {
* math_error("... some error message");
* not_reached();
* }
* if (cisreal(c)) {
* q = c_to_q(c, ok_to_free);
* }
*/
COMPLEX *
c_csc(COMPLEX *c, NUMBER *epsilon)
{
COMPLEX *denom; /* trigonometric identity numerator */
COMPLEX *res; /* trigonometric result */
/*
* firewall - check args
*/
if (c == NULL) {
return NULL;
}
if (check_epsilon(epsilon) == false) {
return NULL;
}
/*
* evaluate the sin(x) denominator
*
* Return NULL if sin(x) failed or we otherwise divide by zero.
*/
denom = c_sin(c, epsilon);
if (denom == NULL || ciszero(denom)) {
return NULL;
}
/*
* compute the trigonometric function value
*/
res = c_div(&_cone_, denom);
comfree(denom);
/*
* return the trigonometric result
*/
return res;
}
COMPLEX * COMPLEX *
c_acsc(COMPLEX *c, NUMBER *epsilon) c_acsc(COMPLEX *c, NUMBER *epsilon)
{ {
@@ -983,6 +1301,7 @@ c_acoth(COMPLEX *c, NUMBER *epsilon)
return tmp2; return tmp2;
} }
COMPLEX * COMPLEX *
c_asech(COMPLEX *c, NUMBER *epsilon) c_asech(COMPLEX *c, NUMBER *epsilon)
{ {
@@ -994,6 +1313,7 @@ c_asech(COMPLEX *c, NUMBER *epsilon)
return tmp2; return tmp2;
} }
COMPLEX * COMPLEX *
c_acsch(COMPLEX *c, NUMBER *epsilon) c_acsch(COMPLEX *c, NUMBER *epsilon)
{ {

View File

@@ -38,6 +38,77 @@ COMPLEX _conei_ = { &_qzero_, &_qone_, 1 };
STATIC COMPLEX _cnegone_ = { &_qnegone_, &_qzero_, 1 }; STATIC COMPLEX _cnegone_ = { &_qnegone_, &_qzero_, 1 };
/*
* cmappr - complex multiple approximation
*
* Approximate a number to nearest multiple of a given real number. Whether
* rounding is down, up, etc. is determined by rnd.
*
* This function is useful to round a result to the nearest epsilon:
*
* COMPLEX *c; (* complex number to round to nearest epsilon *)
* NUMBER *eps; (* epsilon rounding precision *)
* COMPLEX *res; (* c rounded to nearest epsilon *)
* long rnd = 24L; (* a common rounding mode *)
* bool ok_to_free; (* true ==> free c, false ==> do not free c *)
*
* ...
*
* res = cmappr(c, eps, ok_to_free);
*
* given:
* c pointer to COMPLEX value to round
* e pointer to NUMBER multiple
* rnd rounding mode
* cfree true ==> free c, false ==> do not free c
*
* returns:
* allocated pointer to COMPLEX multiple of e approximation of c
*/
COMPLEX *
cmappr(COMPLEX *c, NUMBER *e, long rnd, bool cfree)
{
COMPLEX *r; /* COMPLEX multiple of e approximation of c */
/*
* firewall
*/
if (c == NULL) {
math_error("%s: c is NULL", __func__);
not_reached();
}
if (e == NULL) {
math_error("%s: e is NULL", __func__);
not_reached();
}
/*
* allocate return result
*/
r = comalloc();
/*
* round c to multiple of e
*/
qfree(r->real);
r->real = qmappr(c->real, e, rnd);
qfree(r->imag);
r->imag = qmappr(c->imag, e, rnd);
/*
* free c if requested
*/
if (cfree == true) {
comfree(c);
}
/*
* return the allocated multiple of e approximation of c
*/
return r;
}
/* /*
* Add two complex numbers. * Add two complex numbers.
*/ */

195
func.c
View File

@@ -2927,8 +2927,9 @@ f_sin(int count, VALUE **vals)
break; break;
case V_COM: case V_COM:
c = c_sin(vals[0]->v_com, eps); c = c_sin(vals[0]->v_com, eps);
if (c == NULL) if (c == NULL) {
return error_value(E_SIN3); return error_value(E_SIN3);
}
result.v_com = c; result.v_com = c;
result.v_type = V_COM; result.v_type = V_COM;
if (cisreal(c)) { if (cisreal(c)) {
@@ -2947,18 +2948,16 @@ S_FUNC VALUE
f_tan(int count, VALUE **vals) f_tan(int count, VALUE **vals)
{ {
VALUE result; VALUE result;
VALUE tmp1, tmp2; COMPLEX *c;
NUMBER *err; NUMBER *err;
/* initialize VALUEs */ /* initialize VALUEs */
result.v_subtype = V_NOSUBTYPE; result.v_subtype = V_NOSUBTYPE;
tmp1.v_subtype = V_NOSUBTYPE;
tmp2.v_subtype = V_NOSUBTYPE;
/* /*
* set error tolerance for builtin function * set error tolerance for builtin function
* *
* Use eps VALUE arg if given and value is in a valid range. * Use err VALUE arg if given and value is in a valid range.
*/ */
err = conf->epsilon; err = conf->epsilon;
if (count == 2) { if (count == 2) {
@@ -2967,6 +2966,7 @@ f_tan(int count, VALUE **vals)
} }
err = vals[1]->v_num; err = vals[1]->v_num;
} }
/* /*
* compute tangent to a given error tolerance * compute tangent to a given error tolerance
*/ */
@@ -2976,20 +2976,16 @@ f_tan(int count, VALUE **vals)
result.v_type = V_NUM; result.v_type = V_NUM;
break; break;
case V_COM: case V_COM:
tmp1.v_type = V_COM; c = c_tan(vals[0]->v_com, err);
tmp1.v_com = c_sin(vals[0]->v_com, err); if (c == NULL) {
if (tmp1.v_com == NULL) { return error_value(E_TAN5);
return error_value(E_TAN3);
} }
tmp2.v_type = V_COM; result.v_com = c;
tmp2.v_com = c_cos(vals[0]->v_com, err); result.v_type = V_COM;
if (tmp2.v_com == NULL) { if (cisreal(c)) {
comfree(tmp1.v_com); result.v_num = c_to_q(c, true);
return error_value(E_TAN4); result.v_type = V_NUM;
} }
divvalue(&tmp1, &tmp2, &result);
comfree(tmp1.v_com);
comfree(tmp2.v_com);
break; break;
default: default:
return error_value(E_TAN2); return error_value(E_TAN2);
@@ -2997,21 +2993,77 @@ f_tan(int count, VALUE **vals)
return result; return result;
} }
S_FUNC VALUE S_FUNC VALUE
f_sec(int count, VALUE **vals) f_cot(int count, VALUE **vals)
{ {
VALUE result; VALUE result;
VALUE tmp; COMPLEX *c;
NUMBER *err; NUMBER *err;
/* initialize VALUEs */ /* initialize VALUEs */
result.v_subtype = V_NOSUBTYPE; result.v_subtype = V_NOSUBTYPE;
tmp.v_subtype = V_NOSUBTYPE;
/* /*
* set error tolerance for builtin function * set error tolerance for builtin function
* *
* Use eps VALUE arg if given and value is in a valid range. * Use err VALUE arg if given and value is in a valid range.
*/
err = conf->epsilon;
if (count == 2) {
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)) {
return error_value(E_COT5);
}
result.v_num = qcot(vals[0]->v_num, err);
result.v_type = V_NUM;
break;
case V_COM:
if (ciszero(vals[0]->v_com)) {
return error_value(E_COT5);
}
c = c_cot(vals[0]->v_com, err);
if (c == NULL) {
return error_value(E_COT6);
}
result.v_com = c;
result.v_type = V_COM;
if (cisreal(c)) {
result.v_num = c_to_q(c, true);
result.v_type = V_NUM;
}
break;
default:
return error_value(E_COT2);
}
return result;
}
S_FUNC VALUE
f_sec(int count, VALUE **vals)
{
VALUE result;
COMPLEX *c;
NUMBER *err;
/* initialize VALUEs */
result.v_subtype = V_NOSUBTYPE;
/*
* set error tolerance for builtin function
*
* Use err VALUE arg if given and value is in a valid range.
*/ */
err = conf->epsilon; err = conf->epsilon;
if (count == 2) { if (count == 2) {
@@ -3030,13 +3082,16 @@ f_sec(int count, VALUE **vals)
result.v_type = V_NUM; result.v_type = V_NUM;
break; break;
case V_COM: case V_COM:
tmp.v_type = V_COM; c = c_sec(vals[0]->v_com, err);
tmp.v_com = c_cos(vals[0]->v_com, err); if (c == NULL) {
if (tmp.v_com == NULL) { return error_value(E_SEC5);
return error_value(E_SEC3); }
result.v_com = c;
result.v_type = V_COM;
if (cisreal(c)) {
result.v_num = c_to_q(c, true);
result.v_type = V_NUM;
} }
invertvalue(&tmp, &result);
comfree(tmp.v_com);
break; break;
default: default:
return error_value(E_SEC2); return error_value(E_SEC2);
@@ -3045,79 +3100,20 @@ f_sec(int count, VALUE **vals)
} }
S_FUNC VALUE
f_cot(int count, VALUE **vals)
{
VALUE result;
VALUE tmp1, tmp2;
NUMBER *err;
/* initialize VALUEs */
result.v_subtype = V_NOSUBTYPE;
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 (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))
return error_value(E_1OVER0);
result.v_num = qcot(vals[0]->v_num, err);
result.v_type = V_NUM;
break;
case V_COM:
tmp1.v_type = V_COM;
tmp1.v_com = c_cos(vals[0]->v_com, err);
if (tmp1.v_com == NULL) {
return error_value(E_COT3);
}
tmp2.v_type = V_COM;
tmp2.v_com = c_sin(vals[0]->v_com, err);
if (tmp2.v_com == NULL) {
comfree(tmp1.v_com);
return error_value(E_COT4);
}
divvalue(&tmp1, &tmp2, &result);
comfree(tmp1.v_com);
comfree(tmp2.v_com);
break;
default:
return error_value(E_COT2);
}
return result;
}
S_FUNC VALUE S_FUNC VALUE
f_csc(int count, VALUE **vals) f_csc(int count, VALUE **vals)
{ {
VALUE result; VALUE result;
VALUE tmp; COMPLEX *c;
NUMBER *err; NUMBER *err;
/* initialize VALUEs */ /* initialize VALUEs */
result.v_subtype = V_NOSUBTYPE; result.v_subtype = V_NOSUBTYPE;
tmp.v_subtype = V_NOSUBTYPE;
/* /*
* set error tolerance for builtin function * set error tolerance for builtin function
* *
* Use eps VALUE arg if given and value is in a valid range. * Use err VALUE arg if given and value is in a valid range.
*/ */
err = conf->epsilon; err = conf->epsilon;
if (count == 2) { if (count == 2) {
@@ -3132,19 +3128,26 @@ f_csc(int count, VALUE **vals)
*/ */
switch (vals[0]->v_type) { switch (vals[0]->v_type) {
case V_NUM: case V_NUM:
if (qiszero(vals[0]->v_num)) if (qiszero(vals[0]->v_num)) {
return error_value(E_1OVER0); return error_value(E_CSC5);
}
result.v_num = qcsc(vals[0]->v_num, err); result.v_num = qcsc(vals[0]->v_num, err);
result.v_type = V_NUM; result.v_type = V_NUM;
break; break;
case V_COM: case V_COM:
tmp.v_type = V_COM; if (ciszero(vals[0]->v_com)) {
tmp.v_com = c_sin(vals[0]->v_com, err); return error_value(E_CSC5);
if (tmp.v_com == NULL) { }
return error_value(E_CSC3); c = c_csc(vals[0]->v_com, err);
if (c == NULL) {
return error_value(E_CSC6);
}
result.v_com = c;
result.v_type = V_COM;
if (cisreal(c)) {
result.v_num = c_to_q(c, true);
result.v_type = V_NUM;
} }
invertvalue(&tmp, &result);
comfree(tmp.v_com);
break; break;
default: default:
return error_value(E_CSC2); return error_value(E_CSC2);

View File

@@ -14,6 +14,10 @@ DESCRIPTION
Calculate the cotangent of x to a multiple of eps, with error less Calculate the cotangent of x to a multiple of eps, with error less
in absolute value than .75 * eps. in absolute value than .75 * eps.
This function is equivalent to:
cot(x) = cos(x) / sin(x)
EXAMPLE EXAMPLE
; print cot(1, 1e-5), cot(1, 1e-10), cot(1, 1e-15), cot(1, 1e-20) ; print cot(1, 1e-5), cot(1, 1e-10), cot(1, 1e-15), cot(1, 1e-20)
0.64209 0.6420926159 0.642092615934331 0.64209261593433070301 0.64209 0.6420926159 0.642092615934331 0.64209261593433070301
@@ -33,6 +37,7 @@ LIMITS
LINK LIBRARY LINK LIBRARY
NUMBER *qcot(NUMBER *x, NUMBER *eps) NUMBER *qcot(NUMBER *x, NUMBER *eps)
COMPLEX *c_cot(COMPLEX *c, NUMBER *eps)
SEE ALSO SEE ALSO
sin, cos, tan, sec, csc sin, cos, tan, sec, csc

View File

@@ -14,6 +14,10 @@ DESCRIPTION
Calculate the cosecant of x to a multiple of eps, with error less Calculate the cosecant of x to a multiple of eps, with error less
in absolute value than .75 * eps. in absolute value than .75 * eps.
This function is equivalent to:
csc(x) = 1 / sin(x)
EXAMPLE EXAMPLE
; print csc(1, 1e-5), csc(1, 1e-10), csc(1, 1e-15), csc(1, 1e-20) ; print csc(1, 1e-5), csc(1, 1e-10), csc(1, 1e-15), csc(1, 1e-20)
1.1884 1.1883951058 1.188395105778121 1.18839510577812121626 1.1884 1.1883951058 1.188395105778121 1.18839510577812121626
@@ -33,6 +37,7 @@ LIMITS
LINK LIBRARY LINK LIBRARY
NUMBER *qcsc(NUMBER *x, NUMBER *eps) NUMBER *qcsc(NUMBER *x, NUMBER *eps)
COMPLEX *c_csc(COMPLEX *c, NUMBER *eps)
SEE ALSO SEE ALSO
sin, cos, tan, cot, sec sin, cos, tan, cot, sec

View File

@@ -14,6 +14,10 @@ DESCRIPTION
Calculate the secant of x to a multiple of eps, with error less Calculate the secant of x to a multiple of eps, with error less
in absolute value than .75 * eps. in absolute value than .75 * eps.
This function is equivalent to:
sec(x) = 1 / cos(x)
EXAMPLE EXAMPLE
; print sec(1, 1e-5), sec(1, 1e-10), sec(1, 1e-15), sec(1, 1e-20) ; print sec(1, 1e-5), sec(1, 1e-10), sec(1, 1e-15), sec(1, 1e-20)
1.85082 1.8508157177 1.850815717680926 1.85081571768092561791 1.85082 1.8508157177 1.850815717680926 1.85081571768092561791
@@ -33,6 +37,7 @@ LIMITS
LINK LIBRARY LINK LIBRARY
NUMBER *qsec(NUMBER *x, NUMBER *eps) NUMBER *qsec(NUMBER *x, NUMBER *eps)
COMPLEX *c_sec(COMPLEX *c, NUMBER *eps)
SEE ALSO SEE ALSO
sin, cos, tan, cot, csc sin, cos, tan, cot, csc

View File

@@ -14,6 +14,10 @@ DESCRIPTION
Calculate the tangent of x to a multiple of eps, with error less Calculate the tangent of x to a multiple of eps, with error less
in absolute value than .75 * eps. in absolute value than .75 * eps.
This function is equivalent to:
tan(x) = sin(x) / cos(x)
EXAMPLE EXAMPLE
; print tan(1, 1e-5), tan(1, 1e-10), tan(1, 1e-15), tan(1, 1e-20) ; print tan(1, 1e-5), tan(1, 1e-10), tan(1, 1e-15), tan(1, 1e-20)
1.55741 1.5574077247 1.557407724654902 1.55740772465490223051 1.55741 1.5574077247 1.557407724654902 1.55740772465490223051
@@ -33,6 +37,7 @@ LIMITS
LINK LIBRARY LINK LIBRARY
NUMBER *qtan(NUMBER *x, NUMBER *eps) NUMBER *qtan(NUMBER *x, NUMBER *eps)
COMPLEX *c_tan(COMPLEX *c, NUMBER *eps)
SEE ALSO SEE ALSO
sin, cos, cot, sec, csc sin, cos, cot, sec, csc