summaryrefslogtreecommitdiffstats
path: root/lib/msun/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/msun/src')
-rw-r--r--lib/msun/src/k_cosf.c13
1 files changed, 12 insertions, 1 deletions
diff --git a/lib/msun/src/k_cosf.c b/lib/msun/src/k_cosf.c
index fb021ed..4239ae1 100644
--- a/lib/msun/src/k_cosf.c
+++ b/lib/msun/src/k_cosf.c
@@ -44,10 +44,21 @@ __kernel_cosf(float x, float y)
if(ix < 0x3e99999a) /* if |x| < 0.3 */
return one - ((float)0.5*z - (z*r - x*y));
else {
+ /*
+ * qx is an approximation to x*x/2 such that 1-qx and x*x/2-qx
+ * are both exact. Its implementation is optimized for
+ * efficiency in preference to accuracy. We use x*x/2 ~ x/4 for
+ * x near 0.5 and mask off just enough low bits (3) for both of
+ * the above differences to be exact. We use a constant for
+ * x > 0.78125 to keep using the same algorithm as k_cos.c,
+ * although this gives only a small improvement in accuracy, at
+ * least here. Using x*x/2 to approximate itself (masking off
+ * 3 low bits again) would give better accuracy.
+ */
if(ix > 0x3f480000) { /* x > 0.78125 */
qx = (float)0.28125;
} else {
- SET_FLOAT_WORD(qx,ix-0x01000000); /* x/4 */
+ SET_FLOAT_WORD(qx,(ix-0x01000000)&0xfffffff8);
}
hz = (float)0.5*z-qx;
a = one-qx;
OpenPOWER on IntegriCloud