11dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*-
21dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Copyright (c) 2005 David Schultz <das@FreeBSD.ORG>
31dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * All rights reserved.
41dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
51dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Redistribution and use in source and binary forms, with or without
61dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * modification, are permitted provided that the following conditions
71dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * are met:
81dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 1. Redistributions of source code must retain the above copyright
91dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright
111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    notice, this list of conditions and the following disclaimer in the
121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    documentation and/or other materials provided with the distribution.
131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * SUCH DAMAGE.
251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <sys/cdefs.h>
28a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes__FBSDID("$FreeBSD$");
29a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes
30a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes#include <float.h>
311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "math.h"
331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "math_private.h"
341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define	TBLBITS	4
361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define	TBLSIZE	(1 << TBLBITS)
371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic const float
391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    redux   = 0x1.8p23f / TBLSIZE,
401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    P1	    = 0x1.62e430p-1f,
411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    P2	    = 0x1.ebfbe0p-3f,
421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    P3	    = 0x1.c6b348p-5f,
431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    P4	    = 0x1.3b2c9cp-7f;
441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4578419467a2f88744ae2445fca5eb442877ebb1b0Elliott Hughesstatic volatile float
4678419467a2f88744ae2445fca5eb442877ebb1b0Elliott Hughes    huge    = 0x1p100f,
4778419467a2f88744ae2445fca5eb442877ebb1b0Elliott Hughes    twom100 = 0x1p-100f;
48a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes
491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic const double exp2ft[TBLSIZE] = {
501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	0x1.6a09e667f3bcdp-1,
511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	0x1.7a11473eb0187p-1,
521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	0x1.8ace5422aa0dbp-1,
531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	0x1.9c49182a3f090p-1,
541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	0x1.ae89f995ad3adp-1,
551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	0x1.c199bdd85529cp-1,
561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	0x1.d5818dcfba487p-1,
571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	0x1.ea4afa2a490dap-1,
581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	0x1.0000000000000p+0,
591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	0x1.0b5586cf9890fp+0,
601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	0x1.172b83c7d517bp+0,
611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	0x1.2387a6e756238p+0,
621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	0x1.306fe0a31b715p+0,
631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	0x1.3dea64c123422p+0,
641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	0x1.4bfdad5362a27p+0,
651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	0x1.5ab07dd485429p+0,
661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project};
671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*
691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * exp2f(x): compute the base 2 exponential of x
701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Accuracy: Peak error < 0.501 ulp; location of peak: -0.030110927.
721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Method: (equally-spaced tables)
741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   Reduce x:
761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     x = 2**k + y, for integer k and |y| <= 1/2.
771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     Thus we have exp2f(x) = 2**k * exp2(y).
781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   Reduce y:
801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     y = i/TBLSIZE + z for integer i near y * TBLSIZE.
811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z),
821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     with |z| <= 2**-(TBLSIZE+1).
831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a
851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   degree-4 minimax polynomial with maximum error under 1.4 * 2**-33.
86a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes *   Using double precision for everything except the reduction makes
87a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes *   roundoff error insignificant and simplifies the scaling step.
881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   This method is due to Tang, but I do not use his suggested parameters:
901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *	Tang, P.  Table-driven Implementation of the Exponential Function
921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *	in IEEE Floating-Point Arithmetic.  TOMS 15(2), 144-157 (1989).
931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectfloat
951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectexp2f(float x)
961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
97a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes	double tv, twopk, u, z;
98a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes	float t;
99a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes	uint32_t hx, ix, i0;
1001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	int32_t k;
1011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	/* Filter out exceptional cases. */
103a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes	GET_FLOAT_WORD(hx, x);
1041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	ix = hx & 0x7fffffff;		/* high word of |x| */
1051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if(ix >= 0x43000000) {			/* |x| >= 128 */
1061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		if(ix >= 0x7f800000) {
1071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			if ((ix & 0x7fffff) != 0 || (hx & 0x80000000) == 0)
108a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes				return (x + x);	/* x is NaN or +Inf */
1091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			else
1101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project				return (0.0);	/* x is -Inf */
1111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		}
1121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		if(x >= 0x1.0p7f)
1131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			return (huge * huge);	/* overflow */
1141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		if(x <= -0x1.2cp7f)
1151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			return (twom100 * twom100); /* underflow */
1161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	} else if (ix <= 0x33000000) {		/* |x| <= 0x1p-25 */
1171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		return (1.0f + x);
1181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	}
1191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	/* Reduce x, computing z, i0, and k. */
121a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes	STRICT_ASSIGN(float, t, x + redux);
1221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	GET_FLOAT_WORD(i0, t);
1231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	i0 += TBLSIZE / 2;
124a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes	k = (i0 >> TBLBITS) << 20;
1251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	i0 &= TBLSIZE - 1;
1261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	t -= redux;
1271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	z = x - t;
128a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes	INSERT_WORDS(twopk, 0x3ff00000 + k, 0);
1291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	/* Compute r = exp2(y) = exp2ft[i0] * p(z). */
1311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	tv = exp2ft[i0];
132a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes	u = tv * z;
133a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes	tv = tv + u * (P1 + z * P2) + u * (z * z) * (P3 + z * P4);
1341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
135a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes	/* Scale by 2**(k>>20). */
136a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes	return (tv * twopk);
1371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
138