summaryrefslogtreecommitdiff
path: root/lib/libc/arch/arm/gen/ldexp.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc/arch/arm/gen/ldexp.c')
-rw-r--r--lib/libc/arch/arm/gen/ldexp.c151
1 files changed, 151 insertions, 0 deletions
diff --git a/lib/libc/arch/arm/gen/ldexp.c b/lib/libc/arch/arm/gen/ldexp.c
new file mode 100644
index 00000000000..d35207c98b3
--- /dev/null
+++ b/lib/libc/arch/arm/gen/ldexp.c
@@ -0,0 +1,151 @@
+/* $NetBSD: ldexp.c,v 1.2 2001/11/08 22:45:45 bjh21 Exp $ */
+
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Charles M. Hannum.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/types.h>
+#include <machine/ieee.h>
+#include <errno.h>
+#include <math.h>
+
+/*
+ * Multiply the given value by 2^exponent.
+ */
+double
+ldexp(val, expo)
+ double val;
+ int expo;
+{
+ register int oldexp, newexp;
+ union {
+ double v;
+ struct ieee_double s;
+ } u, mul;
+
+ u.v = val;
+ oldexp = u.s.dbl_exp;
+
+ /*
+ * If input is zero, Inf or NaN, just return it.
+ */
+ if (u.v == 0.0 || oldexp == DBL_EXP_INFNAN)
+ return (val);
+
+ if (oldexp == 0) {
+ /*
+ * u.v is denormal. We must adjust it so that the exponent
+ * arithmetic below will work.
+ */
+ if (expo <= DBL_EXP_BIAS) {
+ /*
+ * Optimization: if the scaling can be done in a single
+ * multiply, or underflows, just do it now.
+ */
+ if (expo <= -DBL_FRACBITS) {
+ errno = ERANGE;
+ return (0.0);
+ }
+ mul.v = 0.0;
+ mul.s.dbl_exp = expo + DBL_EXP_BIAS;
+ u.v *= mul.v;
+ if (u.v == 0.0) {
+ errno = ERANGE;
+ return (0.0);
+ }
+ return (u.v);
+ } else {
+ /*
+ * We know that expo is very large, and therefore the
+ * result cannot be denormal (though it may be Inf).
+ * Shift u.v by just enough to make it normal.
+ */
+ mul.v = 0.0;
+ mul.s.dbl_exp = DBL_FRACBITS + DBL_EXP_BIAS;
+ u.v *= mul.v;
+ expo -= DBL_FRACBITS;
+ oldexp = u.s.dbl_exp;
+ }
+ }
+
+ /*
+ * u.v is now normalized and oldexp has been adjusted if necessary.
+ * Calculate the new exponent and check for underflow and overflow.
+ */
+ newexp = oldexp + expo;
+
+ if (newexp <= 0) {
+ /*
+ * The output number is either denormal or underflows (see
+ * comments in machine/ieee.h).
+ */
+ if (newexp <= -DBL_FRACBITS) {
+ errno = ERANGE;
+ return (0.0);
+ }
+ /*
+ * Denormalize the result. We do this with a multiply. If expo
+ * is very large, it won't fit in a double, so we have to
+ * adjust the exponent first. This is safe because we know
+ * that u.v is normal at this point.
+ */
+ if (expo <= -DBL_EXP_BIAS) {
+ u.s.dbl_exp = 1;
+ expo += oldexp - 1;
+ }
+ mul.v = 0.0;
+ mul.s.dbl_exp = expo + DBL_EXP_BIAS;
+ u.v *= mul.v;
+ return (u.v);
+ } else if (newexp >= DBL_EXP_INFNAN) {
+ /*
+ * The result overflowed; return +/-Inf.
+ */
+ u.s.dbl_exp = DBL_EXP_INFNAN;
+ u.s.dbl_frach = 0;
+ u.s.dbl_fracl = 0;
+ errno = ERANGE;
+ return (u.v);
+ } else {
+ /*
+ * The result is normal; just replace the old exponent with the
+ * new one.
+ */
+ u.s.dbl_exp = newexp;
+ return (u.v);
+ }
+}