summaryrefslogtreecommitdiffstats
path: root/lib/msun/src/s_cos.c
diff options
context:
space:
mode:
authorbde <bde@FreeBSD.org>2005-10-24 14:08:36 +0000
committerbde <bde@FreeBSD.org>2005-10-24 14:08:36 +0000
commit5931c79161136c38c59ced85bd9c919fb37c8710 (patch)
treeafab8a841e03b45446f1c4a211ccce34cb3afdab /lib/msun/src/s_cos.c
parentf75fe16509bebb9bc695bb964cea2e760cfda169 (diff)
downloadFreeBSD-src-5931c79161136c38c59ced85bd9c919fb37c8710.zip
FreeBSD-src-5931c79161136c38c59ced85bd9c919fb37c8710.tar.gz
Moved the optimization for tiny x from __kernel_{cos,sin}[f](x) to
{cos_sin}[f](x) so that x doesn't need to be reclassified in the "kernel" functions to determine if it is tiny (it still needs to be reclassified in the cosine case for other reasons that will go away). This optimization is quite large for exponentially distributed x, since x is tiny for almost half of the domain, but it is a pessimization for uniformally distributed x since it takes a little time for all cases but rarely applies. Arg reduction on exponentially distributed x rarely gives a tiny x unless the reduction is null, so it is best to only do the optimization if the initial x is tiny, which is what this commit arranges. The imediate result is an average optimization of 1.4% relative to the previous version in a case that doesn't favour the optimization (double cos(x) on all float x) and a large pessimization for the relatively unimportant cases of lgamma[f][_r](x) on tiny, negative, exponentially distributed x. The optimization should be recovered for lgamma*() as part of fixing lgamma*()'s low-quality arg reduction. Fixed various wrong constants for the cutoff for "tiny". For cosine, the cutoff is when x**2/2! == {FLT or DBL}_EPSILON/2. We round down to an integral power of 2 (and for cos() reduce the power by another 1) because the exact cutoff doesn't matter and would take more work to determine. For sine, the exact cutoff is larger due to the ration of terms being x**2/3! instead of x**2/2!, but we use the same cutoff as for cosine. We now use a cutoff of 2**-27 for double precision and 2**-12 for single precision. 2**-27 was used in all cases but was misspelled 2**27 in comments. Wrong and sloppy cutoffs just cause missed optimizations (provided the rounding mode is to nearest -- other modes just aren't supported).
Diffstat (limited to 'lib/msun/src/s_cos.c')
-rw-r--r--lib/msun/src/s_cos.c6
1 files changed, 5 insertions, 1 deletions
diff --git a/lib/msun/src/s_cos.c b/lib/msun/src/s_cos.c
index b49b28a..17afa34 100644
--- a/lib/msun/src/s_cos.c
+++ b/lib/msun/src/s_cos.c
@@ -59,7 +59,11 @@ cos(double x)
/* |x| ~< pi/4 */
ix &= 0x7fffffff;
- if(ix <= 0x3fe921fb) return __kernel_cos(x,z);
+ if(ix <= 0x3fe921fb) {
+ if(ix<0x3e400000) /* if x < 2**-27 */
+ if(((int)x)==0) return 1.0; /* generate inexact */
+ return __kernel_cos(x,z);
+ }
/* cos(Inf or NaN) is NaN */
else if (ix>=0x7ff00000) return x-x;
OpenPOWER on IntegriCloud