summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authormartin <martin@NetBSD.org>2020-05-25 15:26:05 +0000
committermartin <martin@NetBSD.org>2020-05-25 15:26:05 +0000
commit8b47b75da19e4d7ee256c011d2ff85ecb1fc980c (patch)
tree2d2192911aba0f9653bf821173740f77ef27d04f /lib
parentd6636233f2734acab9ab745f80622dba86e74629 (diff)
Pull up following revision(s) (requested by riastradh in ticket #920):
lib/libc/compat/gen/compat_ldexp_ieee754.c: revision 1.8 Teach libc's compat ldexp stub to raise fp exceptions. This ldexp stub will shadow the ldexp weak alias for scalbn in libm, which is unfortunate but hard to fix properly without chasing the mythical libc bump beast. With the change here, we should raise all the same exceptions that libm's scalbn does -- overflow, underflow, inexact-result, and (for signalling NaN only) invalid-operation. This in turn should correct the missing overflow/underflow exceptions of our portable C fma, and perhaps other routines. XXX pullup
Diffstat (limited to 'lib')
-rw-r--r--lib/libc/compat/gen/compat_ldexp_ieee754.c57
1 files changed, 35 insertions, 22 deletions
diff --git a/lib/libc/compat/gen/compat_ldexp_ieee754.c b/lib/libc/compat/gen/compat_ldexp_ieee754.c
index 6e7fafc7659..457f9233bd9 100644
--- a/lib/libc/compat/gen/compat_ldexp_ieee754.c
+++ b/lib/libc/compat/gen/compat_ldexp_ieee754.c
@@ -1,4 +1,4 @@
-/* $NetBSD: compat_ldexp_ieee754.c,v 1.7 2016/08/27 09:35:13 christos Exp $ */
+/* $NetBSD: compat_ldexp_ieee754.c,v 1.7.16.1 2020/05/25 15:26:05 martin Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -31,14 +31,34 @@
#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: compat_ldexp_ieee754.c,v 1.7 2016/08/27 09:35:13 christos Exp $");
+__RCSID("$NetBSD: compat_ldexp_ieee754.c,v 1.7.16.1 2020/05/25 15:26:05 martin Exp $");
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
+
#include <machine/ieee.h>
+
#include <errno.h>
+#include <float.h>
+#include <math.h>
+
+static volatile const double tiny = DBL_MIN, huge = DBL_MAX;
+
+static double
+underflow(double val)
+{
+
+ errno = ERANGE;
+ return (val < 0 ? -tiny*tiny : tiny*tiny);
+}
+
+static double
+overflow(double val)
+{
-double ldexp(double, int);
+ errno = ERANGE;
+ return (val < 0 ? -huge*huge : huge*huge);
+}
/*
* Multiply the given value by 2^expon.
@@ -53,10 +73,13 @@ ldexp(double val, int expon)
oldexp = u.dblu_dbl.dbl_exp;
/*
- * If input is zero, Inf or NaN, just return it.
+ * If input is zero, Inf or NaN, just return it, but raise
+ * invalid exception if it is a signalling NaN: adding any of
+ * these inputs to itself gives itself as output; arithmetic on
+ * a signalling NaN additionally raises invalid-operation.
*/
if (u.dblu_d == 0.0 || oldexp == DBL_EXP_INFNAN)
- return (val);
+ return (val + val);
if (oldexp == 0) {
/*
@@ -68,17 +91,13 @@ ldexp(double val, int expon)
* Optimization: if the scaling can be done in a single
* multiply, or underflows, just do it now.
*/
- if (expon <= -DBL_FRACBITS) {
- errno = ERANGE;
- return (val < 0.0 ? -0.0 : 0.0);
- }
+ if (expon <= -DBL_FRACBITS)
+ return underflow(val);
mul.dblu_d = 0.0;
mul.dblu_dbl.dbl_exp = expon + DBL_EXP_BIAS;
u.dblu_d *= mul.dblu_d;
- if (u.dblu_d == 0.0) {
- errno = ERANGE;
- return (val < 0.0 ? -0.0 : 0.0);
- }
+ if (u.dblu_d == 0.0)
+ return underflow(val);
return (u.dblu_d);
} else {
/*
@@ -105,20 +124,14 @@ ldexp(double val, int expon)
/*
* The result overflowed; return +/-Inf.
*/
- u.dblu_dbl.dbl_exp = DBL_EXP_INFNAN;
- u.dblu_dbl.dbl_frach = 0;
- u.dblu_dbl.dbl_fracl = 0;
- errno = ERANGE;
- return (u.dblu_d);
+ return overflow(val);
} else if (newexp <= 0) {
/*
* The output number is either denormal or underflows (see
* comments in machine/ieee.h).
*/
- if (newexp <= -DBL_FRACBITS) {
- errno = ERANGE;
- return (val < 0.0 ? -0.0 : 0.0);
- }
+ if (newexp <= -DBL_FRACBITS)
+ return underflow(val);
/*
* Denormalize the result. We do this with a multiply. If
* expon is very large, it won't fit in a double, so we have