decNumber* decNumberSin (decNumber *_result, decNumber *y, decContext *set)
{
decNumber pi, pi2, zero, one, two, x, fctl, term, cmp, result;
int i;
int negate = 0;
DEC_STASH_CONTEXT (set, &zero);
decNumberFromString (&one, "1", set);
decNumberFromString (&two, "2", set);
decNumberFromString (&pi, PI , set);
// Copy the argument y, so we can modify it.
decNumberCopy (&x, y);
// sin -x = - sin x
/* if (decCompare (&x, &zero) < 0) { */
if (decNumberIsNegative (&x)) { // x < 0
decNumberMinus (&x, &x, set);
negate = 1;
}
// We now have x >= 0
decNumberMultiply (&pi2, &pi, &two, set); // pi2 = 2*pi
decNumberMod (&x, &x, &pi2, set);
// We now have 0 <= x < 2*pi
/*if (decCompare (&x, &pi) >= 0) {*/
decNumberCompare (&cmp, &x, &pi, set);
if (!decNumberIsNegative (&cmp)) {
// x >= pi
decNumberSubtract (&x, &x, &pi, set);
negate = 1-negate;
}
// We now have 0 <= x < pi
decNumberDivide (&pi2, &pi, &two, set); // pi2 = pi/2
/*if (decCompare (&x, &pi2) >= 0) {*/
decNumberCompare (&cmp, &x, &pi2, set);
if (!decNumberIsNegative (&cmp)) {
// x >= pi/2, so let x = pi-x
decNumberSubtract (&x, &pi, &x, set);
}
// We now have 0 <= x <= pi/2.
// x^3 x^5 x^7
// sin x = x - --- + --- - ---- + ...
// 6 120 5040
//
// term(0) = x
// term(i) = - term(i-1) * x^2 / ((2*i)*(2*i+1))
decNumberCopy (&fctl, &one);
decNumberCopy (&term, &x);
decNumberCopy (&result, &x);
// DECNUMDIGITS+3 terms are enough to achieve the required precision.
for (i=0; i<DECNUMDIGITS+3; i++) {
decNumber tmpd, termout;
// term = -term * x^2 / (cnt*(cnt+1))
// cnt = cnt+2
decNumberMinus (&term, &term, set);
decNumberMultiply (&term, &term, &x, set);
decNumberMultiply (&term, &term, &x, set);
// Compute denominator and generate term.
decNumberFromInt32 (&tmpd, ((i+1)*2 + 1) * ((i+1)*2));
decNumberMultiply (&fctl, &fctl, &tmpd, set);
decNumberDivide (&termout, &term, &fctl, set);
// sum = sum + term
decNumberAdd (&result, &result, &termout, set);
}
if (negate) {
decNumberMinus (&result, &result, set);
}
DEC_RESTORE_ROUND (set, _result, &result, &zero)
return _result;
} /* decNumberSin */