aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorBruce Evans <bde@FreeBSD.org>1997-02-16 17:38:11 +0000
committerBruce Evans <bde@FreeBSD.org>1997-02-16 17:38:11 +0000
commit72d8d94d6fe43e71a78956d9b417a1a65d20e87e (patch)
tree77c7efbf934cf008ec346a0efb3e621bedf4c404 /lib
parenta4bd858367c3c88cf946422a02000b4caa40f0e4 (diff)
downloadsrc-72d8d94d6fe43e71a78956d9b417a1a65d20e87e.tar.gz
src-72d8d94d6fe43e71a78956d9b417a1a65d20e87e.zip
Fixed the i87 version of exp(). It returned NaN for args +-Inf. It had
some small (one or two ULP) inaccuracies. Found by: ucbtest
Notes
Notes: svn path=/head/; revision=22802
Diffstat (limited to 'lib')
-rw-r--r--lib/msun/i387/e_exp.S42
1 files changed, 42 insertions, 0 deletions
diff --git a/lib/msun/i387/e_exp.S b/lib/msun/i387/e_exp.S
index 0609df0f43bd..c9a652691833 100644
--- a/lib/msun/i387/e_exp.S
+++ b/lib/msun/i387/e_exp.S
@@ -39,7 +39,30 @@ RCSID("$FreeBSD$")
/* e^x = 2^(x * log2(e)) */
ENTRY(__ieee754_exp)
+ /*
+ * If x is +-Inf, then the subtraction would give Inf-Inf = NaN.
+ * Avoid this. Also avoid it if x is NaN for convenience.
+ */
+ movl 8(%esp),%eax
+ andl $0x7fffffff,%eax
+ cmpl $0x7ff00000,%eax
+ jae x_Inf_or_NaN
+
fldl 4(%esp)
+
+ /*
+ * Ensure that the rounding mode is to nearest (to give the smallest
+ * possible fraction) and that the precision is as high as possible.
+ * We may as well mask interrupts if we switch the mode.
+ */
+ fstcw 4(%esp)
+ movl 4(%esp),%eax
+ andl $0x0300,%eax
+ cmpl $0x0300,%eax /* RC == 0 && PC == 3? */
+ je 1f /* jump if mode is good */
+ movl $0x137f,8(%esp)
+ fldcw 8(%esp)
+1:
fldl2e
fmulp /* x * log2(e) */
fstl %st(1)
@@ -51,4 +74,23 @@ ENTRY(__ieee754_exp)
faddp /* 2^(fract(x * log2(e))) */
fscale /* e^x */
fstpl %st(1)
+ je 1f
+ fldcw 4(%esp)
+1:
+ ret
+
+x_Inf_or_NaN:
+ /*
+ * Return 0 if x is -Inf. Otherwise just return x, although the
+ * C version would return (x + x) (Real Indefinite) if x is a NaN.
+ */
+ cmpl $0xfff00000,8(%esp)
+ jne x_not_minus_Inf
+ cmpl $0,4(%esp)
+ jne x_not_minus_Inf
+ fldz
+ ret
+
+x_not_minus_Inf:
+ fldl 4(%esp)
ret