summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorbde <bde@FreeBSD.org>2005-11-10 17:43:49 +0000
committerbde <bde@FreeBSD.org>2005-11-10 17:43:49 +0000
commit9f37514a123bf2ec67aa6382b6528757c562e47d (patch)
treea4678776b4370fd98e9b3a7874bb63dbdd7cbda1 /lib
parent9487c057e255ed900f5033620724c359ec48e7eb (diff)
downloadFreeBSD-src-9f37514a123bf2ec67aa6382b6528757c562e47d.zip
FreeBSD-src-9f37514a123bf2ec67aa6382b6528757c562e47d.tar.gz
As for __kernel_cosf() and __kernel_sinf(), use a fairly optimal minimax
polynomial for __kernel_tanf(). The old one was the double-precision polynomial with coefficients truncated to float. Truncation is not a good way to convert minimax polynomials to lower precision. Optimize for efficiency and use the lowest-degree polynomial that gives a relative error of less than 1 ulp. It has degree 13 instead of 27, and happens to be 2.5 times more accurate (in infinite precision) than the old polynomial (the maximum error is 0.017 ulps instead of 0.041 ulps). Unlike for cosf and sinf, the old accuracy was close to being inadequate -- the polynomial for double precision has a max error of 0.014 ulps and nearly this small an error is needed. The new accuracy is also a bit small, but exhaustive checking shows that even the old accuracy was enough. The increased accuracy reduces the maximum relative error in the final result on amd64 -O1 from 0.9588 ulps to 0.9044 ulps.
Diffstat (limited to 'lib')
-rw-r--r--lib/msun/src/k_tanf.c28
1 files changed, 11 insertions, 17 deletions
diff --git a/lib/msun/src/k_tanf.c b/lib/msun/src/k_tanf.c
index 8e19309..e7b816d 100644
--- a/lib/msun/src/k_tanf.c
+++ b/lib/msun/src/k_tanf.c
@@ -22,20 +22,14 @@ static const float
one = 1.0000000000e+00, /* 0x3f800000 */
pio4 = 7.8539812565e-01, /* 0x3f490fda */
pio4lo= 3.7748947079e-08, /* 0x33222168 */
+/* Bounds for tan(x)/x - t(x): ~[-1.73e-09, 1.724e-09]. */
T[] = {
- 3.3333334327e-01, /* 0x3eaaaaab */
- 1.3333334029e-01, /* 0x3e088889 */
- 5.3968254477e-02, /* 0x3d5d0dd1 */
- 2.1869488060e-02, /* 0x3cb327a4 */
- 8.8632395491e-03, /* 0x3c11371f */
- 3.5920790397e-03, /* 0x3b6b6916 */
- 1.4562094584e-03, /* 0x3abede48 */
- 5.8804126456e-04, /* 0x3a1a26c8 */
- 2.4646313977e-04, /* 0x398137b9 */
- 7.8179444245e-05, /* 0x38a3f445 */
- 7.1407252108e-05, /* 0x3895c07a */
- -1.8558637748e-05, /* 0xb79bae5f */
- 2.5907305826e-05, /* 0x37d95384 */
+ 0xaaaaa3.0p-25, /* 0.33333310485 */
+ 0x888b06.0p-26, /* 0.13334283238 */
+ 0xdc84c8.0p-28, /* 0.053837567568 */
+ 0xb9d8f1.0p-29, /* 0.022686453536 */
+ 0xcfe632.0p-31, /* 0.0063445800915 */
+ 0xeaf97e.0p-31, /* 0.0071708550677 */
};
float
@@ -54,11 +48,11 @@ __kernel_tanf(float x, float y, int iy)
z = x*x;
w = z*z;
/* Break x^5*(T[1]+x^2*T[2]+...) into
- * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) +
- * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12]))
+ * x^5*(T[1]+x^4*T[3]+x^8*T[5]) +
+ * x^5*(x^2*(T[2]+x^4*T[4]))
*/
- r = T[1]+w*(T[3]+w*(T[5]+w*(T[7]+w*(T[9]+w*T[11]))));
- v = z*(T[2]+w*(T[4]+w*(T[6]+w*(T[8]+w*(T[10]+w*T[12])))));
+ r = T[1]+w*(T[3]+w*T[5]);
+ v = z*(T[2]+w*T[4]);
s = z*x;
r = y + z*(s*(r+v)+y);
r += T[0]*s;
OpenPOWER on IntegriCloud