diff options
author | Elliott Hughes <enh@google.com> | 2013-01-30 19:06:37 -0800 |
---|---|---|
committer | Elliott Hughes <enh@google.com> | 2013-02-01 14:51:19 -0800 |
commit | a0ee07829a9ba7e99ef68e8c12551301cc797f0f (patch) | |
tree | fefc432ee572779579a16d2868d4181a33399281 /libm/upstream-freebsd | |
parent | a990cf5b3392c5aef767aee1e67b4d7ef651afc6 (diff) | |
download | bionic-a0ee07829a9ba7e99ef68e8c12551301cc797f0f.zip bionic-a0ee07829a9ba7e99ef68e8c12551301cc797f0f.tar.gz bionic-a0ee07829a9ba7e99ef68e8c12551301cc797f0f.tar.bz2 |
Upgrade libm.
This brings us up to date with FreeBSD HEAD, fixes various bugs, unifies
the set of functions we support on ARM, MIPS, and x86, fixes "long double",
adds ISO C99 support, and adds basic unit tests.
It turns out that our "long double" functions have always been broken
for non-normal numbers. This patch fixes that by not using the upstream
implementations and just forwarding to the regular "double" implementation
instead (since "long double" on Android is just "double" anyway, which is
what BSD doesn't support).
All the tests pass on ARM, MIPS, and x86, plus glibc on x86-64.
Bug: 3169850
Bug: 8012787
Bug: https://code.google.com/p/android/issues/detail?id=6697
Change-Id: If0c343030959c24bfc50d4d21c9530052c581837
Diffstat (limited to 'libm/upstream-freebsd')
211 files changed, 20309 insertions, 0 deletions
diff --git a/libm/upstream-freebsd/lib/msun/bsdsrc/b_exp.c b/libm/upstream-freebsd/lib/msun/bsdsrc/b_exp.c new file mode 100644 index 0000000..4400992 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/bsdsrc/b_exp.c @@ -0,0 +1,175 @@ +/* + * Copyright (c) 1985, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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 University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +/* @(#)exp.c 8.1 (Berkeley) 6/4/93 */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + + +/* EXP(X) + * RETURN THE EXPONENTIAL OF X + * DOUBLE PRECISION (IEEE 53 bits, VAX D FORMAT 56 BITS) + * CODED IN C BY K.C. NG, 1/19/85; + * REVISED BY K.C. NG on 2/6/85, 2/15/85, 3/7/85, 3/24/85, 4/16/85, 6/14/86. + * + * Required system supported functions: + * scalb(x,n) + * copysign(x,y) + * finite(x) + * + * Method: + * 1. Argument Reduction: given the input x, find r and integer k such + * that + * x = k*ln2 + r, |r| <= 0.5*ln2 . + * r will be represented as r := z+c for better accuracy. + * + * 2. Compute exp(r) by + * + * exp(r) = 1 + r + r*R1/(2-R1), + * where + * R1 = x - x^2*(p1+x^2*(p2+x^2*(p3+x^2*(p4+p5*x^2)))). + * + * 3. exp(x) = 2^k * exp(r) . + * + * Special cases: + * exp(INF) is INF, exp(NaN) is NaN; + * exp(-INF)= 0; + * for finite argument, only exp(0)=1 is exact. + * + * Accuracy: + * exp(x) returns the exponential of x nearly rounded. In a test run + * with 1,156,000 random arguments on a VAX, the maximum observed + * error was 0.869 ulps (units in the last place). + */ + +#include "mathimpl.h" + +static const double p1 = 0x1.555555555553ep-3; +static const double p2 = -0x1.6c16c16bebd93p-9; +static const double p3 = 0x1.1566aaf25de2cp-14; +static const double p4 = -0x1.bbd41c5d26bf1p-20; +static const double p5 = 0x1.6376972bea4d0p-25; +static const double ln2hi = 0x1.62e42fee00000p-1; +static const double ln2lo = 0x1.a39ef35793c76p-33; +static const double lnhuge = 0x1.6602b15b7ecf2p9; +static const double lntiny = -0x1.77af8ebeae354p9; +static const double invln2 = 0x1.71547652b82fep0; + +#if 0 +double exp(x) +double x; +{ + double z,hi,lo,c; + int k; + +#if !defined(vax)&&!defined(tahoe) + if(x!=x) return(x); /* x is NaN */ +#endif /* !defined(vax)&&!defined(tahoe) */ + if( x <= lnhuge ) { + if( x >= lntiny ) { + + /* argument reduction : x --> x - k*ln2 */ + + k=invln2*x+copysign(0.5,x); /* k=NINT(x/ln2) */ + + /* express x-k*ln2 as hi-lo and let x=hi-lo rounded */ + + hi=x-k*ln2hi; + x=hi-(lo=k*ln2lo); + + /* return 2^k*[1+x+x*c/(2+c)] */ + z=x*x; + c= x - z*(p1+z*(p2+z*(p3+z*(p4+z*p5)))); + return scalb(1.0+(hi-(lo-(x*c)/(2.0-c))),k); + + } + /* end of x > lntiny */ + + else + /* exp(-big#) underflows to zero */ + if(finite(x)) return(scalb(1.0,-5000)); + + /* exp(-INF) is zero */ + else return(0.0); + } + /* end of x < lnhuge */ + + else + /* exp(INF) is INF, exp(+big#) overflows to INF */ + return( finite(x) ? scalb(1.0,5000) : x); +} +#endif + +/* returns exp(r = x + c) for |c| < |x| with no overlap. */ + +double __exp__D(x, c) +double x, c; +{ + double z,hi,lo; + int k; + + if (x != x) /* x is NaN */ + return(x); + if ( x <= lnhuge ) { + if ( x >= lntiny ) { + + /* argument reduction : x --> x - k*ln2 */ + z = invln2*x; + k = z + copysign(.5, x); + + /* express (x+c)-k*ln2 as hi-lo and let x=hi-lo rounded */ + + hi=(x-k*ln2hi); /* Exact. */ + x= hi - (lo = k*ln2lo-c); + /* return 2^k*[1+x+x*c/(2+c)] */ + z=x*x; + c= x - z*(p1+z*(p2+z*(p3+z*(p4+z*p5)))); + c = (x*c)/(2.0-c); + + return scalb(1.+(hi-(lo - c)), k); + } + /* end of x > lntiny */ + + else + /* exp(-big#) underflows to zero */ + if(finite(x)) return(scalb(1.0,-5000)); + + /* exp(-INF) is zero */ + else return(0.0); + } + /* end of x < lnhuge */ + + else + /* exp(INF) is INF, exp(+big#) overflows to INF */ + return( finite(x) ? scalb(1.0,5000) : x); +} diff --git a/libm/upstream-freebsd/lib/msun/bsdsrc/b_log.c b/libm/upstream-freebsd/lib/msun/bsdsrc/b_log.c new file mode 100644 index 0000000..5a4b964 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/bsdsrc/b_log.c @@ -0,0 +1,471 @@ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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 University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +/* @(#)log.c 8.2 (Berkeley) 11/30/93 */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <math.h> +#include <errno.h> + +#include "mathimpl.h" + +/* Table-driven natural logarithm. + * + * This code was derived, with minor modifications, from: + * Peter Tang, "Table-Driven Implementation of the + * Logarithm in IEEE Floating-Point arithmetic." ACM Trans. + * Math Software, vol 16. no 4, pp 378-400, Dec 1990). + * + * Calculates log(2^m*F*(1+f/F)), |f/j| <= 1/256, + * where F = j/128 for j an integer in [0, 128]. + * + * log(2^m) = log2_hi*m + log2_tail*m + * since m is an integer, the dominant term is exact. + * m has at most 10 digits (for subnormal numbers), + * and log2_hi has 11 trailing zero bits. + * + * log(F) = logF_hi[j] + logF_lo[j] is in tabular form in log_table.h + * logF_hi[] + 512 is exact. + * + * log(1+f/F) = 2*f/(2*F + f) + 1/12 * (2*f/(2*F + f))**3 + ... + * the leading term is calculated to extra precision in two + * parts, the larger of which adds exactly to the dominant + * m and F terms. + * There are two cases: + * 1. when m, j are non-zero (m | j), use absolute + * precision for the leading term. + * 2. when m = j = 0, |1-x| < 1/256, and log(x) ~= (x-1). + * In this case, use a relative precision of 24 bits. + * (This is done differently in the original paper) + * + * Special cases: + * 0 return signalling -Inf + * neg return signalling NaN + * +Inf return +Inf +*/ + +#define N 128 + +/* Table of log(Fj) = logF_head[j] + logF_tail[j], for Fj = 1+j/128. + * Used for generation of extend precision logarithms. + * The constant 35184372088832 is 2^45, so the divide is exact. + * It ensures correct reading of logF_head, even for inaccurate + * decimal-to-binary conversion routines. (Everybody gets the + * right answer for integers less than 2^53.) + * Values for log(F) were generated using error < 10^-57 absolute + * with the bc -l package. +*/ +static double A1 = .08333333333333178827; +static double A2 = .01250000000377174923; +static double A3 = .002232139987919447809; +static double A4 = .0004348877777076145742; + +static double logF_head[N+1] = { + 0., + .007782140442060381246, + .015504186535963526694, + .023167059281547608406, + .030771658666765233647, + .038318864302141264488, + .045809536031242714670, + .053244514518837604555, + .060624621816486978786, + .067950661908525944454, + .075223421237524235039, + .082443669210988446138, + .089612158689760690322, + .096729626458454731618, + .103796793681567578460, + .110814366340264314203, + .117783035656430001836, + .124703478501032805070, + .131576357788617315236, + .138402322859292326029, + .145182009844575077295, + .151916042025732167530, + .158605030176659056451, + .165249572895390883786, + .171850256926518341060, + .178407657472689606947, + .184922338493834104156, + .191394852999565046047, + .197825743329758552135, + .204215541428766300668, + .210564769107350002741, + .216873938300523150246, + .223143551314024080056, + .229374101064877322642, + .235566071312860003672, + .241719936886966024758, + .247836163904594286577, + .253915209980732470285, + .259957524436686071567, + .265963548496984003577, + .271933715484010463114, + .277868451003087102435, + .283768173130738432519, + .289633292582948342896, + .295464212893421063199, + .301261330578199704177, + .307025035294827830512, + .312755710004239517729, + .318453731118097493890, + .324119468654316733591, + .329753286372579168528, + .335355541920762334484, + .340926586970454081892, + .346466767346100823488, + .351976423156884266063, + .357455888922231679316, + .362905493689140712376, + .368325561158599157352, + .373716409793814818840, + .379078352934811846353, + .384411698910298582632, + .389716751140440464951, + .394993808240542421117, + .400243164127459749579, + .405465108107819105498, + .410659924985338875558, + .415827895143593195825, + .420969294644237379543, + .426084395310681429691, + .431173464818130014464, + .436236766774527495726, + .441274560805140936281, + .446287102628048160113, + .451274644139630254358, + .456237433481874177232, + .461175715122408291790, + .466089729924533457960, + .470979715219073113985, + .475845904869856894947, + .480688529345570714212, + .485507815781602403149, + .490303988045525329653, + .495077266798034543171, + .499827869556611403822, + .504556010751912253908, + .509261901790523552335, + .513945751101346104405, + .518607764208354637958, + .523248143765158602036, + .527867089620485785417, + .532464798869114019908, + .537041465897345915436, + .541597282432121573947, + .546132437597407260909, + .550647117952394182793, + .555141507540611200965, + .559615787935399566777, + .564070138285387656651, + .568504735352689749561, + .572919753562018740922, + .577315365035246941260, + .581691739635061821900, + .586049045003164792433, + .590387446602107957005, + .594707107746216934174, + .599008189645246602594, + .603290851438941899687, + .607555250224322662688, + .611801541106615331955, + .616029877215623855590, + .620240409751204424537, + .624433288012369303032, + .628608659422752680256, + .632766669570628437213, + .636907462236194987781, + .641031179420679109171, + .645137961373620782978, + .649227946625615004450, + .653301272011958644725, + .657358072709030238911, + .661398482245203922502, + .665422632544505177065, + .669430653942981734871, + .673422675212350441142, + .677398823590920073911, + .681359224807238206267, + .685304003098281100392, + .689233281238557538017, + .693147180560117703862 +}; + +static double logF_tail[N+1] = { + 0., + -.00000000000000543229938420049, + .00000000000000172745674997061, + -.00000000000001323017818229233, + -.00000000000001154527628289872, + -.00000000000000466529469958300, + .00000000000005148849572685810, + -.00000000000002532168943117445, + -.00000000000005213620639136504, + -.00000000000001819506003016881, + .00000000000006329065958724544, + .00000000000008614512936087814, + -.00000000000007355770219435028, + .00000000000009638067658552277, + .00000000000007598636597194141, + .00000000000002579999128306990, + -.00000000000004654729747598444, + -.00000000000007556920687451336, + .00000000000010195735223708472, + -.00000000000017319034406422306, + -.00000000000007718001336828098, + .00000000000010980754099855238, + -.00000000000002047235780046195, + -.00000000000008372091099235912, + .00000000000014088127937111135, + .00000000000012869017157588257, + .00000000000017788850778198106, + .00000000000006440856150696891, + .00000000000016132822667240822, + -.00000000000007540916511956188, + -.00000000000000036507188831790, + .00000000000009120937249914984, + .00000000000018567570959796010, + -.00000000000003149265065191483, + -.00000000000009309459495196889, + .00000000000017914338601329117, + -.00000000000001302979717330866, + .00000000000023097385217586939, + .00000000000023999540484211737, + .00000000000015393776174455408, + -.00000000000036870428315837678, + .00000000000036920375082080089, + -.00000000000009383417223663699, + .00000000000009433398189512690, + .00000000000041481318704258568, + -.00000000000003792316480209314, + .00000000000008403156304792424, + -.00000000000034262934348285429, + .00000000000043712191957429145, + -.00000000000010475750058776541, + -.00000000000011118671389559323, + .00000000000037549577257259853, + .00000000000013912841212197565, + .00000000000010775743037572640, + .00000000000029391859187648000, + -.00000000000042790509060060774, + .00000000000022774076114039555, + .00000000000010849569622967912, + -.00000000000023073801945705758, + .00000000000015761203773969435, + .00000000000003345710269544082, + -.00000000000041525158063436123, + .00000000000032655698896907146, + -.00000000000044704265010452446, + .00000000000034527647952039772, + -.00000000000007048962392109746, + .00000000000011776978751369214, + -.00000000000010774341461609578, + .00000000000021863343293215910, + .00000000000024132639491333131, + .00000000000039057462209830700, + -.00000000000026570679203560751, + .00000000000037135141919592021, + -.00000000000017166921336082431, + -.00000000000028658285157914353, + -.00000000000023812542263446809, + .00000000000006576659768580062, + -.00000000000028210143846181267, + .00000000000010701931762114254, + .00000000000018119346366441110, + .00000000000009840465278232627, + -.00000000000033149150282752542, + -.00000000000018302857356041668, + -.00000000000016207400156744949, + .00000000000048303314949553201, + -.00000000000071560553172382115, + .00000000000088821239518571855, + -.00000000000030900580513238244, + -.00000000000061076551972851496, + .00000000000035659969663347830, + .00000000000035782396591276383, + -.00000000000046226087001544578, + .00000000000062279762917225156, + .00000000000072838947272065741, + .00000000000026809646615211673, + -.00000000000010960825046059278, + .00000000000002311949383800537, + -.00000000000058469058005299247, + -.00000000000002103748251144494, + -.00000000000023323182945587408, + -.00000000000042333694288141916, + -.00000000000043933937969737844, + .00000000000041341647073835565, + .00000000000006841763641591466, + .00000000000047585534004430641, + .00000000000083679678674757695, + -.00000000000085763734646658640, + .00000000000021913281229340092, + -.00000000000062242842536431148, + -.00000000000010983594325438430, + .00000000000065310431377633651, + -.00000000000047580199021710769, + -.00000000000037854251265457040, + .00000000000040939233218678664, + .00000000000087424383914858291, + .00000000000025218188456842882, + -.00000000000003608131360422557, + -.00000000000050518555924280902, + .00000000000078699403323355317, + -.00000000000067020876961949060, + .00000000000016108575753932458, + .00000000000058527188436251509, + -.00000000000035246757297904791, + -.00000000000018372084495629058, + .00000000000088606689813494916, + .00000000000066486268071468700, + .00000000000063831615170646519, + .00000000000025144230728376072, + -.00000000000017239444525614834 +}; + +#if 0 +double +#ifdef _ANSI_SOURCE +log(double x) +#else +log(x) double x; +#endif +{ + int m, j; + double F, f, g, q, u, u2, v, zero = 0.0, one = 1.0; + volatile double u1; + + /* Catch special cases */ + if (x <= 0) + if (x == zero) /* log(0) = -Inf */ + return (-one/zero); + else /* log(neg) = NaN */ + return (zero/zero); + else if (!finite(x)) + return (x+x); /* x = NaN, Inf */ + + /* Argument reduction: 1 <= g < 2; x/2^m = g; */ + /* y = F*(1 + f/F) for |f| <= 2^-8 */ + + m = logb(x); + g = ldexp(x, -m); + if (m == -1022) { + j = logb(g), m += j; + g = ldexp(g, -j); + } + j = N*(g-1) + .5; + F = (1.0/N) * j + 1; /* F*128 is an integer in [128, 512] */ + f = g - F; + + /* Approximate expansion for log(1+f/F) ~= u + q */ + g = 1/(2*F+f); + u = 2*f*g; + v = u*u; + q = u*v*(A1 + v*(A2 + v*(A3 + v*A4))); + + /* case 1: u1 = u rounded to 2^-43 absolute. Since u < 2^-8, + * u1 has at most 35 bits, and F*u1 is exact, as F has < 8 bits. + * It also adds exactly to |m*log2_hi + log_F_head[j] | < 750 + */ + if (m | j) + u1 = u + 513, u1 -= 513; + + /* case 2: |1-x| < 1/256. The m- and j- dependent terms are zero; + * u1 = u to 24 bits. + */ + else + u1 = u, TRUNC(u1); + u2 = (2.0*(f - F*u1) - u1*f) * g; + /* u1 + u2 = 2f/(2F+f) to extra precision. */ + + /* log(x) = log(2^m*F*(1+f/F)) = */ + /* (m*log2_hi+logF_head[j]+u1) + (m*log2_lo+logF_tail[j]+q); */ + /* (exact) + (tiny) */ + + u1 += m*logF_head[N] + logF_head[j]; /* exact */ + u2 = (u2 + logF_tail[j]) + q; /* tiny */ + u2 += logF_tail[N]*m; + return (u1 + u2); +} +#endif + +/* + * Extra precision variant, returning struct {double a, b;}; + * log(x) = a+b to 63 bits, with a rounded to 26 bits. + */ +struct Double +#ifdef _ANSI_SOURCE +__log__D(double x) +#else +__log__D(x) double x; +#endif +{ + int m, j; + double F, f, g, q, u, v, u2; + volatile double u1; + struct Double r; + + /* Argument reduction: 1 <= g < 2; x/2^m = g; */ + /* y = F*(1 + f/F) for |f| <= 2^-8 */ + + m = logb(x); + g = ldexp(x, -m); + if (m == -1022) { + j = logb(g), m += j; + g = ldexp(g, -j); + } + j = N*(g-1) + .5; + F = (1.0/N) * j + 1; + f = g - F; + + g = 1/(2*F+f); + u = 2*f*g; + v = u*u; + q = u*v*(A1 + v*(A2 + v*(A3 + v*A4))); + if (m | j) + u1 = u + 513, u1 -= 513; + else + u1 = u, TRUNC(u1); + u2 = (2.0*(f - F*u1) - u1*f) * g; + + u1 += m*logF_head[N] + logF_head[j]; + + u2 += logF_tail[j]; u2 += q; + u2 += logF_tail[N]*m; + r.a = u1 + u2; /* Only difference is here */ + TRUNC(r.a); + r.b = (u1 - r.a) + u2; + return (r); +} diff --git a/libm/upstream-freebsd/lib/msun/bsdsrc/b_tgamma.c b/libm/upstream-freebsd/lib/msun/bsdsrc/b_tgamma.c new file mode 100644 index 0000000..1d0af44 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/bsdsrc/b_tgamma.c @@ -0,0 +1,317 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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 University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +/* @(#)gamma.c 8.1 (Berkeley) 6/4/93 */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * This code by P. McIlroy, Oct 1992; + * + * The financial support of UUNET Communications Services is greatfully + * acknowledged. + */ + +#include <math.h> +#include "mathimpl.h" + +/* METHOD: + * x < 0: Use reflection formula, G(x) = pi/(sin(pi*x)*x*G(x)) + * At negative integers, return NaN and raise invalid. + * + * x < 6.5: + * Use argument reduction G(x+1) = xG(x) to reach the + * range [1.066124,2.066124]. Use a rational + * approximation centered at the minimum (x0+1) to + * ensure monotonicity. + * + * x >= 6.5: Use the asymptotic approximation (Stirling's formula) + * adjusted for equal-ripples: + * + * log(G(x)) ~= (x-.5)*(log(x)-1) + .5(log(2*pi)-1) + 1/x*P(1/(x*x)) + * + * Keep extra precision in multiplying (x-.5)(log(x)-1), to + * avoid premature round-off. + * + * Special values: + * -Inf: return NaN and raise invalid; + * negative integer: return NaN and raise invalid; + * other x ~< 177.79: return +-0 and raise underflow; + * +-0: return +-Inf and raise divide-by-zero; + * finite x ~> 171.63: return +Inf and raise overflow; + * +Inf: return +Inf; + * NaN: return NaN. + * + * Accuracy: tgamma(x) is accurate to within + * x > 0: error provably < 0.9ulp. + * Maximum observed in 1,000,000 trials was .87ulp. + * x < 0: + * Maximum observed error < 4ulp in 1,000,000 trials. + */ + +static double neg_gam(double); +static double small_gam(double); +static double smaller_gam(double); +static struct Double large_gam(double); +static struct Double ratfun_gam(double, double); + +/* + * Rational approximation, A0 + x*x*P(x)/Q(x), on the interval + * [1.066.., 2.066..] accurate to 4.25e-19. + */ +#define LEFT -.3955078125 /* left boundary for rat. approx */ +#define x0 .461632144968362356785 /* xmin - 1 */ + +#define a0_hi 0.88560319441088874992 +#define a0_lo -.00000000000000004996427036469019695 +#define P0 6.21389571821820863029017800727e-01 +#define P1 2.65757198651533466104979197553e-01 +#define P2 5.53859446429917461063308081748e-03 +#define P3 1.38456698304096573887145282811e-03 +#define P4 2.40659950032711365819348969808e-03 +#define Q0 1.45019531250000000000000000000e+00 +#define Q1 1.06258521948016171343454061571e+00 +#define Q2 -2.07474561943859936441469926649e-01 +#define Q3 -1.46734131782005422506287573015e-01 +#define Q4 3.07878176156175520361557573779e-02 +#define Q5 5.12449347980666221336054633184e-03 +#define Q6 -1.76012741431666995019222898833e-03 +#define Q7 9.35021023573788935372153030556e-05 +#define Q8 6.13275507472443958924745652239e-06 +/* + * Constants for large x approximation (x in [6, Inf]) + * (Accurate to 2.8*10^-19 absolute) + */ +#define lns2pi_hi 0.418945312500000 +#define lns2pi_lo -.000006779295327258219670263595 +#define Pa0 8.33333333333333148296162562474e-02 +#define Pa1 -2.77777777774548123579378966497e-03 +#define Pa2 7.93650778754435631476282786423e-04 +#define Pa3 -5.95235082566672847950717262222e-04 +#define Pa4 8.41428560346653702135821806252e-04 +#define Pa5 -1.89773526463879200348872089421e-03 +#define Pa6 5.69394463439411649408050664078e-03 +#define Pa7 -1.44705562421428915453880392761e-02 + +static const double zero = 0., one = 1.0, tiny = 1e-300; + +double +tgamma(x) + double x; +{ + struct Double u; + + if (x >= 6) { + if(x > 171.63) + return (x / zero); + u = large_gam(x); + return(__exp__D(u.a, u.b)); + } else if (x >= 1.0 + LEFT + x0) + return (small_gam(x)); + else if (x > 1.e-17) + return (smaller_gam(x)); + else if (x > -1.e-17) { + if (x != 0.0) + u.a = one - tiny; /* raise inexact */ + return (one/x); + } else if (!finite(x)) + return (x - x); /* x is NaN or -Inf */ + else + return (neg_gam(x)); +} +/* + * Accurate to max(ulp(1/128) absolute, 2^-66 relative) error. + */ +static struct Double +large_gam(x) + double x; +{ + double z, p; + struct Double t, u, v; + + z = one/(x*x); + p = Pa0+z*(Pa1+z*(Pa2+z*(Pa3+z*(Pa4+z*(Pa5+z*(Pa6+z*Pa7)))))); + p = p/x; + + u = __log__D(x); + u.a -= one; + v.a = (x -= .5); + TRUNC(v.a); + v.b = x - v.a; + t.a = v.a*u.a; /* t = (x-.5)*(log(x)-1) */ + t.b = v.b*u.a + x*u.b; + /* return t.a + t.b + lns2pi_hi + lns2pi_lo + p */ + t.b += lns2pi_lo; t.b += p; + u.a = lns2pi_hi + t.b; u.a += t.a; + u.b = t.a - u.a; + u.b += lns2pi_hi; u.b += t.b; + return (u); +} +/* + * Good to < 1 ulp. (provably .90 ulp; .87 ulp on 1,000,000 runs.) + * It also has correct monotonicity. + */ +static double +small_gam(x) + double x; +{ + double y, ym1, t; + struct Double yy, r; + y = x - one; + ym1 = y - one; + if (y <= 1.0 + (LEFT + x0)) { + yy = ratfun_gam(y - x0, 0); + return (yy.a + yy.b); + } + r.a = y; + TRUNC(r.a); + yy.a = r.a - one; + y = ym1; + yy.b = r.b = y - yy.a; + /* Argument reduction: G(x+1) = x*G(x) */ + for (ym1 = y-one; ym1 > LEFT + x0; y = ym1--, yy.a--) { + t = r.a*yy.a; + r.b = r.a*yy.b + y*r.b; + r.a = t; + TRUNC(r.a); + r.b += (t - r.a); + } + /* Return r*tgamma(y). */ + yy = ratfun_gam(y - x0, 0); + y = r.b*(yy.a + yy.b) + r.a*yy.b; + y += yy.a*r.a; + return (y); +} +/* + * Good on (0, 1+x0+LEFT]. Accurate to 1ulp. + */ +static double +smaller_gam(x) + double x; +{ + double t, d; + struct Double r, xx; + if (x < x0 + LEFT) { + t = x, TRUNC(t); + d = (t+x)*(x-t); + t *= t; + xx.a = (t + x), TRUNC(xx.a); + xx.b = x - xx.a; xx.b += t; xx.b += d; + t = (one-x0); t += x; + d = (one-x0); d -= t; d += x; + x = xx.a + xx.b; + } else { + xx.a = x, TRUNC(xx.a); + xx.b = x - xx.a; + t = x - x0; + d = (-x0 -t); d += x; + } + r = ratfun_gam(t, d); + d = r.a/x, TRUNC(d); + r.a -= d*xx.a; r.a -= d*xx.b; r.a += r.b; + return (d + r.a/x); +} +/* + * returns (z+c)^2 * P(z)/Q(z) + a0 + */ +static struct Double +ratfun_gam(z, c) + double z, c; +{ + double p, q; + struct Double r, t; + + q = Q0 +z*(Q1+z*(Q2+z*(Q3+z*(Q4+z*(Q5+z*(Q6+z*(Q7+z*Q8))))))); + p = P0 + z*(P1 + z*(P2 + z*(P3 + z*P4))); + + /* return r.a + r.b = a0 + (z+c)^2*p/q, with r.a truncated to 26 bits. */ + p = p/q; + t.a = z, TRUNC(t.a); /* t ~= z + c */ + t.b = (z - t.a) + c; + t.b *= (t.a + z); + q = (t.a *= t.a); /* t = (z+c)^2 */ + TRUNC(t.a); + t.b += (q - t.a); + r.a = p, TRUNC(r.a); /* r = P/Q */ + r.b = p - r.a; + t.b = t.b*p + t.a*r.b + a0_lo; + t.a *= r.a; /* t = (z+c)^2*(P/Q) */ + r.a = t.a + a0_hi, TRUNC(r.a); + r.b = ((a0_hi-r.a) + t.a) + t.b; + return (r); /* r = a0 + t */ +} + +static double +neg_gam(x) + double x; +{ + int sgn = 1; + struct Double lg, lsine; + double y, z; + + y = ceil(x); + if (y == x) /* Negative integer. */ + return ((x - x) / zero); + z = y - x; + if (z > 0.5) + z = one - z; + y = 0.5 * y; + if (y == ceil(y)) + sgn = -1; + if (z < .25) + z = sin(M_PI*z); + else + z = cos(M_PI*(0.5-z)); + /* Special case: G(1-x) = Inf; G(x) may be nonzero. */ + if (x < -170) { + if (x < -190) + return ((double)sgn*tiny*tiny); + y = one - x; /* exact: 128 < |x| < 255 */ + lg = large_gam(y); + lsine = __log__D(M_PI/z); /* = TRUNC(log(u)) + small */ + lg.a -= lsine.a; /* exact (opposite signs) */ + lg.b -= lsine.b; + y = -(lg.a + lg.b); + z = (y + lg.a) + lg.b; + y = __exp__D(y, z); + if (sgn < 0) y = -y; + return (y); + } + y = one-x; + if (one-y == x) + y = tgamma(y); + else /* 1-x is inexact */ + y = -x*tgamma(-x); + if (sgn < 0) y = -y; + return (M_PI / (y*z)); +} diff --git a/libm/upstream-freebsd/lib/msun/bsdsrc/mathimpl.h b/libm/upstream-freebsd/lib/msun/bsdsrc/mathimpl.h new file mode 100644 index 0000000..04a4b6e --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/bsdsrc/mathimpl.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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 University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)mathimpl.h 8.1 (Berkeley) 6/4/93 + * $FreeBSD$ + */ + +#ifndef _MATHIMPL_H_ +#define _MATHIMPL_H_ + +#include <sys/cdefs.h> +#include <math.h> + +#include "../src/math_private.h" + +/* + * TRUNC() is a macro that sets the trailing 27 bits in the mantissa of an + * IEEE double variable to zero. It must be expression-like for syntactic + * reasons, and we implement this expression using an inline function + * instead of a pure macro to avoid depending on the gcc feature of + * statement-expressions. + */ +#define TRUNC(d) (_b_trunc(&(d))) + +static __inline void +_b_trunc(volatile double *_dp) +{ + uint32_t _lw; + + GET_LOW_WORD(_lw, *_dp); + SET_LOW_WORD(*_dp, _lw & 0xf8000000); +} + +struct Double { + double a; + double b; +}; + +/* + * Functions internal to the math package, yet not static. + */ +double __exp__D(double, double); +struct Double __log__D(double); + +#endif /* !_MATHIMPL_H_ */ diff --git a/libm/upstream-freebsd/lib/msun/src/e_acos.c b/libm/upstream-freebsd/lib/msun/src/e_acos.c new file mode 100644 index 0000000..1f6dca5 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_acos.c @@ -0,0 +1,111 @@ + +/* @(#)e_acos.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* __ieee754_acos(x) + * Method : + * acos(x) = pi/2 - asin(x) + * acos(-x) = pi/2 + asin(x) + * For |x|<=0.5 + * acos(x) = pi/2 - (x + x*x^2*R(x^2)) (see asin.c) + * For x>0.5 + * acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2))) + * = 2asin(sqrt((1-x)/2)) + * = 2s + 2s*z*R(z) ...z=(1-x)/2, s=sqrt(z) + * = 2f + (2c + 2s*z*R(z)) + * where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term + * for f so that f+c ~ sqrt(z). + * For x<-0.5 + * acos(x) = pi - 2asin(sqrt((1-|x|)/2)) + * = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z) + * + * Special cases: + * if x is NaN, return x itself; + * if |x|>1, return NaN with invalid signal. + * + * Function needed: sqrt + */ + +#include <float.h> + +#include "math.h" +#include "math_private.h" + +static const double +one= 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */ +pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */ +pio2_hi = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */ +static volatile double +pio2_lo = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */ +static const double +pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */ +pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */ +pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */ +pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */ +pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */ +pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */ +qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */ +qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */ +qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */ +qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +double +__ieee754_acos(double x) +{ + double z,p,q,r,w,s,c,df; + int32_t hx,ix; + GET_HIGH_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x3ff00000) { /* |x| >= 1 */ + u_int32_t lx; + GET_LOW_WORD(lx,x); + if(((ix-0x3ff00000)|lx)==0) { /* |x|==1 */ + if(hx>0) return 0.0; /* acos(1) = 0 */ + else return pi+2.0*pio2_lo; /* acos(-1)= pi */ + } + return (x-x)/(x-x); /* acos(|x|>1) is NaN */ + } + if(ix<0x3fe00000) { /* |x| < 0.5 */ + if(ix<=0x3c600000) return pio2_hi+pio2_lo;/*if|x|<2**-57*/ + z = x*x; + p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5))))); + q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4))); + r = p/q; + return pio2_hi - (x - (pio2_lo-x*r)); + } else if (hx<0) { /* x < -0.5 */ + z = (one+x)*0.5; + p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5))))); + q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4))); + s = sqrt(z); + r = p/q; + w = r*s-pio2_lo; + return pi - 2.0*(s+w); + } else { /* x > 0.5 */ + z = (one-x)*0.5; + s = sqrt(z); + df = s; + SET_LOW_WORD(df,0); + c = (z-df*df)/(s+df); + p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5))))); + q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4))); + r = p/q; + w = r*s+c; + return 2.0*(df+w); + } +} + +#if LDBL_MANT_DIG == 53 +__weak_reference(acos, acosl); +#endif diff --git a/libm/upstream-freebsd/lib/msun/src/e_acosf.c b/libm/upstream-freebsd/lib/msun/src/e_acosf.c new file mode 100644 index 0000000..c9f62cc --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_acosf.c @@ -0,0 +1,77 @@ +/* e_acosf.c -- float version of e_acos.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +static const float +one = 1.0000000000e+00, /* 0x3F800000 */ +pi = 3.1415925026e+00, /* 0x40490fda */ +pio2_hi = 1.5707962513e+00; /* 0x3fc90fda */ +static volatile float +pio2_lo = 7.5497894159e-08; /* 0x33a22168 */ +static const float +pS0 = 1.6666586697e-01, +pS1 = -4.2743422091e-02, +pS2 = -8.6563630030e-03, +qS1 = -7.0662963390e-01; + +float +__ieee754_acosf(float x) +{ + float z,p,q,r,w,s,c,df; + int32_t hx,ix; + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x3f800000) { /* |x| >= 1 */ + if(ix==0x3f800000) { /* |x| == 1 */ + if(hx>0) return 0.0; /* acos(1) = 0 */ + else return pi+(float)2.0*pio2_lo; /* acos(-1)= pi */ + } + return (x-x)/(x-x); /* acos(|x|>1) is NaN */ + } + if(ix<0x3f000000) { /* |x| < 0.5 */ + if(ix<=0x32800000) return pio2_hi+pio2_lo;/*if|x|<2**-26*/ + z = x*x; + p = z*(pS0+z*(pS1+z*pS2)); + q = one+z*qS1; + r = p/q; + return pio2_hi - (x - (pio2_lo-x*r)); + } else if (hx<0) { /* x < -0.5 */ + z = (one+x)*(float)0.5; + p = z*(pS0+z*(pS1+z*pS2)); + q = one+z*qS1; + s = sqrtf(z); + r = p/q; + w = r*s-pio2_lo; + return pi - (float)2.0*(s+w); + } else { /* x > 0.5 */ + int32_t idf; + z = (one-x)*(float)0.5; + s = sqrtf(z); + df = s; + GET_FLOAT_WORD(idf,df); + SET_FLOAT_WORD(df,idf&0xfffff000); + c = (z-df*df)/(s+df); + p = z*(pS0+z*(pS1+z*pS2)); + q = one+z*qS1; + r = p/q; + w = r*s+c; + return (float)2.0*(df+w); + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_acosh.c b/libm/upstream-freebsd/lib/msun/src/e_acosh.c new file mode 100644 index 0000000..a0cc6cb --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_acosh.c @@ -0,0 +1,62 @@ + +/* @(#)e_acosh.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* __ieee754_acosh(x) + * Method : + * Based on + * acosh(x) = log [ x + sqrt(x*x-1) ] + * we have + * acosh(x) := log(x)+ln2, if x is large; else + * acosh(x) := log(2x-1/(sqrt(x*x-1)+x)) if x>2; else + * acosh(x) := log1p(t+sqrt(2.0*t+t*t)); where t=x-1. + * + * Special cases: + * acosh(x) is NaN with signal if x<1. + * acosh(NaN) is NaN without signal. + */ + +#include "math.h" +#include "math_private.h" + +static const double +one = 1.0, +ln2 = 6.93147180559945286227e-01; /* 0x3FE62E42, 0xFEFA39EF */ + +double +__ieee754_acosh(double x) +{ + double t; + int32_t hx; + u_int32_t lx; + EXTRACT_WORDS(hx,lx,x); + if(hx<0x3ff00000) { /* x < 1 */ + return (x-x)/(x-x); + } else if(hx >=0x41b00000) { /* x > 2**28 */ + if(hx >=0x7ff00000) { /* x is inf of NaN */ + return x+x; + } else + return __ieee754_log(x)+ln2; /* acosh(huge)=log(2x) */ + } else if(((hx-0x3ff00000)|lx)==0) { + return 0.0; /* acosh(1) = 0 */ + } else if (hx > 0x40000000) { /* 2**28 > x > 2 */ + t=x*x; + return __ieee754_log(2.0*x-one/(x+sqrt(t-one))); + } else { /* 1<x<2 */ + t = x-one; + return log1p(t+sqrt(2.0*t+t*t)); + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_acoshf.c b/libm/upstream-freebsd/lib/msun/src/e_acoshf.c new file mode 100644 index 0000000..f529b20 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_acoshf.c @@ -0,0 +1,48 @@ +/* e_acoshf.c -- float version of e_acosh.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +static const float +one = 1.0, +ln2 = 6.9314718246e-01; /* 0x3f317218 */ + +float +__ieee754_acoshf(float x) +{ + float t; + int32_t hx; + GET_FLOAT_WORD(hx,x); + if(hx<0x3f800000) { /* x < 1 */ + return (x-x)/(x-x); + } else if(hx >=0x4d800000) { /* x > 2**28 */ + if(hx >=0x7f800000) { /* x is inf of NaN */ + return x+x; + } else + return __ieee754_logf(x)+ln2; /* acosh(huge)=log(2x) */ + } else if (hx==0x3f800000) { + return 0.0; /* acosh(1) = 0 */ + } else if (hx > 0x40000000) { /* 2**28 > x > 2 */ + t=x*x; + return __ieee754_logf((float)2.0*x-one/(x+__ieee754_sqrtf(t-one))); + } else { /* 1<x<2 */ + t = x-one; + return log1pf(t+__ieee754_sqrtf((float)2.0*t+t*t)); + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_acosl.c b/libm/upstream-freebsd/lib/msun/src/e_acosl.c new file mode 100644 index 0000000..d33c8fe --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_acosl.c @@ -0,0 +1,87 @@ + +/* @(#)e_acos.c 1.3 95/01/18 */ +/* FreeBSD: head/lib/msun/src/e_acos.c 176451 2008-02-22 02:30:36Z das */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * See comments in e_acos.c. + * Converted to long double by David Schultz <das@FreeBSD.ORG>. + */ + +#include <float.h> + +#include "invtrig.h" +#include "math.h" +#include "math_private.h" + +static const long double +one= 1.00000000000000000000e+00; + +#ifdef __i386__ +/* XXX Work around the fact that gcc truncates long double constants on i386 */ +static volatile double +pi1 = 3.14159265358979311600e+00, /* 0x1.921fb54442d18p+1 */ +pi2 = 1.22514845490862001043e-16; /* 0x1.1a80000000000p-53 */ +#define pi ((long double)pi1 + pi2) +#else +static const long double +pi = 3.14159265358979323846264338327950280e+00L; +#endif + +long double +acosl(long double x) +{ + union IEEEl2bits u; + long double z,p,q,r,w,s,c,df; + int16_t expsign, expt; + u.e = x; + expsign = u.xbits.expsign; + expt = expsign & 0x7fff; + if(expt >= BIAS) { /* |x| >= 1 */ + if(expt==BIAS && ((u.bits.manh&~LDBL_NBIT)|u.bits.manl)==0) { + if (expsign>0) return 0.0; /* acos(1) = 0 */ + else return pi+2.0*pio2_lo; /* acos(-1)= pi */ + } + return (x-x)/(x-x); /* acos(|x|>1) is NaN */ + } + if(expt<BIAS-1) { /* |x| < 0.5 */ + if(expt<ACOS_CONST) return pio2_hi+pio2_lo;/*x tiny: acosl=pi/2*/ + z = x*x; + p = P(z); + q = Q(z); + r = p/q; + return pio2_hi - (x - (pio2_lo-x*r)); + } else if (expsign<0) { /* x < -0.5 */ + z = (one+x)*0.5; + p = P(z); + q = Q(z); + s = sqrtl(z); + r = p/q; + w = r*s-pio2_lo; + return pi - 2.0*(s+w); + } else { /* x > 0.5 */ + z = (one-x)*0.5; + s = sqrtl(z); + u.e = s; + u.bits.manl = 0; + df = u.e; + c = (z-df*df)/(s+df); + p = P(z); + q = Q(z); + r = p/q; + w = r*s+c; + return 2.0*(df+w); + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_asin.c b/libm/upstream-freebsd/lib/msun/src/e_asin.c new file mode 100644 index 0000000..27de207 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_asin.c @@ -0,0 +1,117 @@ + +/* @(#)e_asin.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* __ieee754_asin(x) + * Method : + * Since asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ... + * we approximate asin(x) on [0,0.5] by + * asin(x) = x + x*x^2*R(x^2) + * where + * R(x^2) is a rational approximation of (asin(x)-x)/x^3 + * and its remez error is bounded by + * |(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75) + * + * For x in [0.5,1] + * asin(x) = pi/2-2*asin(sqrt((1-x)/2)) + * Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2; + * then for x>0.98 + * asin(x) = pi/2 - 2*(s+s*z*R(z)) + * = pio2_hi - (2*(s+s*z*R(z)) - pio2_lo) + * For x<=0.98, let pio4_hi = pio2_hi/2, then + * f = hi part of s; + * c = sqrt(z) - f = (z-f*f)/(s+f) ...f+c=sqrt(z) + * and + * asin(x) = pi/2 - 2*(s+s*z*R(z)) + * = pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo) + * = pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c)) + * + * Special cases: + * if x is NaN, return x itself; + * if |x|>1, return NaN with invalid signal. + * + */ + +#include <float.h> + +#include "math.h" +#include "math_private.h" + +static const double +one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */ +huge = 1.000e+300, +pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */ +pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */ +pio4_hi = 7.85398163397448278999e-01, /* 0x3FE921FB, 0x54442D18 */ + /* coefficient for R(x^2) */ +pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */ +pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */ +pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */ +pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */ +pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */ +pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */ +qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */ +qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */ +qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */ +qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +double +__ieee754_asin(double x) +{ + double t=0.0,w,p,q,c,r,s; + int32_t hx,ix; + GET_HIGH_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>= 0x3ff00000) { /* |x|>= 1 */ + u_int32_t lx; + GET_LOW_WORD(lx,x); + if(((ix-0x3ff00000)|lx)==0) + /* asin(1)=+-pi/2 with inexact */ + return x*pio2_hi+x*pio2_lo; + return (x-x)/(x-x); /* asin(|x|>1) is NaN */ + } else if (ix<0x3fe00000) { /* |x|<0.5 */ + if(ix<0x3e500000) { /* if |x| < 2**-26 */ + if(huge+x>one) return x;/* return x with inexact if x!=0*/ + } + t = x*x; + p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5))))); + q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4))); + w = p/q; + return x+x*w; + } + /* 1> |x|>= 0.5 */ + w = one-fabs(x); + t = w*0.5; + p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5))))); + q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4))); + s = sqrt(t); + if(ix>=0x3FEF3333) { /* if |x| > 0.975 */ + w = p/q; + t = pio2_hi-(2.0*(s+s*w)-pio2_lo); + } else { + w = s; + SET_LOW_WORD(w,0); + c = (t-w*w)/(s+w); + r = p/q; + p = 2.0*s*r-(pio2_lo-2.0*c); + q = pio4_hi-2.0*w; + t = pio4_hi-(p-q); + } + if(hx>0) return t; else return -t; +} + +#if LDBL_MANT_DIG == 53 +__weak_reference(asin, asinl); +#endif diff --git a/libm/upstream-freebsd/lib/msun/src/e_asinf.c b/libm/upstream-freebsd/lib/msun/src/e_asinf.c new file mode 100644 index 0000000..deaabb6 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_asinf.c @@ -0,0 +1,65 @@ +/* e_asinf.c -- float version of e_asin.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +static const float +one = 1.0000000000e+00, /* 0x3F800000 */ +huge = 1.000e+30, + /* coefficient for R(x^2) */ +pS0 = 1.6666586697e-01, +pS1 = -4.2743422091e-02, +pS2 = -8.6563630030e-03, +qS1 = -7.0662963390e-01; + +static const double +pio2 = 1.570796326794896558e+00; + +float +__ieee754_asinf(float x) +{ + double s; + float t,w,p,q; + int32_t hx,ix; + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x3f800000) { /* |x| >= 1 */ + if(ix==0x3f800000) /* |x| == 1 */ + return x*pio2; /* asin(+-1) = +-pi/2 with inexact */ + return (x-x)/(x-x); /* asin(|x|>1) is NaN */ + } else if (ix<0x3f000000) { /* |x|<0.5 */ + if(ix<0x39800000) { /* |x| < 2**-12 */ + if(huge+x>one) return x;/* return x with inexact if x!=0*/ + } + t = x*x; + p = t*(pS0+t*(pS1+t*pS2)); + q = one+t*qS1; + w = p/q; + return x+x*w; + } + /* 1> |x|>= 0.5 */ + w = one-fabsf(x); + t = w*(float)0.5; + p = t*(pS0+t*(pS1+t*pS2)); + q = one+t*qS1; + s = sqrt(t); + w = p/q; + t = pio2-2.0*(s+s*w); + if(hx>0) return t; else return -t; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_asinl.c b/libm/upstream-freebsd/lib/msun/src/e_asinl.c new file mode 100644 index 0000000..a85765f --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_asinl.c @@ -0,0 +1,77 @@ + +/* @(#)e_asin.c 1.3 95/01/18 */ +/* FreeBSD: head/lib/msun/src/e_asin.c 176451 2008-02-22 02:30:36Z das */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * See comments in e_asin.c. + * Converted to long double by David Schultz <das@FreeBSD.ORG>. + */ + +#include <float.h> + +#include "invtrig.h" +#include "math.h" +#include "math_private.h" + +static const long double +one = 1.00000000000000000000e+00, +huge = 1.000e+300; + +long double +asinl(long double x) +{ + union IEEEl2bits u; + long double t=0.0,w,p,q,c,r,s; + int16_t expsign, expt; + u.e = x; + expsign = u.xbits.expsign; + expt = expsign & 0x7fff; + if(expt >= BIAS) { /* |x|>= 1 */ + if(expt==BIAS && ((u.bits.manh&~LDBL_NBIT)|u.bits.manl)==0) + /* asin(1)=+-pi/2 with inexact */ + return x*pio2_hi+x*pio2_lo; + return (x-x)/(x-x); /* asin(|x|>1) is NaN */ + } else if (expt<BIAS-1) { /* |x|<0.5 */ + if(expt<ASIN_LINEAR) { /* if |x| is small, asinl(x)=x */ + if(huge+x>one) return x;/* return x with inexact if x!=0*/ + } + t = x*x; + p = P(t); + q = Q(t); + w = p/q; + return x+x*w; + } + /* 1> |x|>= 0.5 */ + w = one-fabsl(x); + t = w*0.5; + p = P(t); + q = Q(t); + s = sqrtl(t); + if(u.bits.manh>=THRESH) { /* if |x| is close to 1 */ + w = p/q; + t = pio2_hi-(2.0*(s+s*w)-pio2_lo); + } else { + u.e = s; + u.bits.manl = 0; + w = u.e; + c = (t-w*w)/(s+w); + r = p/q; + p = 2.0*s*r-(pio2_lo-2.0*c); + q = pio4_hi-2.0*w; + t = pio4_hi-(p-q); + } + if(expsign>0) return t; else return -t; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_atan2.c b/libm/upstream-freebsd/lib/msun/src/e_atan2.c new file mode 100644 index 0000000..a4a985b --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_atan2.c @@ -0,0 +1,129 @@ + +/* @(#)e_atan2.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* __ieee754_atan2(y,x) + * Method : + * 1. Reduce y to positive by atan2(y,x)=-atan2(-y,x). + * 2. Reduce x to positive by (if x and y are unexceptional): + * ARG (x+iy) = arctan(y/x) ... if x > 0, + * ARG (x+iy) = pi - arctan[y/(-x)] ... if x < 0, + * + * Special cases: + * + * ATAN2((anything), NaN ) is NaN; + * ATAN2(NAN , (anything) ) is NaN; + * ATAN2(+-0, +(anything but NaN)) is +-0 ; + * ATAN2(+-0, -(anything but NaN)) is +-pi ; + * ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2; + * ATAN2(+-(anything but INF and NaN), +INF) is +-0 ; + * ATAN2(+-(anything but INF and NaN), -INF) is +-pi; + * ATAN2(+-INF,+INF ) is +-pi/4 ; + * ATAN2(+-INF,-INF ) is +-3pi/4; + * ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2; + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include <float.h> + +#include "math.h" +#include "math_private.h" + +static volatile double +tiny = 1.0e-300; +static const double +zero = 0.0, +pi_o_4 = 7.8539816339744827900E-01, /* 0x3FE921FB, 0x54442D18 */ +pi_o_2 = 1.5707963267948965580E+00, /* 0x3FF921FB, 0x54442D18 */ +pi = 3.1415926535897931160E+00; /* 0x400921FB, 0x54442D18 */ +static volatile double +pi_lo = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ + +double +__ieee754_atan2(double y, double x) +{ + double z; + int32_t k,m,hx,hy,ix,iy; + u_int32_t lx,ly; + + EXTRACT_WORDS(hx,lx,x); + ix = hx&0x7fffffff; + EXTRACT_WORDS(hy,ly,y); + iy = hy&0x7fffffff; + if(((ix|((lx|-lx)>>31))>0x7ff00000)|| + ((iy|((ly|-ly)>>31))>0x7ff00000)) /* x or y is NaN */ + return x+y; + if((hx-0x3ff00000|lx)==0) return atan(y); /* x=1.0 */ + m = ((hy>>31)&1)|((hx>>30)&2); /* 2*sign(x)+sign(y) */ + + /* when y = 0 */ + if((iy|ly)==0) { + switch(m) { + case 0: + case 1: return y; /* atan(+-0,+anything)=+-0 */ + case 2: return pi+tiny;/* atan(+0,-anything) = pi */ + case 3: return -pi-tiny;/* atan(-0,-anything) =-pi */ + } + } + /* when x = 0 */ + if((ix|lx)==0) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny; + + /* when x is INF */ + if(ix==0x7ff00000) { + if(iy==0x7ff00000) { + switch(m) { + case 0: return pi_o_4+tiny;/* atan(+INF,+INF) */ + case 1: return -pi_o_4-tiny;/* atan(-INF,+INF) */ + case 2: return 3.0*pi_o_4+tiny;/*atan(+INF,-INF)*/ + case 3: return -3.0*pi_o_4-tiny;/*atan(-INF,-INF)*/ + } + } else { + switch(m) { + case 0: return zero ; /* atan(+...,+INF) */ + case 1: return -zero ; /* atan(-...,+INF) */ + case 2: return pi+tiny ; /* atan(+...,-INF) */ + case 3: return -pi-tiny ; /* atan(-...,-INF) */ + } + } + } + /* when y is INF */ + if(iy==0x7ff00000) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny; + + /* compute y/x */ + k = (iy-ix)>>20; + if(k > 60) { /* |y/x| > 2**60 */ + z=pi_o_2+0.5*pi_lo; + m&=1; + } + else if(hx<0&&k<-60) z=0.0; /* 0 > |y|/x > -2**-60 */ + else z=atan(fabs(y/x)); /* safe to do y/x */ + switch (m) { + case 0: return z ; /* atan(+,+) */ + case 1: return -z ; /* atan(-,+) */ + case 2: return pi-(z-pi_lo);/* atan(+,-) */ + default: /* case 3 */ + return (z-pi_lo)-pi;/* atan(-,-) */ + } +} + +#if LDBL_MANT_DIG == 53 +__weak_reference(atan2, atan2l); +#endif diff --git a/libm/upstream-freebsd/lib/msun/src/e_atan2f.c b/libm/upstream-freebsd/lib/msun/src/e_atan2f.c new file mode 100644 index 0000000..fc77bff --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_atan2f.c @@ -0,0 +1,96 @@ +/* e_atan2f.c -- float version of e_atan2.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +static volatile float +tiny = 1.0e-30; +static const float +zero = 0.0, +pi_o_4 = 7.8539818525e-01, /* 0x3f490fdb */ +pi_o_2 = 1.5707963705e+00, /* 0x3fc90fdb */ +pi = 3.1415927410e+00; /* 0x40490fdb */ +static volatile float +pi_lo = -8.7422776573e-08; /* 0xb3bbbd2e */ + +float +__ieee754_atan2f(float y, float x) +{ + float z; + int32_t k,m,hx,hy,ix,iy; + + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + GET_FLOAT_WORD(hy,y); + iy = hy&0x7fffffff; + if((ix>0x7f800000)|| + (iy>0x7f800000)) /* x or y is NaN */ + return x+y; + if(hx==0x3f800000) return atanf(y); /* x=1.0 */ + m = ((hy>>31)&1)|((hx>>30)&2); /* 2*sign(x)+sign(y) */ + + /* when y = 0 */ + if(iy==0) { + switch(m) { + case 0: + case 1: return y; /* atan(+-0,+anything)=+-0 */ + case 2: return pi+tiny;/* atan(+0,-anything) = pi */ + case 3: return -pi-tiny;/* atan(-0,-anything) =-pi */ + } + } + /* when x = 0 */ + if(ix==0) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny; + + /* when x is INF */ + if(ix==0x7f800000) { + if(iy==0x7f800000) { + switch(m) { + case 0: return pi_o_4+tiny;/* atan(+INF,+INF) */ + case 1: return -pi_o_4-tiny;/* atan(-INF,+INF) */ + case 2: return (float)3.0*pi_o_4+tiny;/*atan(+INF,-INF)*/ + case 3: return (float)-3.0*pi_o_4-tiny;/*atan(-INF,-INF)*/ + } + } else { + switch(m) { + case 0: return zero ; /* atan(+...,+INF) */ + case 1: return -zero ; /* atan(-...,+INF) */ + case 2: return pi+tiny ; /* atan(+...,-INF) */ + case 3: return -pi-tiny ; /* atan(-...,-INF) */ + } + } + } + /* when y is INF */ + if(iy==0x7f800000) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny; + + /* compute y/x */ + k = (iy-ix)>>23; + if(k > 26) { /* |y/x| > 2**26 */ + z=pi_o_2+(float)0.5*pi_lo; + m&=1; + } + else if(k<-26&&hx<0) z=0.0; /* 0 > |y|/x > -2**-26 */ + else z=atanf(fabsf(y/x)); /* safe to do y/x */ + switch (m) { + case 0: return z ; /* atan(+,+) */ + case 1: return -z ; /* atan(-,+) */ + case 2: return pi-(z-pi_lo);/* atan(+,-) */ + default: /* case 3 */ + return (z-pi_lo)-pi;/* atan(-,-) */ + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_atan2l.c b/libm/upstream-freebsd/lib/msun/src/e_atan2l.c new file mode 100644 index 0000000..0326482 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_atan2l.c @@ -0,0 +1,120 @@ + +/* @(#)e_atan2.c 1.3 95/01/18 */ +/* FreeBSD: head/lib/msun/src/e_atan2.c 176451 2008-02-22 02:30:36Z das */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * See comments in e_atan2.c. + * Converted to long double by David Schultz <das@FreeBSD.ORG>. + */ + +#include <float.h> + +#include "invtrig.h" +#include "math.h" +#include "math_private.h" + +static volatile long double +tiny = 1.0e-300; +static const long double +zero = 0.0; + +#ifdef __i386__ +/* XXX Work around the fact that gcc truncates long double constants on i386 */ +static volatile double +pi1 = 3.14159265358979311600e+00, /* 0x1.921fb54442d18p+1 */ +pi2 = 1.22514845490862001043e-16; /* 0x1.1a80000000000p-53 */ +#define pi ((long double)pi1 + pi2) +#else +static const long double +pi = 3.14159265358979323846264338327950280e+00L; +#endif + +long double +atan2l(long double y, long double x) +{ + union IEEEl2bits ux, uy; + long double z; + int32_t k,m; + int16_t exptx, expsignx, expty, expsigny; + + uy.e = y; + expsigny = uy.xbits.expsign; + expty = expsigny & 0x7fff; + ux.e = x; + expsignx = ux.xbits.expsign; + exptx = expsignx & 0x7fff; + + if ((exptx==BIAS+LDBL_MAX_EXP && + ((ux.bits.manh&~LDBL_NBIT)|ux.bits.manl)!=0) || /* x is NaN */ + (expty==BIAS+LDBL_MAX_EXP && + ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl)!=0)) /* y is NaN */ + return x+y; + if (expsignx==BIAS && ((ux.bits.manh&~LDBL_NBIT)|ux.bits.manl)==0) + return atanl(y); /* x=1.0 */ + m = ((expsigny>>15)&1)|((expsignx>>14)&2); /* 2*sign(x)+sign(y) */ + + /* when y = 0 */ + if(expty==0 && ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl)==0) { + switch(m) { + case 0: + case 1: return y; /* atan(+-0,+anything)=+-0 */ + case 2: return pi+tiny;/* atan(+0,-anything) = pi */ + case 3: return -pi-tiny;/* atan(-0,-anything) =-pi */ + } + } + /* when x = 0 */ + if(exptx==0 && ((ux.bits.manh&~LDBL_NBIT)|ux.bits.manl)==0) + return (expsigny<0)? -pio2_hi-tiny: pio2_hi+tiny; + + /* when x is INF */ + if(exptx==BIAS+LDBL_MAX_EXP) { + if(expty==BIAS+LDBL_MAX_EXP) { + switch(m) { + case 0: return pio2_hi*0.5+tiny;/* atan(+INF,+INF) */ + case 1: return -pio2_hi*0.5-tiny;/* atan(-INF,+INF) */ + case 2: return 1.5*pio2_hi+tiny;/*atan(+INF,-INF)*/ + case 3: return -1.5*pio2_hi-tiny;/*atan(-INF,-INF)*/ + } + } else { + switch(m) { + case 0: return zero ; /* atan(+...,+INF) */ + case 1: return -zero ; /* atan(-...,+INF) */ + case 2: return pi+tiny ; /* atan(+...,-INF) */ + case 3: return -pi-tiny ; /* atan(-...,-INF) */ + } + } + } + /* when y is INF */ + if(expty==BIAS+LDBL_MAX_EXP) + return (expsigny<0)? -pio2_hi-tiny: pio2_hi+tiny; + + /* compute y/x */ + k = expty-exptx; + if(k > LDBL_MANT_DIG+2) { /* |y/x| huge */ + z=pio2_hi+pio2_lo; + m&=1; + } + else if(expsignx<0&&k<-LDBL_MANT_DIG-2) z=0.0; /* |y/x| tiny, x<0 */ + else z=atanl(fabsl(y/x)); /* safe to do y/x */ + switch (m) { + case 0: return z ; /* atan(+,+) */ + case 1: return -z ; /* atan(-,+) */ + case 2: return pi-(z-pi_lo);/* atan(+,-) */ + default: /* case 3 */ + return (z-pi_lo)-pi;/* atan(-,-) */ + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_atanh.c b/libm/upstream-freebsd/lib/msun/src/e_atanh.c new file mode 100644 index 0000000..ab8a2e1 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_atanh.c @@ -0,0 +1,62 @@ + +/* @(#)e_atanh.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* __ieee754_atanh(x) + * Method : + * 1.Reduced x to positive by atanh(-x) = -atanh(x) + * 2.For x>=0.5 + * 1 2x x + * atanh(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------) + * 2 1 - x 1 - x + * + * For x<0.5 + * atanh(x) = 0.5*log1p(2x+2x*x/(1-x)) + * + * Special cases: + * atanh(x) is NaN if |x| > 1 with signal; + * atanh(NaN) is that NaN with no signal; + * atanh(+-1) is +-INF with signal. + * + */ + +#include "math.h" +#include "math_private.h" + +static const double one = 1.0, huge = 1e300; +static const double zero = 0.0; + +double +__ieee754_atanh(double x) +{ + double t; + int32_t hx,ix; + u_int32_t lx; + EXTRACT_WORDS(hx,lx,x); + ix = hx&0x7fffffff; + if ((ix|((lx|(-lx))>>31))>0x3ff00000) /* |x|>1 */ + return (x-x)/(x-x); + if(ix==0x3ff00000) + return x/zero; + if(ix<0x3e300000&&(huge+x)>zero) return x; /* x<2**-28 */ + SET_HIGH_WORD(x,ix); + if(ix<0x3fe00000) { /* x < 0.5 */ + t = x+x; + t = 0.5*log1p(t+t*x/(one-x)); + } else + t = 0.5*log1p((x+x)/(one-x)); + if(hx>=0) return t; else return -t; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_atanhf.c b/libm/upstream-freebsd/lib/msun/src/e_atanhf.c new file mode 100644 index 0000000..4bd6a8f --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_atanhf.c @@ -0,0 +1,45 @@ +/* e_atanhf.c -- float version of e_atanh.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +static const float one = 1.0, huge = 1e30; + +static const float zero = 0.0; + +float +__ieee754_atanhf(float x) +{ + float t; + int32_t hx,ix; + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if (ix>0x3f800000) /* |x|>1 */ + return (x-x)/(x-x); + if(ix==0x3f800000) + return x/zero; + if(ix<0x31800000&&(huge+x)>zero) return x; /* x<2**-28 */ + SET_FLOAT_WORD(x,ix); + if(ix<0x3f000000) { /* x < 0.5 */ + t = x+x; + t = (float)0.5*log1pf(t+t*x/(one-x)); + } else + t = (float)0.5*log1pf((x+x)/(one-x)); + if(hx>=0) return t; else return -t; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_cosh.c b/libm/upstream-freebsd/lib/msun/src/e_cosh.c new file mode 100644 index 0000000..a363695 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_cosh.c @@ -0,0 +1,79 @@ + +/* @(#)e_cosh.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* __ieee754_cosh(x) + * Method : + * mathematically cosh(x) if defined to be (exp(x)+exp(-x))/2 + * 1. Replace x by |x| (cosh(x) = cosh(-x)). + * 2. + * [ exp(x) - 1 ]^2 + * 0 <= x <= ln2/2 : cosh(x) := 1 + ------------------- + * 2*exp(x) + * + * exp(x) + 1/exp(x) + * ln2/2 <= x <= 22 : cosh(x) := ------------------- + * 2 + * 22 <= x <= lnovft : cosh(x) := exp(x)/2 + * lnovft <= x <= ln2ovft: cosh(x) := exp(x/2)/2 * exp(x/2) + * ln2ovft < x : cosh(x) := huge*huge (overflow) + * + * Special cases: + * cosh(x) is |x| if x is +INF, -INF, or NaN. + * only cosh(0)=1 is exact for finite x. + */ + +#include "math.h" +#include "math_private.h" + +static const double one = 1.0, half=0.5, huge = 1.0e300; + +double +__ieee754_cosh(double x) +{ + double t,w; + int32_t ix; + + /* High word of |x|. */ + GET_HIGH_WORD(ix,x); + ix &= 0x7fffffff; + + /* x is INF or NaN */ + if(ix>=0x7ff00000) return x*x; + + /* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */ + if(ix<0x3fd62e43) { + t = expm1(fabs(x)); + w = one+t; + if (ix<0x3c800000) return w; /* cosh(tiny) = 1 */ + return one+(t*t)/(w+w); + } + + /* |x| in [0.5*ln2,22], return (exp(|x|)+1/exp(|x|)/2; */ + if (ix < 0x40360000) { + t = __ieee754_exp(fabs(x)); + return half*t+half/t; + } + + /* |x| in [22, log(maxdouble)] return half*exp(|x|) */ + if (ix < 0x40862E42) return half*__ieee754_exp(fabs(x)); + + /* |x| in [log(maxdouble), overflowthresold] */ + if (ix<=0x408633CE) + return __ldexp_exp(fabs(x), -1); + + /* |x| > overflowthresold, cosh(x) overflow */ + return huge*huge; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_coshf.c b/libm/upstream-freebsd/lib/msun/src/e_coshf.c new file mode 100644 index 0000000..95a0d6e --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_coshf.c @@ -0,0 +1,59 @@ +/* e_coshf.c -- float version of e_cosh.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +static const float one = 1.0, half=0.5, huge = 1.0e30; + +float +__ieee754_coshf(float x) +{ + float t,w; + int32_t ix; + + GET_FLOAT_WORD(ix,x); + ix &= 0x7fffffff; + + /* x is INF or NaN */ + if(ix>=0x7f800000) return x*x; + + /* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */ + if(ix<0x3eb17218) { + t = expm1f(fabsf(x)); + w = one+t; + if (ix<0x39800000) return one; /* cosh(tiny) = 1 */ + return one+(t*t)/(w+w); + } + + /* |x| in [0.5*ln2,9], return (exp(|x|)+1/exp(|x|))/2; */ + if (ix < 0x41100000) { + t = __ieee754_expf(fabsf(x)); + return half*t+half/t; + } + + /* |x| in [9, log(maxfloat)] return half*exp(|x|) */ + if (ix < 0x42b17217) return half*__ieee754_expf(fabsf(x)); + + /* |x| in [log(maxfloat), overflowthresold] */ + if (ix<=0x42b2d4fc) + return __ldexp_expf(fabsf(x), -1); + + /* |x| > overflowthresold, cosh(x) overflow */ + return huge*huge; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_exp.c b/libm/upstream-freebsd/lib/msun/src/e_exp.c new file mode 100644 index 0000000..e432bc8 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_exp.c @@ -0,0 +1,164 @@ + +/* @(#)e_exp.c 1.6 04/04/22 */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* __ieee754_exp(x) + * Returns the exponential of x. + * + * Method + * 1. Argument reduction: + * Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658. + * Given x, find r and integer k such that + * + * x = k*ln2 + r, |r| <= 0.5*ln2. + * + * Here r will be represented as r = hi-lo for better + * accuracy. + * + * 2. Approximation of exp(r) by a special rational function on + * the interval [0,0.34658]: + * Write + * R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ... + * We use a special Remes algorithm on [0,0.34658] to generate + * a polynomial of degree 5 to approximate R. The maximum error + * of this polynomial approximation is bounded by 2**-59. In + * other words, + * R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5 + * (where z=r*r, and the values of P1 to P5 are listed below) + * and + * | 5 | -59 + * | 2.0+P1*z+...+P5*z - R(z) | <= 2 + * | | + * The computation of exp(r) thus becomes + * 2*r + * exp(r) = 1 + ------- + * R - r + * r*R1(r) + * = 1 + r + ----------- (for better accuracy) + * 2 - R1(r) + * where + * 2 4 10 + * R1(r) = r - (P1*r + P2*r + ... + P5*r ). + * + * 3. Scale back to obtain exp(x): + * From step 1, we have + * exp(x) = 2^k * exp(r) + * + * Special cases: + * exp(INF) is INF, exp(NaN) is NaN; + * exp(-INF) is 0, and + * for finite argument, only exp(0)=1 is exact. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Misc. info. + * For IEEE double + * if x > 7.09782712893383973096e+02 then exp(x) overflow + * if x < -7.45133219101941108420e+02 then exp(x) underflow + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include <float.h> + +#include "math.h" +#include "math_private.h" + +static const double +one = 1.0, +halF[2] = {0.5,-0.5,}, +huge = 1.0e+300, +o_threshold= 7.09782712893383973096e+02, /* 0x40862E42, 0xFEFA39EF */ +u_threshold= -7.45133219101941108420e+02, /* 0xc0874910, 0xD52D3051 */ +ln2HI[2] ={ 6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */ + -6.93147180369123816490e-01,},/* 0xbfe62e42, 0xfee00000 */ +ln2LO[2] ={ 1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */ + -1.90821492927058770002e-10,},/* 0xbdea39ef, 0x35793c76 */ +invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */ +P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ +P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ +P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ +P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ +P5 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ + +static volatile double +twom1000= 9.33263618503218878990e-302; /* 2**-1000=0x01700000,0*/ + +double +__ieee754_exp(double x) /* default IEEE double exp */ +{ + double y,hi=0.0,lo=0.0,c,t,twopk; + int32_t k=0,xsb; + u_int32_t hx; + + GET_HIGH_WORD(hx,x); + xsb = (hx>>31)&1; /* sign bit of x */ + hx &= 0x7fffffff; /* high word of |x| */ + + /* filter out non-finite argument */ + if(hx >= 0x40862E42) { /* if |x|>=709.78... */ + if(hx>=0x7ff00000) { + u_int32_t lx; + GET_LOW_WORD(lx,x); + if(((hx&0xfffff)|lx)!=0) + return x+x; /* NaN */ + else return (xsb==0)? x:0.0; /* exp(+-inf)={inf,0} */ + } + if(x > o_threshold) return huge*huge; /* overflow */ + if(x < u_threshold) return twom1000*twom1000; /* underflow */ + } + + /* argument reduction */ + if(hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */ + if(hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */ + hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb; + } else { + k = (int)(invln2*x+halF[xsb]); + t = k; + hi = x - t*ln2HI[0]; /* t*ln2HI is exact here */ + lo = t*ln2LO[0]; + } + STRICT_ASSIGN(double, x, hi - lo); + } + else if(hx < 0x3e300000) { /* when |x|<2**-28 */ + if(huge+x>one) return one+x;/* trigger inexact */ + } + else k = 0; + + /* x is now in primary range */ + t = x*x; + if(k >= -1021) + INSERT_WORDS(twopk,0x3ff00000+(k<<20), 0); + else + INSERT_WORDS(twopk,0x3ff00000+((k+1000)<<20), 0); + c = x - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); + if(k==0) return one-((x*c)/(c-2.0)-x); + else y = one-((lo-(x*c)/(2.0-c))-hi); + if(k >= -1021) { + if (k==1024) return y*2.0*0x1p1023; + return y*twopk; + } else { + return y*twopk*twom1000; + } +} + +#if (LDBL_MANT_DIG == 53) +__weak_reference(exp, expl); +#endif diff --git a/libm/upstream-freebsd/lib/msun/src/e_expf.c b/libm/upstream-freebsd/lib/msun/src/e_expf.c new file mode 100644 index 0000000..a479076 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_expf.c @@ -0,0 +1,97 @@ +/* e_expf.c -- float version of e_exp.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <float.h> + +#include "math.h" +#include "math_private.h" + +static const float +one = 1.0, +halF[2] = {0.5,-0.5,}, +huge = 1.0e+30, +o_threshold= 8.8721679688e+01, /* 0x42b17180 */ +u_threshold= -1.0397208405e+02, /* 0xc2cff1b5 */ +ln2HI[2] ={ 6.9314575195e-01, /* 0x3f317200 */ + -6.9314575195e-01,}, /* 0xbf317200 */ +ln2LO[2] ={ 1.4286067653e-06, /* 0x35bfbe8e */ + -1.4286067653e-06,}, /* 0xb5bfbe8e */ +invln2 = 1.4426950216e+00, /* 0x3fb8aa3b */ +/* + * Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]: + * |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74 + */ +P1 = 1.6666625440e-1, /* 0xaaaa8f.0p-26 */ +P2 = -2.7667332906e-3; /* -0xb55215.0p-32 */ + +static volatile float twom100 = 7.8886090522e-31; /* 2**-100=0x0d800000 */ + +float +__ieee754_expf(float x) +{ + float y,hi=0.0,lo=0.0,c,t,twopk; + int32_t k=0,xsb; + u_int32_t hx; + + GET_FLOAT_WORD(hx,x); + xsb = (hx>>31)&1; /* sign bit of x */ + hx &= 0x7fffffff; /* high word of |x| */ + + /* filter out non-finite argument */ + if(hx >= 0x42b17218) { /* if |x|>=88.721... */ + if(hx>0x7f800000) + return x+x; /* NaN */ + if(hx==0x7f800000) + return (xsb==0)? x:0.0; /* exp(+-inf)={inf,0} */ + if(x > o_threshold) return huge*huge; /* overflow */ + if(x < u_threshold) return twom100*twom100; /* underflow */ + } + + /* argument reduction */ + if(hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */ + if(hx < 0x3F851592) { /* and |x| < 1.5 ln2 */ + hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb; + } else { + k = invln2*x+halF[xsb]; + t = k; + hi = x - t*ln2HI[0]; /* t*ln2HI is exact here */ + lo = t*ln2LO[0]; + } + STRICT_ASSIGN(float, x, hi - lo); + } + else if(hx < 0x39000000) { /* when |x|<2**-14 */ + if(huge+x>one) return one+x;/* trigger inexact */ + } + else k = 0; + + /* x is now in primary range */ + t = x*x; + if(k >= -125) + SET_FLOAT_WORD(twopk,0x3f800000+(k<<23)); + else + SET_FLOAT_WORD(twopk,0x3f800000+((k+100)<<23)); + c = x - t*(P1+t*P2); + if(k==0) return one-((x*c)/(c-(float)2.0)-x); + else y = one-((lo-(x*c)/((float)2.0-c))-hi); + if(k >= -125) { + if(k==128) return y*2.0F*0x1p127F; + return y*twopk; + } else { + return y*twopk*twom100; + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_fmod.c b/libm/upstream-freebsd/lib/msun/src/e_fmod.c new file mode 100644 index 0000000..720aa03 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_fmod.c @@ -0,0 +1,132 @@ + +/* @(#)e_fmod.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * __ieee754_fmod(x,y) + * Return x mod y in exact arithmetic + * Method: shift and subtract + */ + +#include "math.h" +#include "math_private.h" + +static const double one = 1.0, Zero[] = {0.0, -0.0,}; + +double +__ieee754_fmod(double x, double y) +{ + int32_t n,hx,hy,hz,ix,iy,sx,i; + u_int32_t lx,ly,lz; + + EXTRACT_WORDS(hx,lx,x); + EXTRACT_WORDS(hy,ly,y); + sx = hx&0x80000000; /* sign of x */ + hx ^=sx; /* |x| */ + hy &= 0x7fffffff; /* |y| */ + + /* purge off exception values */ + if((hy|ly)==0||(hx>=0x7ff00000)|| /* y=0,or x not finite */ + ((hy|((ly|-ly)>>31))>0x7ff00000)) /* or y is NaN */ + return (x*y)/(x*y); + if(hx<=hy) { + if((hx<hy)||(lx<ly)) return x; /* |x|<|y| return x */ + if(lx==ly) + return Zero[(u_int32_t)sx>>31]; /* |x|=|y| return x*0*/ + } + + /* determine ix = ilogb(x) */ + if(hx<0x00100000) { /* subnormal x */ + if(hx==0) { + for (ix = -1043, i=lx; i>0; i<<=1) ix -=1; + } else { + for (ix = -1022,i=(hx<<11); i>0; i<<=1) ix -=1; + } + } else ix = (hx>>20)-1023; + + /* determine iy = ilogb(y) */ + if(hy<0x00100000) { /* subnormal y */ + if(hy==0) { + for (iy = -1043, i=ly; i>0; i<<=1) iy -=1; + } else { + for (iy = -1022,i=(hy<<11); i>0; i<<=1) iy -=1; + } + } else iy = (hy>>20)-1023; + + /* set up {hx,lx}, {hy,ly} and align y to x */ + if(ix >= -1022) + hx = 0x00100000|(0x000fffff&hx); + else { /* subnormal x, shift x to normal */ + n = -1022-ix; + if(n<=31) { + hx = (hx<<n)|(lx>>(32-n)); + lx <<= n; + } else { + hx = lx<<(n-32); + lx = 0; + } + } + if(iy >= -1022) + hy = 0x00100000|(0x000fffff&hy); + else { /* subnormal y, shift y to normal */ + n = -1022-iy; + if(n<=31) { + hy = (hy<<n)|(ly>>(32-n)); + ly <<= n; + } else { + hy = ly<<(n-32); + ly = 0; + } + } + + /* fix point fmod */ + n = ix - iy; + while(n--) { + hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1; + if(hz<0){hx = hx+hx+(lx>>31); lx = lx+lx;} + else { + if((hz|lz)==0) /* return sign(x)*0 */ + return Zero[(u_int32_t)sx>>31]; + hx = hz+hz+(lz>>31); lx = lz+lz; + } + } + hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1; + if(hz>=0) {hx=hz;lx=lz;} + + /* convert back to floating value and restore the sign */ + if((hx|lx)==0) /* return sign(x)*0 */ + return Zero[(u_int32_t)sx>>31]; + while(hx<0x00100000) { /* normalize x */ + hx = hx+hx+(lx>>31); lx = lx+lx; + iy -= 1; + } + if(iy>= -1022) { /* normalize output */ + hx = ((hx-0x00100000)|((iy+1023)<<20)); + INSERT_WORDS(x,hx|sx,lx); + } else { /* subnormal output */ + n = -1022 - iy; + if(n<=20) { + lx = (lx>>n)|((u_int32_t)hx<<(32-n)); + hx >>= n; + } else if (n<=31) { + lx = (hx<<(32-n))|(lx>>n); hx = sx; + } else { + lx = hx>>(n-32); hx = sx; + } + INSERT_WORDS(x,hx|sx,lx); + x *= one; /* create necessary signal */ + } + return x; /* exact output */ +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_fmodf.c b/libm/upstream-freebsd/lib/msun/src/e_fmodf.c new file mode 100644 index 0000000..52ce373 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_fmodf.c @@ -0,0 +1,104 @@ +/* e_fmodf.c -- float version of e_fmod.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * __ieee754_fmodf(x,y) + * Return x mod y in exact arithmetic + * Method: shift and subtract + */ + +#include "math.h" +#include "math_private.h" + +static const float one = 1.0, Zero[] = {0.0, -0.0,}; + +float +__ieee754_fmodf(float x, float y) +{ + int32_t n,hx,hy,hz,ix,iy,sx,i; + + GET_FLOAT_WORD(hx,x); + GET_FLOAT_WORD(hy,y); + sx = hx&0x80000000; /* sign of x */ + hx ^=sx; /* |x| */ + hy &= 0x7fffffff; /* |y| */ + + /* purge off exception values */ + if(hy==0||(hx>=0x7f800000)|| /* y=0,or x not finite */ + (hy>0x7f800000)) /* or y is NaN */ + return (x*y)/(x*y); + if(hx<hy) return x; /* |x|<|y| return x */ + if(hx==hy) + return Zero[(u_int32_t)sx>>31]; /* |x|=|y| return x*0*/ + + /* determine ix = ilogb(x) */ + if(hx<0x00800000) { /* subnormal x */ + for (ix = -126,i=(hx<<8); i>0; i<<=1) ix -=1; + } else ix = (hx>>23)-127; + + /* determine iy = ilogb(y) */ + if(hy<0x00800000) { /* subnormal y */ + for (iy = -126,i=(hy<<8); i>=0; i<<=1) iy -=1; + } else iy = (hy>>23)-127; + + /* set up {hx,lx}, {hy,ly} and align y to x */ + if(ix >= -126) + hx = 0x00800000|(0x007fffff&hx); + else { /* subnormal x, shift x to normal */ + n = -126-ix; + hx = hx<<n; + } + if(iy >= -126) + hy = 0x00800000|(0x007fffff&hy); + else { /* subnormal y, shift y to normal */ + n = -126-iy; + hy = hy<<n; + } + + /* fix point fmod */ + n = ix - iy; + while(n--) { + hz=hx-hy; + if(hz<0){hx = hx+hx;} + else { + if(hz==0) /* return sign(x)*0 */ + return Zero[(u_int32_t)sx>>31]; + hx = hz+hz; + } + } + hz=hx-hy; + if(hz>=0) {hx=hz;} + + /* convert back to floating value and restore the sign */ + if(hx==0) /* return sign(x)*0 */ + return Zero[(u_int32_t)sx>>31]; + while(hx<0x00800000) { /* normalize x */ + hx = hx+hx; + iy -= 1; + } + if(iy>= -126) { /* normalize output */ + hx = ((hx-0x00800000)|((iy+127)<<23)); + SET_FLOAT_WORD(x,hx|sx); + } else { /* subnormal output */ + n = -126 - iy; + hx >>= n; + SET_FLOAT_WORD(x,hx|sx); + x *= one; /* create necessary signal */ + } + return x; /* exact output */ +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_fmodl.c b/libm/upstream-freebsd/lib/msun/src/e_fmodl.c new file mode 100644 index 0000000..e315f76 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_fmodl.c @@ -0,0 +1,149 @@ +/* @(#)e_fmod.c 1.3 95/01/18 */ +/*- + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <float.h> +#include <stdint.h> + +#include "fpmath.h" +#include "math.h" +#include "math_private.h" + +#define BIAS (LDBL_MAX_EXP - 1) + +#if LDBL_MANL_SIZE > 32 +typedef uint64_t manl_t; +#else +typedef uint32_t manl_t; +#endif + +#if LDBL_MANH_SIZE > 32 +typedef uint64_t manh_t; +#else +typedef uint32_t manh_t; +#endif + +/* + * These macros add and remove an explicit integer bit in front of the + * fractional mantissa, if the architecture doesn't have such a bit by + * default already. + */ +#ifdef LDBL_IMPLICIT_NBIT +#define SET_NBIT(hx) ((hx) | (1ULL << LDBL_MANH_SIZE)) +#define HFRAC_BITS LDBL_MANH_SIZE +#else +#define SET_NBIT(hx) (hx) +#define HFRAC_BITS (LDBL_MANH_SIZE - 1) +#endif + +#define MANL_SHIFT (LDBL_MANL_SIZE - 1) + +static const long double one = 1.0, Zero[] = {0.0, -0.0,}; + +/* + * fmodl(x,y) + * Return x mod y in exact arithmetic + * Method: shift and subtract + * + * Assumptions: + * - The low part of the mantissa fits in a manl_t exactly. + * - The high part of the mantissa fits in an int64_t with enough room + * for an explicit integer bit in front of the fractional bits. + */ +long double +fmodl(long double x, long double y) +{ + union IEEEl2bits ux, uy; + int64_t hx,hz; /* We need a carry bit even if LDBL_MANH_SIZE is 32. */ + manh_t hy; + manl_t lx,ly,lz; + int ix,iy,n,sx; + + ux.e = x; + uy.e = y; + sx = ux.bits.sign; + + /* purge off exception values */ + if((uy.bits.exp|uy.bits.manh|uy.bits.manl)==0 || /* y=0 */ + (ux.bits.exp == BIAS + LDBL_MAX_EXP) || /* or x not finite */ + (uy.bits.exp == BIAS + LDBL_MAX_EXP && + ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl)!=0)) /* or y is NaN */ + return (x*y)/(x*y); + if(ux.bits.exp<=uy.bits.exp) { + if((ux.bits.exp<uy.bits.exp) || + (ux.bits.manh<=uy.bits.manh && + (ux.bits.manh<uy.bits.manh || + ux.bits.manl<uy.bits.manl))) { + return x; /* |x|<|y| return x or x-y */ + } + if(ux.bits.manh==uy.bits.manh && ux.bits.manl==uy.bits.manl) { + return Zero[sx]; /* |x|=|y| return x*0*/ + } + } + + /* determine ix = ilogb(x) */ + if(ux.bits.exp == 0) { /* subnormal x */ + ux.e *= 0x1.0p512; + ix = ux.bits.exp - (BIAS + 512); + } else { + ix = ux.bits.exp - BIAS; + } + + /* determine iy = ilogb(y) */ + if(uy.bits.exp == 0) { /* subnormal y */ + uy.e *= 0x1.0p512; + iy = uy.bits.exp - (BIAS + 512); + } else { + iy = uy.bits.exp - BIAS; + } + + /* set up {hx,lx}, {hy,ly} and align y to x */ + hx = SET_NBIT(ux.bits.manh); + hy = SET_NBIT(uy.bits.manh); + lx = ux.bits.manl; + ly = uy.bits.manl; + + /* fix point fmod */ + n = ix - iy; + + while(n--) { + hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1; + if(hz<0){hx = hx+hx+(lx>>MANL_SHIFT); lx = lx+lx;} + else { + if ((hz|lz)==0) /* return sign(x)*0 */ + return Zero[sx]; + hx = hz+hz+(lz>>MANL_SHIFT); lx = lz+lz; + } + } + hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1; + if(hz>=0) {hx=hz;lx=lz;} + + /* convert back to floating value and restore the sign */ + if((hx|lx)==0) /* return sign(x)*0 */ + return Zero[sx]; + while(hx<(1ULL<<HFRAC_BITS)) { /* normalize x */ + hx = hx+hx+(lx>>MANL_SHIFT); lx = lx+lx; + iy -= 1; + } + ux.bits.manh = hx; /* The mantissa is truncated here if needed. */ + ux.bits.manl = lx; + if (iy < LDBL_MIN_EXP) { + ux.bits.exp = iy + (BIAS + 512); + ux.e *= 0x1p-512; + } else { + ux.bits.exp = iy + BIAS; + } + x = ux.e * one; /* create necessary signal */ + return x; /* exact output */ +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_gamma.c b/libm/upstream-freebsd/lib/msun/src/e_gamma.c new file mode 100644 index 0000000..28fb5cc --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_gamma.c @@ -0,0 +1,33 @@ + +/* @(#)e_gamma.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* __ieee754_gamma(x) + * Return the logarithm of the Gamma function of x. + * + * Method: call __ieee754_gamma_r + */ + +#include "math.h" +#include "math_private.h" + +extern int signgam; + +double +__ieee754_gamma(double x) +{ + return __ieee754_gamma_r(x,&signgam); +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_gamma_r.c b/libm/upstream-freebsd/lib/msun/src/e_gamma_r.c new file mode 100644 index 0000000..2c423dc --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_gamma_r.c @@ -0,0 +1,32 @@ + +/* @(#)e_gamma_r.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* __ieee754_gamma_r(x, signgamp) + * Reentrant version of the logarithm of the Gamma function + * with user provide pointer for the sign of Gamma(x). + * + * Method: See __ieee754_lgamma_r + */ + +#include "math.h" +#include "math_private.h" + +double +__ieee754_gamma_r(double x, int *signgamp) +{ + return __ieee754_lgamma_r(x,signgamp); +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_gammaf.c b/libm/upstream-freebsd/lib/msun/src/e_gammaf.c new file mode 100644 index 0000000..c1b1668 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_gammaf.c @@ -0,0 +1,34 @@ +/* e_gammaf.c -- float version of e_gamma.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* __ieee754_gammaf(x) + * Return the logarithm of the Gamma function of x. + * + * Method: call __ieee754_gammaf_r + */ + +#include "math.h" +#include "math_private.h" + +extern int signgam; + +float +__ieee754_gammaf(float x) +{ + return __ieee754_gammaf_r(x,&signgam); +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_gammaf_r.c b/libm/upstream-freebsd/lib/msun/src/e_gammaf_r.c new file mode 100644 index 0000000..9d7831b --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_gammaf_r.c @@ -0,0 +1,33 @@ +/* e_gammaf_r.c -- float version of e_gamma_r.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* __ieee754_gammaf_r(x, signgamp) + * Reentrant version of the logarithm of the Gamma function + * with user provide pointer for the sign of Gamma(x). + * + * Method: See __ieee754_lgammaf_r + */ + +#include "math.h" +#include "math_private.h" + +float +__ieee754_gammaf_r(float x, int *signgamp) +{ + return __ieee754_lgammaf_r(x,signgamp); +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_hypot.c b/libm/upstream-freebsd/lib/msun/src/e_hypot.c new file mode 100644 index 0000000..2398e98 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_hypot.c @@ -0,0 +1,131 @@ + +/* @(#)e_hypot.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* __ieee754_hypot(x,y) + * + * Method : + * If (assume round-to-nearest) z=x*x+y*y + * has error less than sqrt(2)/2 ulp, than + * sqrt(z) has error less than 1 ulp (exercise). + * + * So, compute sqrt(x*x+y*y) with some care as + * follows to get the error below 1 ulp: + * + * Assume x>y>0; + * (if possible, set rounding to round-to-nearest) + * 1. if x > 2y use + * x1*x1+(y*y+(x2*(x+x1))) for x*x+y*y + * where x1 = x with lower 32 bits cleared, x2 = x-x1; else + * 2. if x <= 2y use + * t1*y1+((x-y)*(x-y)+(t1*y2+t2*y)) + * where t1 = 2x with lower 32 bits cleared, t2 = 2x-t1, + * y1= y with lower 32 bits chopped, y2 = y-y1. + * + * NOTE: scaling may be necessary if some argument is too + * large or too tiny + * + * Special cases: + * hypot(x,y) is INF if x or y is +INF or -INF; else + * hypot(x,y) is NAN if x or y is NAN. + * + * Accuracy: + * hypot(x,y) returns sqrt(x^2+y^2) with error less + * than 1 ulps (units in the last place) + */ + +#include <float.h> + +#include "math.h" +#include "math_private.h" + +double +__ieee754_hypot(double x, double y) +{ + double a,b,t1,t2,y1,y2,w; + int32_t j,k,ha,hb; + + GET_HIGH_WORD(ha,x); + ha &= 0x7fffffff; + GET_HIGH_WORD(hb,y); + hb &= 0x7fffffff; + if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;} + a = fabs(a); + b = fabs(b); + if((ha-hb)>0x3c00000) {return a+b;} /* x/y > 2**60 */ + k=0; + if(ha > 0x5f300000) { /* a>2**500 */ + if(ha >= 0x7ff00000) { /* Inf or NaN */ + u_int32_t low; + /* Use original arg order iff result is NaN; quieten sNaNs. */ + w = fabs(x+0.0)-fabs(y+0.0); + GET_LOW_WORD(low,a); + if(((ha&0xfffff)|low)==0) w = a; + GET_LOW_WORD(low,b); + if(((hb^0x7ff00000)|low)==0) w = b; + return w; + } + /* scale a and b by 2**-600 */ + ha -= 0x25800000; hb -= 0x25800000; k += 600; + SET_HIGH_WORD(a,ha); + SET_HIGH_WORD(b,hb); + } + if(hb < 0x20b00000) { /* b < 2**-500 */ + if(hb <= 0x000fffff) { /* subnormal b or 0 */ + u_int32_t low; + GET_LOW_WORD(low,b); + if((hb|low)==0) return a; + t1=0; + SET_HIGH_WORD(t1,0x7fd00000); /* t1=2^1022 */ + b *= t1; + a *= t1; + k -= 1022; + } else { /* scale a and b by 2^600 */ + ha += 0x25800000; /* a *= 2^600 */ + hb += 0x25800000; /* b *= 2^600 */ + k -= 600; + SET_HIGH_WORD(a,ha); + SET_HIGH_WORD(b,hb); + } + } + /* medium size a and b */ + w = a-b; + if (w>b) { + t1 = 0; + SET_HIGH_WORD(t1,ha); + t2 = a-t1; + w = sqrt(t1*t1-(b*(-b)-t2*(a+t1))); + } else { + a = a+a; + y1 = 0; + SET_HIGH_WORD(y1,hb); + y2 = b - y1; + t1 = 0; + SET_HIGH_WORD(t1,ha+0x00100000); + t2 = a - t1; + w = sqrt(t1*y1-(w*(-w)-(t1*y2+t2*b))); + } + if(k!=0) { + u_int32_t high; + t1 = 1.0; + GET_HIGH_WORD(high,t1); + SET_HIGH_WORD(t1,high+(k<<20)); + return t1*w; + } else return w; +} + +#if LDBL_MANT_DIG == 53 +__weak_reference(hypot, hypotl); +#endif diff --git a/libm/upstream-freebsd/lib/msun/src/e_hypotf.c b/libm/upstream-freebsd/lib/msun/src/e_hypotf.c new file mode 100644 index 0000000..6d083e4 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_hypotf.c @@ -0,0 +1,83 @@ +/* e_hypotf.c -- float version of e_hypot.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +float +__ieee754_hypotf(float x, float y) +{ + float a,b,t1,t2,y1,y2,w; + int32_t j,k,ha,hb; + + GET_FLOAT_WORD(ha,x); + ha &= 0x7fffffff; + GET_FLOAT_WORD(hb,y); + hb &= 0x7fffffff; + if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;} + a = fabsf(a); + b = fabsf(b); + if((ha-hb)>0xf000000) {return a+b;} /* x/y > 2**30 */ + k=0; + if(ha > 0x58800000) { /* a>2**50 */ + if(ha >= 0x7f800000) { /* Inf or NaN */ + /* Use original arg order iff result is NaN; quieten sNaNs. */ + w = fabsf(x+0.0F)-fabsf(y+0.0F); + if(ha == 0x7f800000) w = a; + if(hb == 0x7f800000) w = b; + return w; + } + /* scale a and b by 2**-68 */ + ha -= 0x22000000; hb -= 0x22000000; k += 68; + SET_FLOAT_WORD(a,ha); + SET_FLOAT_WORD(b,hb); + } + if(hb < 0x26800000) { /* b < 2**-50 */ + if(hb <= 0x007fffff) { /* subnormal b or 0 */ + if(hb==0) return a; + SET_FLOAT_WORD(t1,0x7e800000); /* t1=2^126 */ + b *= t1; + a *= t1; + k -= 126; + } else { /* scale a and b by 2^68 */ + ha += 0x22000000; /* a *= 2^68 */ + hb += 0x22000000; /* b *= 2^68 */ + k -= 68; + SET_FLOAT_WORD(a,ha); + SET_FLOAT_WORD(b,hb); + } + } + /* medium size a and b */ + w = a-b; + if (w>b) { + SET_FLOAT_WORD(t1,ha&0xfffff000); + t2 = a-t1; + w = __ieee754_sqrtf(t1*t1-(b*(-b)-t2*(a+t1))); + } else { + a = a+a; + SET_FLOAT_WORD(y1,hb&0xfffff000); + y2 = b - y1; + SET_FLOAT_WORD(t1,(ha+0x00800000)&0xfffff000); + t2 = a - t1; + w = __ieee754_sqrtf(t1*y1-(w*(-w)-(t1*y2+t2*b))); + } + if(k!=0) { + SET_FLOAT_WORD(t1,0x3f800000+(k<<23)); + return t1*w; + } else return w; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_hypotl.c b/libm/upstream-freebsd/lib/msun/src/e_hypotl.c new file mode 100644 index 0000000..7b5ab89 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_hypotl.c @@ -0,0 +1,124 @@ +/* From: @(#)e_hypot.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* long double version of hypot(). See e_hypot.c for most comments. */ + +#include <float.h> + +#include "fpmath.h" +#include "math.h" +#include "math_private.h" + +#define GET_LDBL_MAN(h, l, v) do { \ + union IEEEl2bits uv; \ + \ + uv.e = v; \ + h = uv.bits.manh; \ + l = uv.bits.manl; \ +} while (0) + +#undef GET_HIGH_WORD +#define GET_HIGH_WORD(i, v) GET_LDBL_EXPSIGN(i, v) +#undef SET_HIGH_WORD +#define SET_HIGH_WORD(v, i) SET_LDBL_EXPSIGN(v, i) + +#define DESW(exp) (exp) /* delta expsign word */ +#define ESW(exp) (MAX_EXP - 1 + (exp)) /* expsign word */ +#define MANT_DIG LDBL_MANT_DIG +#define MAX_EXP LDBL_MAX_EXP + +#if LDBL_MANL_SIZE > 32 +typedef uint64_t man_t; +#else +typedef uint32_t man_t; +#endif + +long double +hypotl(long double x, long double y) +{ + long double a=x,b=y,t1,t2,y1,y2,w; + int32_t j,k,ha,hb; + + GET_HIGH_WORD(ha,x); + ha &= 0x7fff; + GET_HIGH_WORD(hb,y); + hb &= 0x7fff; + if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;} + a = fabsl(a); + b = fabsl(b); + if((ha-hb)>DESW(MANT_DIG+7)) {return a+b;} /* x/y > 2**(MANT_DIG+7) */ + k=0; + if(ha > ESW(MAX_EXP/2-12)) { /* a>2**(MAX_EXP/2-12) */ + if(ha >= ESW(MAX_EXP)) { /* Inf or NaN */ + man_t manh, manl; + /* Use original arg order iff result is NaN; quieten sNaNs. */ + w = fabsl(x+0.0)-fabsl(y+0.0); + GET_LDBL_MAN(manh,manl,a); + if (manh == LDBL_NBIT && manl == 0) w = a; + GET_LDBL_MAN(manh,manl,b); + if (hb >= ESW(MAX_EXP) && manh == LDBL_NBIT && manl == 0) w = b; + return w; + } + /* scale a and b by 2**-(MAX_EXP/2+88) */ + ha -= DESW(MAX_EXP/2+88); hb -= DESW(MAX_EXP/2+88); + k += MAX_EXP/2+88; + SET_HIGH_WORD(a,ha); + SET_HIGH_WORD(b,hb); + } + if(hb < ESW(-(MAX_EXP/2-12))) { /* b < 2**-(MAX_EXP/2-12) */ + if(hb <= 0) { /* subnormal b or 0 */ + man_t manh, manl; + GET_LDBL_MAN(manh,manl,b); + if((manh|manl)==0) return a; + t1=0; + SET_HIGH_WORD(t1,ESW(MAX_EXP-2)); /* t1=2^(MAX_EXP-2) */ + b *= t1; + a *= t1; + k -= MAX_EXP-2; + } else { /* scale a and b by 2^(MAX_EXP/2+88) */ + ha += DESW(MAX_EXP/2+88); + hb += DESW(MAX_EXP/2+88); + k -= MAX_EXP/2+88; + SET_HIGH_WORD(a,ha); + SET_HIGH_WORD(b,hb); + } + } + /* medium size a and b */ + w = a-b; + if (w>b) { + t1 = a; + union IEEEl2bits uv; + uv.e = t1; uv.bits.manl = 0; t1 = uv.e; + t2 = a-t1; + w = sqrtl(t1*t1-(b*(-b)-t2*(a+t1))); + } else { + a = a+a; + y1 = b; + union IEEEl2bits uv; + uv.e = y1; uv.bits.manl = 0; y1 = uv.e; + y2 = b - y1; + t1 = a; + uv.e = t1; uv.bits.manl = 0; t1 = uv.e; + t2 = a - t1; + w = sqrtl(t1*y1-(w*(-w)-(t1*y2+t2*b))); + } + if(k!=0) { + u_int32_t high; + t1 = 1.0; + GET_HIGH_WORD(high,t1); + SET_HIGH_WORD(t1,high+DESW(k)); + return t1*w; + } else return w; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_j0.c b/libm/upstream-freebsd/lib/msun/src/e_j0.c new file mode 100644 index 0000000..8320f25 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_j0.c @@ -0,0 +1,381 @@ + +/* @(#)e_j0.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* __ieee754_j0(x), __ieee754_y0(x) + * Bessel function of the first and second kinds of order zero. + * Method -- j0(x): + * 1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ... + * 2. Reduce x to |x| since j0(x)=j0(-x), and + * for x in (0,2) + * j0(x) = 1-z/4+ z^2*R0/S0, where z = x*x; + * (precision: |j0-1+z/4-z^2R0/S0 |<2**-63.67 ) + * for x in (2,inf) + * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0)) + * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) + * as follow: + * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4) + * = 1/sqrt(2) * (cos(x) + sin(x)) + * sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * (To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one.) + * + * 3 Special cases + * j0(nan)= nan + * j0(0) = 1 + * j0(inf) = 0 + * + * Method -- y0(x): + * 1. For x<2. + * Since + * y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x^2/4 - ...) + * therefore y0(x)-2/pi*j0(x)*ln(x) is an even function. + * We use the following function to approximate y0, + * y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x^2 + * where + * U(z) = u00 + u01*z + ... + u06*z^6 + * V(z) = 1 + v01*z + ... + v04*z^4 + * with absolute approximation error bounded by 2**-72. + * Note: For tiny x, U/V = u0 and j0(x)~1, hence + * y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27) + * 2. For x>=2. + * y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0)) + * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) + * by the method mentioned above. + * 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0. + */ + +#include "math.h" +#include "math_private.h" + +static double pzero(double), qzero(double); + +static const double +huge = 1e300, +one = 1.0, +invsqrtpi= 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */ +tpi = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ + /* R0/S0 on [0, 2.00] */ +R02 = 1.56249999999999947958e-02, /* 0x3F8FFFFF, 0xFFFFFFFD */ +R03 = -1.89979294238854721751e-04, /* 0xBF28E6A5, 0xB61AC6E9 */ +R04 = 1.82954049532700665670e-06, /* 0x3EBEB1D1, 0x0C503919 */ +R05 = -4.61832688532103189199e-09, /* 0xBE33D5E7, 0x73D63FCE */ +S01 = 1.56191029464890010492e-02, /* 0x3F8FFCE8, 0x82C8C2A4 */ +S02 = 1.16926784663337450260e-04, /* 0x3F1EA6D2, 0xDD57DBF4 */ +S03 = 5.13546550207318111446e-07, /* 0x3EA13B54, 0xCE84D5A9 */ +S04 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */ + +static const double zero = 0.0; + +double +__ieee754_j0(double x) +{ + double z, s,c,ss,cc,r,u,v; + int32_t hx,ix; + + GET_HIGH_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x7ff00000) return one/(x*x); + x = fabs(x); + if(ix >= 0x40000000) { /* |x| >= 2.0 */ + s = sin(x); + c = cos(x); + ss = s-c; + cc = s+c; + if(ix<0x7fe00000) { /* make sure x+x not overflow */ + z = -cos(x+x); + if ((s*c)<zero) cc = z/ss; + else ss = z/cc; + } + /* + * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) + * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) + */ + if(ix>0x48000000) z = (invsqrtpi*cc)/sqrt(x); + else { + u = pzero(x); v = qzero(x); + z = invsqrtpi*(u*cc-v*ss)/sqrt(x); + } + return z; + } + if(ix<0x3f200000) { /* |x| < 2**-13 */ + if(huge+x>one) { /* raise inexact if x != 0 */ + if(ix<0x3e400000) return one; /* |x|<2**-27 */ + else return one - 0.25*x*x; + } + } + z = x*x; + r = z*(R02+z*(R03+z*(R04+z*R05))); + s = one+z*(S01+z*(S02+z*(S03+z*S04))); + if(ix < 0x3FF00000) { /* |x| < 1.00 */ + return one + z*(-0.25+(r/s)); + } else { + u = 0.5*x; + return((one+u)*(one-u)+z*(r/s)); + } +} + +static const double +u00 = -7.38042951086872317523e-02, /* 0xBFB2E4D6, 0x99CBD01F */ +u01 = 1.76666452509181115538e-01, /* 0x3FC69D01, 0x9DE9E3FC */ +u02 = -1.38185671945596898896e-02, /* 0xBF8C4CE8, 0xB16CFA97 */ +u03 = 3.47453432093683650238e-04, /* 0x3F36C54D, 0x20B29B6B */ +u04 = -3.81407053724364161125e-06, /* 0xBECFFEA7, 0x73D25CAD */ +u05 = 1.95590137035022920206e-08, /* 0x3E550057, 0x3B4EABD4 */ +u06 = -3.98205194132103398453e-11, /* 0xBDC5E43D, 0x693FB3C8 */ +v01 = 1.27304834834123699328e-02, /* 0x3F8A1270, 0x91C9C71A */ +v02 = 7.60068627350353253702e-05, /* 0x3F13ECBB, 0xF578C6C1 */ +v03 = 2.59150851840457805467e-07, /* 0x3E91642D, 0x7FF202FD */ +v04 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ + +double +__ieee754_y0(double x) +{ + double z, s,c,ss,cc,u,v; + int32_t hx,ix,lx; + + EXTRACT_WORDS(hx,lx,x); + ix = 0x7fffffff&hx; + /* Y0(NaN) is NaN, y0(-inf) is Nan, y0(inf) is 0 */ + if(ix>=0x7ff00000) return one/(x+x*x); + if((ix|lx)==0) return -one/zero; + if(hx<0) return zero/zero; + if(ix >= 0x40000000) { /* |x| >= 2.0 */ + /* y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x0)+q0(x)*cos(x0)) + * where x0 = x-pi/4 + * Better formula: + * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4) + * = 1/sqrt(2) * (sin(x) + cos(x)) + * sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one. + */ + s = sin(x); + c = cos(x); + ss = s-c; + cc = s+c; + /* + * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) + * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) + */ + if(ix<0x7fe00000) { /* make sure x+x not overflow */ + z = -cos(x+x); + if ((s*c)<zero) cc = z/ss; + else ss = z/cc; + } + if(ix>0x48000000) z = (invsqrtpi*ss)/sqrt(x); + else { + u = pzero(x); v = qzero(x); + z = invsqrtpi*(u*ss+v*cc)/sqrt(x); + } + return z; + } + if(ix<=0x3e400000) { /* x < 2**-27 */ + return(u00 + tpi*__ieee754_log(x)); + } + z = x*x; + u = u00+z*(u01+z*(u02+z*(u03+z*(u04+z*(u05+z*u06))))); + v = one+z*(v01+z*(v02+z*(v03+z*v04))); + return(u/v + tpi*(__ieee754_j0(x)*__ieee754_log(x))); +} + +/* The asymptotic expansions of pzero is + * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. + * For x >= 2, We approximate pzero by + * pzero(x) = 1 + (R/S) + * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 + * S = 1 + pS0*s^2 + ... + pS4*s^10 + * and + * | pzero(x)-1-R/S | <= 2 ** ( -60.26) + */ +static const double pR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + -7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */ + -8.08167041275349795626e+00, /* 0xC02029D0, 0xB44FA779 */ + -2.57063105679704847262e+02, /* 0xC0701102, 0x7B19E863 */ + -2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */ + -5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */ +}; +static const double pS8[5] = { + 1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */ + 3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */ + 4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */ + 1.16752972564375915681e+05, /* 0x40FC810F, 0x8F9FA9BD */ + 4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */ +}; + +static const double pR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */ + -7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */ + -4.15961064470587782438e+00, /* 0xC010A370, 0xF90C6BBF */ + -6.76747652265167261021e+01, /* 0xC050EB2F, 0x5A7D1783 */ + -3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */ + -3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */ +}; +static const double pS5[5] = { + 6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */ + 1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */ + 5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */ + 9.62544514357774460223e+03, /* 0x40C2CCB8, 0xFA76FA38 */ + 2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */ +}; + +static const double pR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + -2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */ + -7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */ + -2.40903221549529611423e+00, /* 0xC00345B2, 0xAEA48074 */ + -2.19659774734883086467e+01, /* 0xC035F74A, 0x4CB94E14 */ + -5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */ + -3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */ +}; +static const double pS3[5] = { + 3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */ + 3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */ + 1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */ + 1.12799679856907414432e+03, /* 0x40919FFC, 0xB8C39B7E */ + 1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */ +}; + +static const double pR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + -8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */ + -7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */ + -1.45073846780952986357e+00, /* 0xBFF73639, 0x8A24A843 */ + -7.63569613823527770791e+00, /* 0xC01E8AF3, 0xEDAFA7F3 */ + -1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */ + -3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */ +}; +static const double pS2[5] = { + 2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */ + 1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */ + 2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */ + 1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */ + 1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */ +}; + + static double pzero(double x) +{ + const double *p,*q; + double z,r,s; + int32_t ix; + GET_HIGH_WORD(ix,x); + ix &= 0x7fffffff; + if(ix>=0x40200000) {p = pR8; q= pS8;} + else if(ix>=0x40122E8B){p = pR5; q= pS5;} + else if(ix>=0x4006DB6D){p = pR3; q= pS3;} + else if(ix>=0x40000000){p = pR2; q= pS2;} + z = one/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return one+ r/s; +} + + +/* For x >= 8, the asymptotic expansions of qzero is + * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. + * We approximate pzero by + * qzero(x) = s*(-1.25 + (R/S)) + * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 + * S = 1 + qS0*s^2 + ... + qS5*s^12 + * and + * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) + */ +static const double qR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + 7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */ + 1.17682064682252693899e+01, /* 0x40278952, 0x5BB334D6 */ + 5.57673380256401856059e+02, /* 0x40816D63, 0x15301825 */ + 8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */ + 3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */ +}; +static const double qS8[6] = { + 1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */ + 8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */ + 1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */ + 8.03309257119514397345e+05, /* 0x412883DA, 0x83A52B43 */ + 8.40501579819060512818e+05, /* 0x4129A66B, 0x28DE0B3D */ + -3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */ +}; + +static const double qR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */ + 7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */ + 5.83563508962056953777e+00, /* 0x401757B0, 0xB9953DD3 */ + 1.35111577286449829671e+02, /* 0x4060E392, 0x0A8788E9 */ + 1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */ + 1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */ +}; +static const double qS5[6] = { + 8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */ + 2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */ + 1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */ + 5.67511122894947329769e+04, /* 0x40EBB5E3, 0x97E02372 */ + 3.59767538425114471465e+04, /* 0x40E19118, 0x1F7A54A0 */ + -5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */ +}; + +static const double qR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + 4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */ + 7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */ + 3.34423137516170720929e+00, /* 0x400AC0FC, 0x61149CF5 */ + 4.26218440745412650017e+01, /* 0x40454F98, 0x962DAEDD */ + 1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */ + 1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */ +}; +static const double qS3[6] = { + 4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */ + 7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */ + 3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */ + 6.46042516752568917582e+03, /* 0x40B93C6C, 0xD7C76A28 */ + 2.51633368920368957333e+03, /* 0x40A3A8AA, 0xD94FB1C0 */ + -1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */ +}; + +static const double qR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */ + 7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */ + 1.99819174093815998816e+00, /* 0x3FFFF897, 0xE727779C */ + 1.44956029347885735348e+01, /* 0x402CFDBF, 0xAAF96FE5 */ + 3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */ + 1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */ +}; +static const double qS2[6] = { + 3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */ + 2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */ + 8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */ + 8.82935845112488550512e+02, /* 0x408B977C, 0x9C5CC214 */ + 2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */ + -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */ +}; + + static double qzero(double x) +{ + const double *p,*q; + double s,r,z; + int32_t ix; + GET_HIGH_WORD(ix,x); + ix &= 0x7fffffff; + if(ix>=0x40200000) {p = qR8; q= qS8;} + else if(ix>=0x40122E8B){p = qR5; q= qS5;} + else if(ix>=0x4006DB6D){p = qR3; q= qS3;} + else if(ix>=0x40000000){p = qR2; q= qS2;} + z = one/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return (-.125 + r/s)/x; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_j0f.c b/libm/upstream-freebsd/lib/msun/src/e_j0f.c new file mode 100644 index 0000000..c45faf3 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_j0f.c @@ -0,0 +1,337 @@ +/* e_j0f.c -- float version of e_j0.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +static float pzerof(float), qzerof(float); + +static const float +huge = 1e30, +one = 1.0, +invsqrtpi= 5.6418961287e-01, /* 0x3f106ebb */ +tpi = 6.3661974669e-01, /* 0x3f22f983 */ + /* R0/S0 on [0, 2.00] */ +R02 = 1.5625000000e-02, /* 0x3c800000 */ +R03 = -1.8997929874e-04, /* 0xb947352e */ +R04 = 1.8295404516e-06, /* 0x35f58e88 */ +R05 = -4.6183270541e-09, /* 0xb19eaf3c */ +S01 = 1.5619102865e-02, /* 0x3c7fe744 */ +S02 = 1.1692678527e-04, /* 0x38f53697 */ +S03 = 5.1354652442e-07, /* 0x3509daa6 */ +S04 = 1.1661400734e-09; /* 0x30a045e8 */ + +static const float zero = 0.0; + +float +__ieee754_j0f(float x) +{ + float z, s,c,ss,cc,r,u,v; + int32_t hx,ix; + + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x7f800000) return one/(x*x); + x = fabsf(x); + if(ix >= 0x40000000) { /* |x| >= 2.0 */ + s = sinf(x); + c = cosf(x); + ss = s-c; + cc = s+c; + if(ix<0x7f000000) { /* make sure x+x not overflow */ + z = -cosf(x+x); + if ((s*c)<zero) cc = z/ss; + else ss = z/cc; + } + /* + * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) + * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) + */ + if(ix>0x80000000) z = (invsqrtpi*cc)/sqrtf(x); + else { + u = pzerof(x); v = qzerof(x); + z = invsqrtpi*(u*cc-v*ss)/sqrtf(x); + } + return z; + } + if(ix<0x39000000) { /* |x| < 2**-13 */ + if(huge+x>one) { /* raise inexact if x != 0 */ + if(ix<0x32000000) return one; /* |x|<2**-27 */ + else return one - (float)0.25*x*x; + } + } + z = x*x; + r = z*(R02+z*(R03+z*(R04+z*R05))); + s = one+z*(S01+z*(S02+z*(S03+z*S04))); + if(ix < 0x3F800000) { /* |x| < 1.00 */ + return one + z*((float)-0.25+(r/s)); + } else { + u = (float)0.5*x; + return((one+u)*(one-u)+z*(r/s)); + } +} + +static const float +u00 = -7.3804296553e-02, /* 0xbd9726b5 */ +u01 = 1.7666645348e-01, /* 0x3e34e80d */ +u02 = -1.3818567619e-02, /* 0xbc626746 */ +u03 = 3.4745343146e-04, /* 0x39b62a69 */ +u04 = -3.8140706238e-06, /* 0xb67ff53c */ +u05 = 1.9559013964e-08, /* 0x32a802ba */ +u06 = -3.9820518410e-11, /* 0xae2f21eb */ +v01 = 1.2730483897e-02, /* 0x3c509385 */ +v02 = 7.6006865129e-05, /* 0x389f65e0 */ +v03 = 2.5915085189e-07, /* 0x348b216c */ +v04 = 4.4111031494e-10; /* 0x2ff280c2 */ + +float +__ieee754_y0f(float x) +{ + float z, s,c,ss,cc,u,v; + int32_t hx,ix; + + GET_FLOAT_WORD(hx,x); + ix = 0x7fffffff&hx; + /* Y0(NaN) is NaN, y0(-inf) is Nan, y0(inf) is 0 */ + if(ix>=0x7f800000) return one/(x+x*x); + if(ix==0) return -one/zero; + if(hx<0) return zero/zero; + if(ix >= 0x40000000) { /* |x| >= 2.0 */ + /* y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x0)+q0(x)*cos(x0)) + * where x0 = x-pi/4 + * Better formula: + * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4) + * = 1/sqrt(2) * (sin(x) + cos(x)) + * sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one. + */ + s = sinf(x); + c = cosf(x); + ss = s-c; + cc = s+c; + /* + * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) + * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) + */ + if(ix<0x7f000000) { /* make sure x+x not overflow */ + z = -cosf(x+x); + if ((s*c)<zero) cc = z/ss; + else ss = z/cc; + } + if(ix>0x80000000) z = (invsqrtpi*ss)/sqrtf(x); + else { + u = pzerof(x); v = qzerof(x); + z = invsqrtpi*(u*ss+v*cc)/sqrtf(x); + } + return z; + } + if(ix<=0x32000000) { /* x < 2**-27 */ + return(u00 + tpi*__ieee754_logf(x)); + } + z = x*x; + u = u00+z*(u01+z*(u02+z*(u03+z*(u04+z*(u05+z*u06))))); + v = one+z*(v01+z*(v02+z*(v03+z*v04))); + return(u/v + tpi*(__ieee754_j0f(x)*__ieee754_logf(x))); +} + +/* The asymptotic expansions of pzero is + * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. + * For x >= 2, We approximate pzero by + * pzero(x) = 1 + (R/S) + * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 + * S = 1 + pS0*s^2 + ... + pS4*s^10 + * and + * | pzero(x)-1-R/S | <= 2 ** ( -60.26) + */ +static const float pR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + -7.0312500000e-02, /* 0xbd900000 */ + -8.0816707611e+00, /* 0xc1014e86 */ + -2.5706311035e+02, /* 0xc3808814 */ + -2.4852163086e+03, /* 0xc51b5376 */ + -5.2530439453e+03, /* 0xc5a4285a */ +}; +static const float pS8[5] = { + 1.1653436279e+02, /* 0x42e91198 */ + 3.8337448730e+03, /* 0x456f9beb */ + 4.0597855469e+04, /* 0x471e95db */ + 1.1675296875e+05, /* 0x47e4087c */ + 4.7627726562e+04, /* 0x473a0bba */ +}; +static const float pR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -1.1412546255e-11, /* 0xad48c58a */ + -7.0312492549e-02, /* 0xbd8fffff */ + -4.1596107483e+00, /* 0xc0851b88 */ + -6.7674766541e+01, /* 0xc287597b */ + -3.3123129272e+02, /* 0xc3a59d9b */ + -3.4643338013e+02, /* 0xc3ad3779 */ +}; +static const float pS5[5] = { + 6.0753936768e+01, /* 0x42730408 */ + 1.0512523193e+03, /* 0x44836813 */ + 5.9789707031e+03, /* 0x45bad7c4 */ + 9.6254453125e+03, /* 0x461665c8 */ + 2.4060581055e+03, /* 0x451660ee */ +}; + +static const float pR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + -2.5470459075e-09, /* 0xb12f081b */ + -7.0311963558e-02, /* 0xbd8fffb8 */ + -2.4090321064e+00, /* 0xc01a2d95 */ + -2.1965976715e+01, /* 0xc1afba52 */ + -5.8079170227e+01, /* 0xc2685112 */ + -3.1447946548e+01, /* 0xc1fb9565 */ +}; +static const float pS3[5] = { + 3.5856033325e+01, /* 0x420f6c94 */ + 3.6151397705e+02, /* 0x43b4c1ca */ + 1.1936077881e+03, /* 0x44953373 */ + 1.1279968262e+03, /* 0x448cffe6 */ + 1.7358093262e+02, /* 0x432d94b8 */ +}; + +static const float pR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + -8.8753431271e-08, /* 0xb3be98b7 */ + -7.0303097367e-02, /* 0xbd8ffb12 */ + -1.4507384300e+00, /* 0xbfb9b1cc */ + -7.6356959343e+00, /* 0xc0f4579f */ + -1.1193166733e+01, /* 0xc1331736 */ + -3.2336456776e+00, /* 0xc04ef40d */ +}; +static const float pS2[5] = { + 2.2220300674e+01, /* 0x41b1c32d */ + 1.3620678711e+02, /* 0x430834f0 */ + 2.7047027588e+02, /* 0x43873c32 */ + 1.5387539673e+02, /* 0x4319e01a */ + 1.4657617569e+01, /* 0x416a859a */ +}; + + static float pzerof(float x) +{ + const float *p,*q; + float z,r,s; + int32_t ix; + GET_FLOAT_WORD(ix,x); + ix &= 0x7fffffff; + if(ix>=0x41000000) {p = pR8; q= pS8;} + else if(ix>=0x40f71c58){p = pR5; q= pS5;} + else if(ix>=0x4036db68){p = pR3; q= pS3;} + else if(ix>=0x40000000){p = pR2; q= pS2;} + z = one/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return one+ r/s; +} + + +/* For x >= 8, the asymptotic expansions of qzero is + * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. + * We approximate pzero by + * qzero(x) = s*(-1.25 + (R/S)) + * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 + * S = 1 + qS0*s^2 + ... + qS5*s^12 + * and + * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) + */ +static const float qR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + 7.3242187500e-02, /* 0x3d960000 */ + 1.1768206596e+01, /* 0x413c4a93 */ + 5.5767340088e+02, /* 0x440b6b19 */ + 8.8591972656e+03, /* 0x460a6cca */ + 3.7014625000e+04, /* 0x471096a0 */ +}; +static const float qS8[6] = { + 1.6377603149e+02, /* 0x4323c6aa */ + 8.0983447266e+03, /* 0x45fd12c2 */ + 1.4253829688e+05, /* 0x480b3293 */ + 8.0330925000e+05, /* 0x49441ed4 */ + 8.4050156250e+05, /* 0x494d3359 */ + -3.4389928125e+05, /* 0xc8a7eb69 */ +}; + +static const float qR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.8408595828e-11, /* 0x2da1ec79 */ + 7.3242180049e-02, /* 0x3d95ffff */ + 5.8356351852e+00, /* 0x40babd86 */ + 1.3511157227e+02, /* 0x43071c90 */ + 1.0272437744e+03, /* 0x448067cd */ + 1.9899779053e+03, /* 0x44f8bf4b */ +}; +static const float qS5[6] = { + 8.2776611328e+01, /* 0x42a58da0 */ + 2.0778142090e+03, /* 0x4501dd07 */ + 1.8847289062e+04, /* 0x46933e94 */ + 5.6751113281e+04, /* 0x475daf1d */ + 3.5976753906e+04, /* 0x470c88c1 */ + -5.3543427734e+03, /* 0xc5a752be */ +}; + +static const float qR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + 4.3774099900e-09, /* 0x3196681b */ + 7.3241114616e-02, /* 0x3d95ff70 */ + 3.3442313671e+00, /* 0x405607e3 */ + 4.2621845245e+01, /* 0x422a7cc5 */ + 1.7080809021e+02, /* 0x432acedf */ + 1.6673394775e+02, /* 0x4326bbe4 */ +}; +static const float qS3[6] = { + 4.8758872986e+01, /* 0x42430916 */ + 7.0968920898e+02, /* 0x44316c1c */ + 3.7041481934e+03, /* 0x4567825f */ + 6.4604252930e+03, /* 0x45c9e367 */ + 2.5163337402e+03, /* 0x451d4557 */ + -1.4924745178e+02, /* 0xc3153f59 */ +}; + +static const float qR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.5044444979e-07, /* 0x342189db */ + 7.3223426938e-02, /* 0x3d95f62a */ + 1.9981917143e+00, /* 0x3fffc4bf */ + 1.4495602608e+01, /* 0x4167edfd */ + 3.1666231155e+01, /* 0x41fd5471 */ + 1.6252708435e+01, /* 0x4182058c */ +}; +static const float qS2[6] = { + 3.0365585327e+01, /* 0x41f2ecb8 */ + 2.6934811401e+02, /* 0x4386ac8f */ + 8.4478375244e+02, /* 0x44533229 */ + 8.8293585205e+02, /* 0x445cbbe5 */ + 2.1266638184e+02, /* 0x4354aa98 */ + -5.3109550476e+00, /* 0xc0a9f358 */ +}; + + static float qzerof(float x) +{ + const float *p,*q; + float s,r,z; + int32_t ix; + GET_FLOAT_WORD(ix,x); + ix &= 0x7fffffff; + if(ix>=0x41000000) {p = qR8; q= qS8;} + else if(ix>=0x40f71c58){p = qR5; q= qS5;} + else if(ix>=0x4036db68){p = qR3; q= qS3;} + else if(ix>=0x40000000){p = qR2; q= qS2;} + z = one/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return (-(float).125 + r/s)/x; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_j1.c b/libm/upstream-freebsd/lib/msun/src/e_j1.c new file mode 100644 index 0000000..63800ad --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_j1.c @@ -0,0 +1,376 @@ + +/* @(#)e_j1.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* __ieee754_j1(x), __ieee754_y1(x) + * Bessel function of the first and second kinds of order zero. + * Method -- j1(x): + * 1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ... + * 2. Reduce x to |x| since j1(x)=-j1(-x), and + * for x in (0,2) + * j1(x) = x/2 + x*z*R0/S0, where z = x*x; + * (precision: |j1/x - 1/2 - R0/S0 |<2**-61.51 ) + * for x in (2,inf) + * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1)) + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) + * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) + * as follow: + * cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) + * = -1/sqrt(2) * (sin(x) + cos(x)) + * (To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one.) + * + * 3 Special cases + * j1(nan)= nan + * j1(0) = 0 + * j1(inf) = 0 + * + * Method -- y1(x): + * 1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN + * 2. For x<2. + * Since + * y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x^3-...) + * therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function. + * We use the following function to approximate y1, + * y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x^2 + * where for x in [0,2] (abs err less than 2**-65.89) + * U(z) = U0[0] + U0[1]*z + ... + U0[4]*z^4 + * V(z) = 1 + v0[0]*z + ... + v0[4]*z^5 + * Note: For tiny x, 1/x dominate y1 and hence + * y1(tiny) = -2/pi/tiny, (choose tiny<2**-54) + * 3. For x>=2. + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) + * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) + * by method mentioned above. + */ + +#include "math.h" +#include "math_private.h" + +static double pone(double), qone(double); + +static const double +huge = 1e300, +one = 1.0, +invsqrtpi= 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */ +tpi = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ + /* R0/S0 on [0,2] */ +r00 = -6.25000000000000000000e-02, /* 0xBFB00000, 0x00000000 */ +r01 = 1.40705666955189706048e-03, /* 0x3F570D9F, 0x98472C61 */ +r02 = -1.59955631084035597520e-05, /* 0xBEF0C5C6, 0xBA169668 */ +r03 = 4.96727999609584448412e-08, /* 0x3E6AAAFA, 0x46CA0BD9 */ +s01 = 1.91537599538363460805e-02, /* 0x3F939D0B, 0x12637E53 */ +s02 = 1.85946785588630915560e-04, /* 0x3F285F56, 0xB9CDF664 */ +s03 = 1.17718464042623683263e-06, /* 0x3EB3BFF8, 0x333F8498 */ +s04 = 5.04636257076217042715e-09, /* 0x3E35AC88, 0xC97DFF2C */ +s05 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ + +static const double zero = 0.0; + +double +__ieee754_j1(double x) +{ + double z, s,c,ss,cc,r,u,v,y; + int32_t hx,ix; + + GET_HIGH_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x7ff00000) return one/x; + y = fabs(x); + if(ix >= 0x40000000) { /* |x| >= 2.0 */ + s = sin(y); + c = cos(y); + ss = -s-c; + cc = s-c; + if(ix<0x7fe00000) { /* make sure y+y not overflow */ + z = cos(y+y); + if ((s*c)>zero) cc = z/ss; + else ss = z/cc; + } + /* + * j1(x) = 1/sqrt(pi) * (P(1,x)*cc - Q(1,x)*ss) / sqrt(x) + * y1(x) = 1/sqrt(pi) * (P(1,x)*ss + Q(1,x)*cc) / sqrt(x) + */ + if(ix>0x48000000) z = (invsqrtpi*cc)/sqrt(y); + else { + u = pone(y); v = qone(y); + z = invsqrtpi*(u*cc-v*ss)/sqrt(y); + } + if(hx<0) return -z; + else return z; + } + if(ix<0x3e400000) { /* |x|<2**-27 */ + if(huge+x>one) return 0.5*x;/* inexact if x!=0 necessary */ + } + z = x*x; + r = z*(r00+z*(r01+z*(r02+z*r03))); + s = one+z*(s01+z*(s02+z*(s03+z*(s04+z*s05)))); + r *= x; + return(x*0.5+r/s); +} + +static const double U0[5] = { + -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */ + 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */ + -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */ + 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */ + -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */ +}; +static const double V0[5] = { + 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */ + 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */ + 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */ + 6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */ + 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */ +}; + +double +__ieee754_y1(double x) +{ + double z, s,c,ss,cc,u,v; + int32_t hx,ix,lx; + + EXTRACT_WORDS(hx,lx,x); + ix = 0x7fffffff&hx; + /* if Y1(NaN) is NaN, Y1(-inf) is NaN, Y1(inf) is 0 */ + if(ix>=0x7ff00000) return one/(x+x*x); + if((ix|lx)==0) return -one/zero; + if(hx<0) return zero/zero; + if(ix >= 0x40000000) { /* |x| >= 2.0 */ + s = sin(x); + c = cos(x); + ss = -s-c; + cc = s-c; + if(ix<0x7fe00000) { /* make sure x+x not overflow */ + z = cos(x+x); + if ((s*c)>zero) cc = z/ss; + else ss = z/cc; + } + /* y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x0)+q1(x)*cos(x0)) + * where x0 = x-3pi/4 + * Better formula: + * cos(x0) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) + * = -1/sqrt(2) * (cos(x) + sin(x)) + * To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one. + */ + if(ix>0x48000000) z = (invsqrtpi*ss)/sqrt(x); + else { + u = pone(x); v = qone(x); + z = invsqrtpi*(u*ss+v*cc)/sqrt(x); + } + return z; + } + if(ix<=0x3c900000) { /* x < 2**-54 */ + return(-tpi/x); + } + z = x*x; + u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4]))); + v = one+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4])))); + return(x*(u/v) + tpi*(__ieee754_j1(x)*__ieee754_log(x)-one/x)); +} + +/* For x >= 8, the asymptotic expansions of pone is + * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. + * We approximate pone by + * pone(x) = 1 + (R/S) + * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 + * S = 1 + ps0*s^2 + ... + ps4*s^10 + * and + * | pone(x)-1-R/S | <= 2 ** ( -60.06) + */ + +static const double pr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */ + 1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */ + 4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */ + 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */ + 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */ +}; +static const double ps8[5] = { + 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */ + 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */ + 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */ + 9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */ + 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */ +}; + +static const double pr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */ + 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */ + 6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */ + 1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */ + 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */ + 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */ +}; +static const double ps5[5] = { + 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */ + 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */ + 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */ + 7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */ + 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */ +}; + +static const double pr3[6] = { + 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */ + 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */ + 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */ + 3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */ + 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */ + 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */ +}; +static const double ps3[5] = { + 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */ + 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */ + 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */ + 8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */ + 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */ +}; + +static const double pr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */ + 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */ + 2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */ + 1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */ + 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */ + 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */ +}; +static const double ps2[5] = { + 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */ + 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */ + 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */ + 1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */ + 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */ +}; + + static double pone(double x) +{ + const double *p,*q; + double z,r,s; + int32_t ix; + GET_HIGH_WORD(ix,x); + ix &= 0x7fffffff; + if(ix>=0x40200000) {p = pr8; q= ps8;} + else if(ix>=0x40122E8B){p = pr5; q= ps5;} + else if(ix>=0x4006DB6D){p = pr3; q= ps3;} + else if(ix>=0x40000000){p = pr2; q= ps2;} + z = one/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return one+ r/s; +} + + +/* For x >= 8, the asymptotic expansions of qone is + * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. + * We approximate pone by + * qone(x) = s*(0.375 + (R/S)) + * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 + * S = 1 + qs1*s^2 + ... + qs6*s^12 + * and + * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) + */ + +static const double qr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */ + -1.62717534544589987888e+01, /* 0xC0304591, 0xA26779F7 */ + -7.59601722513950107896e+02, /* 0xC087BCD0, 0x53E4B576 */ + -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */ + -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */ +}; +static const double qs8[6] = { + 1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */ + 7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */ + 1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */ + 7.19657723683240939863e+05, /* 0x4125F653, 0x72869C19 */ + 6.66601232617776375264e+05, /* 0x412457D2, 0x7719AD5C */ + -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */ +}; + +static const double qr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */ + -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */ + -8.05644828123936029840e+00, /* 0xC0201CE6, 0xCA03AD4B */ + -1.83669607474888380239e+02, /* 0xC066F56D, 0x6CA7B9B0 */ + -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */ + -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */ +}; +static const double qs5[6] = { + 8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */ + 1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */ + 1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */ + 4.98514270910352279316e+04, /* 0x40E8576D, 0xAABAD197 */ + 2.79480751638918118260e+04, /* 0x40DB4B04, 0xCF7C364B */ + -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */ +}; + +static const double qr3[6] = { + -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */ + -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */ + -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */ + -5.78472216562783643212e+01, /* 0xC04CEC71, 0xC25D16DA */ + -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */ + -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */ +}; +static const double qs3[6] = { + 4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */ + 6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */ + 3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */ + 5.54772909720722782367e+03, /* 0x40B5ABBA, 0xA61D54A6 */ + 1.90311919338810798763e+03, /* 0x409DBC7A, 0x0DD4DF4B */ + -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */ +}; + +static const double qr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */ + -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */ + -2.75220568278187460720e+00, /* 0xC0060484, 0x69BB4EDA */ + -1.96636162643703720221e+01, /* 0xC033A9E2, 0xC168907F */ + -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */ + -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */ +}; +static const double qs2[6] = { + 2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */ + 2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */ + 7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */ + 7.39393205320467245656e+02, /* 0x40871B25, 0x48D4C029 */ + 1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */ + -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */ +}; + + static double qone(double x) +{ + const double *p,*q; + double s,r,z; + int32_t ix; + GET_HIGH_WORD(ix,x); + ix &= 0x7fffffff; + if(ix>=0x40200000) {p = qr8; q= qs8;} + else if(ix>=0x40122E8B){p = qr5; q= qs5;} + else if(ix>=0x4006DB6D){p = qr3; q= qs3;} + else if(ix>=0x40000000){p = qr2; q= qs2;} + z = one/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return (.375 + r/s)/x; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_j1f.c b/libm/upstream-freebsd/lib/msun/src/e_j1f.c new file mode 100644 index 0000000..88e2d83 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_j1f.c @@ -0,0 +1,333 @@ +/* e_j1f.c -- float version of e_j1.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +static float ponef(float), qonef(float); + +static const float +huge = 1e30, +one = 1.0, +invsqrtpi= 5.6418961287e-01, /* 0x3f106ebb */ +tpi = 6.3661974669e-01, /* 0x3f22f983 */ + /* R0/S0 on [0,2] */ +r00 = -6.2500000000e-02, /* 0xbd800000 */ +r01 = 1.4070566976e-03, /* 0x3ab86cfd */ +r02 = -1.5995563444e-05, /* 0xb7862e36 */ +r03 = 4.9672799207e-08, /* 0x335557d2 */ +s01 = 1.9153760746e-02, /* 0x3c9ce859 */ +s02 = 1.8594678841e-04, /* 0x3942fab6 */ +s03 = 1.1771846857e-06, /* 0x359dffc2 */ +s04 = 5.0463624390e-09, /* 0x31ad6446 */ +s05 = 1.2354227016e-11; /* 0x2d59567e */ + +static const float zero = 0.0; + +float +__ieee754_j1f(float x) +{ + float z, s,c,ss,cc,r,u,v,y; + int32_t hx,ix; + + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x7f800000) return one/x; + y = fabsf(x); + if(ix >= 0x40000000) { /* |x| >= 2.0 */ + s = sinf(y); + c = cosf(y); + ss = -s-c; + cc = s-c; + if(ix<0x7f000000) { /* make sure y+y not overflow */ + z = cosf(y+y); + if ((s*c)>zero) cc = z/ss; + else ss = z/cc; + } + /* + * j1(x) = 1/sqrt(pi) * (P(1,x)*cc - Q(1,x)*ss) / sqrt(x) + * y1(x) = 1/sqrt(pi) * (P(1,x)*ss + Q(1,x)*cc) / sqrt(x) + */ + if(ix>0x80000000) z = (invsqrtpi*cc)/sqrtf(y); + else { + u = ponef(y); v = qonef(y); + z = invsqrtpi*(u*cc-v*ss)/sqrtf(y); + } + if(hx<0) return -z; + else return z; + } + if(ix<0x32000000) { /* |x|<2**-27 */ + if(huge+x>one) return (float)0.5*x;/* inexact if x!=0 necessary */ + } + z = x*x; + r = z*(r00+z*(r01+z*(r02+z*r03))); + s = one+z*(s01+z*(s02+z*(s03+z*(s04+z*s05)))); + r *= x; + return(x*(float)0.5+r/s); +} + +static const float U0[5] = { + -1.9605709612e-01, /* 0xbe48c331 */ + 5.0443872809e-02, /* 0x3d4e9e3c */ + -1.9125689287e-03, /* 0xbafaaf2a */ + 2.3525259166e-05, /* 0x37c5581c */ + -9.1909917899e-08, /* 0xb3c56003 */ +}; +static const float V0[5] = { + 1.9916731864e-02, /* 0x3ca3286a */ + 2.0255257550e-04, /* 0x3954644b */ + 1.3560879779e-06, /* 0x35b602d4 */ + 6.2274145840e-09, /* 0x31d5f8eb */ + 1.6655924903e-11, /* 0x2d9281cf */ +}; + +float +__ieee754_y1f(float x) +{ + float z, s,c,ss,cc,u,v; + int32_t hx,ix; + + GET_FLOAT_WORD(hx,x); + ix = 0x7fffffff&hx; + /* if Y1(NaN) is NaN, Y1(-inf) is NaN, Y1(inf) is 0 */ + if(ix>=0x7f800000) return one/(x+x*x); + if(ix==0) return -one/zero; + if(hx<0) return zero/zero; + if(ix >= 0x40000000) { /* |x| >= 2.0 */ + s = sinf(x); + c = cosf(x); + ss = -s-c; + cc = s-c; + if(ix<0x7f000000) { /* make sure x+x not overflow */ + z = cosf(x+x); + if ((s*c)>zero) cc = z/ss; + else ss = z/cc; + } + /* y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x0)+q1(x)*cos(x0)) + * where x0 = x-3pi/4 + * Better formula: + * cos(x0) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) + * = -1/sqrt(2) * (cos(x) + sin(x)) + * To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one. + */ + if(ix>0x48000000) z = (invsqrtpi*ss)/sqrtf(x); + else { + u = ponef(x); v = qonef(x); + z = invsqrtpi*(u*ss+v*cc)/sqrtf(x); + } + return z; + } + if(ix<=0x24800000) { /* x < 2**-54 */ + return(-tpi/x); + } + z = x*x; + u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4]))); + v = one+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4])))); + return(x*(u/v) + tpi*(__ieee754_j1f(x)*__ieee754_logf(x)-one/x)); +} + +/* For x >= 8, the asymptotic expansions of pone is + * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. + * We approximate pone by + * pone(x) = 1 + (R/S) + * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 + * S = 1 + ps0*s^2 + ... + ps4*s^10 + * and + * | pone(x)-1-R/S | <= 2 ** ( -60.06) + */ + +static const float pr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + 1.1718750000e-01, /* 0x3df00000 */ + 1.3239480972e+01, /* 0x4153d4ea */ + 4.1205184937e+02, /* 0x43ce06a3 */ + 3.8747453613e+03, /* 0x45722bed */ + 7.9144794922e+03, /* 0x45f753d6 */ +}; +static const float ps8[5] = { + 1.1420736694e+02, /* 0x42e46a2c */ + 3.6509309082e+03, /* 0x45642ee5 */ + 3.6956207031e+04, /* 0x47105c35 */ + 9.7602796875e+04, /* 0x47bea166 */ + 3.0804271484e+04, /* 0x46f0a88b */ +}; + +static const float pr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.3199052094e-11, /* 0x2d68333f */ + 1.1718749255e-01, /* 0x3defffff */ + 6.8027510643e+00, /* 0x40d9b023 */ + 1.0830818176e+02, /* 0x42d89dca */ + 5.1763616943e+02, /* 0x440168b7 */ + 5.2871520996e+02, /* 0x44042dc6 */ +}; +static const float ps5[5] = { + 5.9280597687e+01, /* 0x426d1f55 */ + 9.9140142822e+02, /* 0x4477d9b1 */ + 5.3532670898e+03, /* 0x45a74a23 */ + 7.8446904297e+03, /* 0x45f52586 */ + 1.5040468750e+03, /* 0x44bc0180 */ +}; + +static const float pr3[6] = { + 3.0250391081e-09, /* 0x314fe10d */ + 1.1718686670e-01, /* 0x3defffab */ + 3.9329774380e+00, /* 0x407bb5e7 */ + 3.5119403839e+01, /* 0x420c7a45 */ + 9.1055007935e+01, /* 0x42b61c2a */ + 4.8559066772e+01, /* 0x42423c7c */ +}; +static const float ps3[5] = { + 3.4791309357e+01, /* 0x420b2a4d */ + 3.3676245117e+02, /* 0x43a86198 */ + 1.0468714600e+03, /* 0x4482dbe3 */ + 8.9081134033e+02, /* 0x445eb3ed */ + 1.0378793335e+02, /* 0x42cf936c */ +}; + +static const float pr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.0771083225e-07, /* 0x33e74ea8 */ + 1.1717621982e-01, /* 0x3deffa16 */ + 2.3685150146e+00, /* 0x401795c0 */ + 1.2242610931e+01, /* 0x4143e1bc */ + 1.7693971634e+01, /* 0x418d8d41 */ + 5.0735230446e+00, /* 0x40a25a4d */ +}; +static const float ps2[5] = { + 2.1436485291e+01, /* 0x41ab7dec */ + 1.2529022980e+02, /* 0x42fa9499 */ + 2.3227647400e+02, /* 0x436846c7 */ + 1.1767937469e+02, /* 0x42eb5bd7 */ + 8.3646392822e+00, /* 0x4105d590 */ +}; + + static float ponef(float x) +{ + const float *p,*q; + float z,r,s; + int32_t ix; + GET_FLOAT_WORD(ix,x); + ix &= 0x7fffffff; + if(ix>=0x41000000) {p = pr8; q= ps8;} + else if(ix>=0x40f71c58){p = pr5; q= ps5;} + else if(ix>=0x4036db68){p = pr3; q= ps3;} + else if(ix>=0x40000000){p = pr2; q= ps2;} + z = one/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return one+ r/s; +} + + +/* For x >= 8, the asymptotic expansions of qone is + * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. + * We approximate pone by + * qone(x) = s*(0.375 + (R/S)) + * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 + * S = 1 + qs1*s^2 + ... + qs6*s^12 + * and + * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) + */ + +static const float qr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + -1.0253906250e-01, /* 0xbdd20000 */ + -1.6271753311e+01, /* 0xc1822c8d */ + -7.5960174561e+02, /* 0xc43de683 */ + -1.1849806641e+04, /* 0xc639273a */ + -4.8438511719e+04, /* 0xc73d3683 */ +}; +static const float qs8[6] = { + 1.6139537048e+02, /* 0x43216537 */ + 7.8253862305e+03, /* 0x45f48b17 */ + 1.3387534375e+05, /* 0x4802bcd6 */ + 7.1965775000e+05, /* 0x492fb29c */ + 6.6660125000e+05, /* 0x4922be94 */ + -2.9449025000e+05, /* 0xc88fcb48 */ +}; + +static const float qr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -2.0897993405e-11, /* 0xadb7d219 */ + -1.0253904760e-01, /* 0xbdd1fffe */ + -8.0564479828e+00, /* 0xc100e736 */ + -1.8366960144e+02, /* 0xc337ab6b */ + -1.3731937256e+03, /* 0xc4aba633 */ + -2.6124443359e+03, /* 0xc523471c */ +}; +static const float qs5[6] = { + 8.1276550293e+01, /* 0x42a28d98 */ + 1.9917987061e+03, /* 0x44f8f98f */ + 1.7468484375e+04, /* 0x468878f8 */ + 4.9851425781e+04, /* 0x4742bb6d */ + 2.7948074219e+04, /* 0x46da5826 */ + -4.7191835938e+03, /* 0xc5937978 */ +}; + +static const float qr3[6] = { + -5.0783124372e-09, /* 0xb1ae7d4f */ + -1.0253783315e-01, /* 0xbdd1ff5b */ + -4.6101160049e+00, /* 0xc0938612 */ + -5.7847221375e+01, /* 0xc267638e */ + -2.2824453735e+02, /* 0xc3643e9a */ + -2.1921012878e+02, /* 0xc35b35cb */ +}; +static const float qs3[6] = { + 4.7665153503e+01, /* 0x423ea91e */ + 6.7386511230e+02, /* 0x4428775e */ + 3.3801528320e+03, /* 0x45534272 */ + 5.5477290039e+03, /* 0x45ad5dd5 */ + 1.9031191406e+03, /* 0x44ede3d0 */ + -1.3520118713e+02, /* 0xc3073381 */ +}; + +static const float qr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + -1.7838172539e-07, /* 0xb43f8932 */ + -1.0251704603e-01, /* 0xbdd1f475 */ + -2.7522056103e+00, /* 0xc0302423 */ + -1.9663616180e+01, /* 0xc19d4f16 */ + -4.2325313568e+01, /* 0xc2294d1f */ + -2.1371921539e+01, /* 0xc1aaf9b2 */ +}; +static const float qs2[6] = { + 2.9533363342e+01, /* 0x41ec4454 */ + 2.5298155212e+02, /* 0x437cfb47 */ + 7.5750280762e+02, /* 0x443d602e */ + 7.3939318848e+02, /* 0x4438d92a */ + 1.5594900513e+02, /* 0x431bf2f2 */ + -4.9594988823e+00, /* 0xc09eb437 */ +}; + + static float qonef(float x) +{ + const float *p,*q; + float s,r,z; + int32_t ix; + GET_FLOAT_WORD(ix,x); + ix &= 0x7fffffff; + if(ix>=0x40200000) {p = qr8; q= qs8;} + else if(ix>=0x40f71c58){p = qr5; q= qs5;} + else if(ix>=0x4036db68){p = qr3; q= qs3;} + else if(ix>=0x40000000){p = qr2; q= qs2;} + z = one/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return ((float).375 + r/s)/x; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_jn.c b/libm/upstream-freebsd/lib/msun/src/e_jn.c new file mode 100644 index 0000000..8b0bc62 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_jn.c @@ -0,0 +1,270 @@ + +/* @(#)e_jn.c 1.4 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * __ieee754_jn(n, x), __ieee754_yn(n, x) + * floating point Bessel's function of the 1st and 2nd kind + * of order n + * + * Special cases: + * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal; + * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal. + * Note 2. About jn(n,x), yn(n,x) + * For n=0, j0(x) is called, + * for n=1, j1(x) is called, + * for n<x, forward recursion us used starting + * from values of j0(x) and j1(x). + * for n>x, a continued fraction approximation to + * j(n,x)/j(n-1,x) is evaluated and then backward + * recursion is used starting from a supposed value + * for j(n,x). The resulting value of j(0,x) is + * compared with the actual value to correct the + * supposed value of j(n,x). + * + * yn(n,x) is similar in all respects, except + * that forward recursion is used for all + * values of n>1. + * + */ + +#include "math.h" +#include "math_private.h" + +static const double +invsqrtpi= 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */ +two = 2.00000000000000000000e+00, /* 0x40000000, 0x00000000 */ +one = 1.00000000000000000000e+00; /* 0x3FF00000, 0x00000000 */ + +static const double zero = 0.00000000000000000000e+00; + +double +__ieee754_jn(int n, double x) +{ + int32_t i,hx,ix,lx, sgn; + double a, b, temp, di; + double z, w; + + /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x) + * Thus, J(-n,x) = J(n,-x) + */ + EXTRACT_WORDS(hx,lx,x); + ix = 0x7fffffff&hx; + /* if J(n,NaN) is NaN */ + if((ix|((u_int32_t)(lx|-lx))>>31)>0x7ff00000) return x+x; + if(n<0){ + n = -n; + x = -x; + hx ^= 0x80000000; + } + if(n==0) return(__ieee754_j0(x)); + if(n==1) return(__ieee754_j1(x)); + sgn = (n&1)&(hx>>31); /* even n -- 0, odd n -- sign(x) */ + x = fabs(x); + if((ix|lx)==0||ix>=0x7ff00000) /* if x is 0 or inf */ + b = zero; + else if((double)n<=x) { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + if(ix>=0x52D00000) { /* x > 2**302 */ + /* (x >> n**2) + * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Let s=sin(x), c=cos(x), + * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + * + * n sin(xn)*sqt2 cos(xn)*sqt2 + * ---------------------------------- + * 0 s-c c+s + * 1 -s-c -c+s + * 2 -s+c -c-s + * 3 s+c c-s + */ + switch(n&3) { + case 0: temp = cos(x)+sin(x); break; + case 1: temp = -cos(x)+sin(x); break; + case 2: temp = -cos(x)-sin(x); break; + case 3: temp = cos(x)-sin(x); break; + } + b = invsqrtpi*temp/sqrt(x); + } else { + a = __ieee754_j0(x); + b = __ieee754_j1(x); + for(i=1;i<n;i++){ + temp = b; + b = b*((double)(i+i)/x) - a; /* avoid underflow */ + a = temp; + } + } + } else { + if(ix<0x3e100000) { /* x < 2**-29 */ + /* x is tiny, return the first Taylor expansion of J(n,x) + * J(n,x) = 1/n!*(x/2)^n - ... + */ + if(n>33) /* underflow */ + b = zero; + else { + temp = x*0.5; b = temp; + for (a=one,i=2;i<=n;i++) { + a *= (double)i; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + } + b = b/a; + } + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + double t,v; + double q0,q1,h,tmp; int32_t k,m; + w = (n+n)/(double)x; h = 2.0/(double)x; + q0 = w; z = w+h; q1 = w*z - 1.0; k=1; + while(q1<1.0e9) { + k += 1; z += h; + tmp = z*q1 - q0; + q0 = q1; + q1 = tmp; + } + m = n+n; + for(t=zero, i = 2*(n+k); i>=m; i -= 2) t = one/(i/x-t); + a = t; + b = one; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = n; + v = two/x; + tmp = tmp*__ieee754_log(fabs(v*tmp)); + if(tmp<7.09782712893383973096e+02) { + for(i=n-1,di=(double)(i+i);i>0;i--){ + temp = b; + b *= di; + b = b/x - a; + a = temp; + di -= two; + } + } else { + for(i=n-1,di=(double)(i+i);i>0;i--){ + temp = b; + b *= di; + b = b/x - a; + a = temp; + di -= two; + /* scale b to avoid spurious overflow */ + if(b>1e100) { + a /= b; + t /= b; + b = one; + } + } + } + z = __ieee754_j0(x); + w = __ieee754_j1(x); + if (fabs(z) >= fabs(w)) + b = (t*z/b); + else + b = (t*w/a); + } + } + if(sgn==1) return -b; else return b; +} + +double +__ieee754_yn(int n, double x) +{ + int32_t i,hx,ix,lx; + int32_t sign; + double a, b, temp; + + EXTRACT_WORDS(hx,lx,x); + ix = 0x7fffffff&hx; + /* if Y(n,NaN) is NaN */ + if((ix|((u_int32_t)(lx|-lx))>>31)>0x7ff00000) return x+x; + if((ix|lx)==0) return -one/zero; + if(hx<0) return zero/zero; + sign = 1; + if(n<0){ + n = -n; + sign = 1 - ((n&1)<<1); + } + if(n==0) return(__ieee754_y0(x)); + if(n==1) return(sign*__ieee754_y1(x)); + if(ix==0x7ff00000) return zero; + if(ix>=0x52D00000) { /* x > 2**302 */ + /* (x >> n**2) + * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Let s=sin(x), c=cos(x), + * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + * + * n sin(xn)*sqt2 cos(xn)*sqt2 + * ---------------------------------- + * 0 s-c c+s + * 1 -s-c -c+s + * 2 -s+c -c-s + * 3 s+c c-s + */ + switch(n&3) { + case 0: temp = sin(x)-cos(x); break; + case 1: temp = -sin(x)-cos(x); break; + case 2: temp = -sin(x)+cos(x); break; + case 3: temp = sin(x)+cos(x); break; + } + b = invsqrtpi*temp/sqrt(x); + } else { + u_int32_t high; + a = __ieee754_y0(x); + b = __ieee754_y1(x); + /* quit if b is -inf */ + GET_HIGH_WORD(high,b); + for(i=1;i<n&&high!=0xfff00000;i++){ + temp = b; + b = ((double)(i+i)/x)*b - a; + GET_HIGH_WORD(high,b); + a = temp; + } + } + if(sign>0) return b; else return -b; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_jnf.c b/libm/upstream-freebsd/lib/msun/src/e_jnf.c new file mode 100644 index 0000000..f564aec --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_jnf.c @@ -0,0 +1,199 @@ +/* e_jnf.c -- float version of e_jn.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +static const float +two = 2.0000000000e+00, /* 0x40000000 */ +one = 1.0000000000e+00; /* 0x3F800000 */ + +static const float zero = 0.0000000000e+00; + +float +__ieee754_jnf(int n, float x) +{ + int32_t i,hx,ix, sgn; + float a, b, temp, di; + float z, w; + + /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x) + * Thus, J(-n,x) = J(n,-x) + */ + GET_FLOAT_WORD(hx,x); + ix = 0x7fffffff&hx; + /* if J(n,NaN) is NaN */ + if(ix>0x7f800000) return x+x; + if(n<0){ + n = -n; + x = -x; + hx ^= 0x80000000; + } + if(n==0) return(__ieee754_j0f(x)); + if(n==1) return(__ieee754_j1f(x)); + sgn = (n&1)&(hx>>31); /* even n -- 0, odd n -- sign(x) */ + x = fabsf(x); + if(ix==0||ix>=0x7f800000) /* if x is 0 or inf */ + b = zero; + else if((float)n<=x) { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + a = __ieee754_j0f(x); + b = __ieee754_j1f(x); + for(i=1;i<n;i++){ + temp = b; + b = b*((float)(i+i)/x) - a; /* avoid underflow */ + a = temp; + } + } else { + if(ix<0x30800000) { /* x < 2**-29 */ + /* x is tiny, return the first Taylor expansion of J(n,x) + * J(n,x) = 1/n!*(x/2)^n - ... + */ + if(n>33) /* underflow */ + b = zero; + else { + temp = x*(float)0.5; b = temp; + for (a=one,i=2;i<=n;i++) { + a *= (float)i; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + } + b = b/a; + } + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + float t,v; + float q0,q1,h,tmp; int32_t k,m; + w = (n+n)/(float)x; h = (float)2.0/(float)x; + q0 = w; z = w+h; q1 = w*z - (float)1.0; k=1; + while(q1<(float)1.0e9) { + k += 1; z += h; + tmp = z*q1 - q0; + q0 = q1; + q1 = tmp; + } + m = n+n; + for(t=zero, i = 2*(n+k); i>=m; i -= 2) t = one/(i/x-t); + a = t; + b = one; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = n; + v = two/x; + tmp = tmp*__ieee754_logf(fabsf(v*tmp)); + if(tmp<(float)8.8721679688e+01) { + for(i=n-1,di=(float)(i+i);i>0;i--){ + temp = b; + b *= di; + b = b/x - a; + a = temp; + di -= two; + } + } else { + for(i=n-1,di=(float)(i+i);i>0;i--){ + temp = b; + b *= di; + b = b/x - a; + a = temp; + di -= two; + /* scale b to avoid spurious overflow */ + if(b>(float)1e10) { + a /= b; + t /= b; + b = one; + } + } + } + z = __ieee754_j0f(x); + w = __ieee754_j1f(x); + if (fabsf(z) >= fabsf(w)) + b = (t*z/b); + else + b = (t*w/a); + } + } + if(sgn==1) return -b; else return b; +} + +float +__ieee754_ynf(int n, float x) +{ + int32_t i,hx,ix,ib; + int32_t sign; + float a, b, temp; + + GET_FLOAT_WORD(hx,x); + ix = 0x7fffffff&hx; + /* if Y(n,NaN) is NaN */ + if(ix>0x7f800000) return x+x; + if(ix==0) return -one/zero; + if(hx<0) return zero/zero; + sign = 1; + if(n<0){ + n = -n; + sign = 1 - ((n&1)<<1); + } + if(n==0) return(__ieee754_y0f(x)); + if(n==1) return(sign*__ieee754_y1f(x)); + if(ix==0x7f800000) return zero; + + a = __ieee754_y0f(x); + b = __ieee754_y1f(x); + /* quit if b is -inf */ + GET_FLOAT_WORD(ib,b); + for(i=1;i<n&&ib!=0xff800000;i++){ + temp = b; + b = ((float)(i+i)/x)*b - a; + GET_FLOAT_WORD(ib,b); + a = temp; + } + if(sign>0) return b; else return -b; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_lgamma.c b/libm/upstream-freebsd/lib/msun/src/e_lgamma.c new file mode 100644 index 0000000..4674d9b --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_lgamma.c @@ -0,0 +1,33 @@ + +/* @(#)e_lgamma.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* __ieee754_lgamma(x) + * Return the logarithm of the Gamma function of x. + * + * Method: call __ieee754_lgamma_r + */ + +#include "math.h" +#include "math_private.h" + +extern int signgam; + +double +__ieee754_lgamma(double x) +{ + return __ieee754_lgamma_r(x,&signgam); +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_lgamma_r.c b/libm/upstream-freebsd/lib/msun/src/e_lgamma_r.c new file mode 100644 index 0000000..1cff592 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_lgamma_r.c @@ -0,0 +1,297 @@ + +/* @(#)e_lgamma_r.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* __ieee754_lgamma_r(x, signgamp) + * Reentrant version of the logarithm of the Gamma function + * with user provide pointer for the sign of Gamma(x). + * + * Method: + * 1. Argument Reduction for 0 < x <= 8 + * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may + * reduce x to a number in [1.5,2.5] by + * lgamma(1+s) = log(s) + lgamma(s) + * for example, + * lgamma(7.3) = log(6.3) + lgamma(6.3) + * = log(6.3*5.3) + lgamma(5.3) + * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) + * 2. Polynomial approximation of lgamma around its + * minimun ymin=1.461632144968362245 to maintain monotonicity. + * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use + * Let z = x-ymin; + * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) + * where + * poly(z) is a 14 degree polynomial. + * 2. Rational approximation in the primary interval [2,3] + * We use the following approximation: + * s = x-2.0; + * lgamma(x) = 0.5*s + s*P(s)/Q(s) + * with accuracy + * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71 + * Our algorithms are based on the following observation + * + * zeta(2)-1 2 zeta(3)-1 3 + * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... + * 2 3 + * + * where Euler = 0.5771... is the Euler constant, which is very + * close to 0.5. + * + * 3. For x>=8, we have + * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... + * (better formula: + * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) + * Let z = 1/x, then we approximation + * f(z) = lgamma(x) - (x-0.5)(log(x)-1) + * by + * 3 5 11 + * w = w0 + w1*z + w2*z + w3*z + ... + w6*z + * where + * |w - f(z)| < 2**-58.74 + * + * 4. For negative x, since (G is gamma function) + * -x*G(-x)*G(x) = pi/sin(pi*x), + * we have + * G(x) = pi/(sin(pi*x)*(-x)*G(-x)) + * since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0 + * Hence, for x<0, signgam = sign(sin(pi*x)) and + * lgamma(x) = log(|Gamma(x)|) + * = log(pi/(|x*sin(pi*x)|)) - lgamma(-x); + * Note: one should avoid compute pi*(-x) directly in the + * computation of sin(pi*(-x)). + * + * 5. Special Cases + * lgamma(2+s) ~ s*(1-Euler) for tiny s + * lgamma(1) = lgamma(2) = 0 + * lgamma(x) ~ -log(|x|) for tiny x + * lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero + * lgamma(inf) = inf + * lgamma(-inf) = inf (bug for bug compatible with C99!?) + * + */ + +#include "math.h" +#include "math_private.h" + +static const double +two52= 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */ +half= 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */ +one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */ +pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */ +a0 = 7.72156649015328655494e-02, /* 0x3FB3C467, 0xE37DB0C8 */ +a1 = 3.22467033424113591611e-01, /* 0x3FD4A34C, 0xC4A60FAD */ +a2 = 6.73523010531292681824e-02, /* 0x3FB13E00, 0x1A5562A7 */ +a3 = 2.05808084325167332806e-02, /* 0x3F951322, 0xAC92547B */ +a4 = 7.38555086081402883957e-03, /* 0x3F7E404F, 0xB68FEFE8 */ +a5 = 2.89051383673415629091e-03, /* 0x3F67ADD8, 0xCCB7926B */ +a6 = 1.19270763183362067845e-03, /* 0x3F538A94, 0x116F3F5D */ +a7 = 5.10069792153511336608e-04, /* 0x3F40B6C6, 0x89B99C00 */ +a8 = 2.20862790713908385557e-04, /* 0x3F2CF2EC, 0xED10E54D */ +a9 = 1.08011567247583939954e-04, /* 0x3F1C5088, 0x987DFB07 */ +a10 = 2.52144565451257326939e-05, /* 0x3EFA7074, 0x428CFA52 */ +a11 = 4.48640949618915160150e-05, /* 0x3F07858E, 0x90A45837 */ +tc = 1.46163214496836224576e+00, /* 0x3FF762D8, 0x6356BE3F */ +tf = -1.21486290535849611461e-01, /* 0xBFBF19B9, 0xBCC38A42 */ +/* tt = -(tail of tf) */ +tt = -3.63867699703950536541e-18, /* 0xBC50C7CA, 0xA48A971F */ +t0 = 4.83836122723810047042e-01, /* 0x3FDEF72B, 0xC8EE38A2 */ +t1 = -1.47587722994593911752e-01, /* 0xBFC2E427, 0x8DC6C509 */ +t2 = 6.46249402391333854778e-02, /* 0x3FB08B42, 0x94D5419B */ +t3 = -3.27885410759859649565e-02, /* 0xBFA0C9A8, 0xDF35B713 */ +t4 = 1.79706750811820387126e-02, /* 0x3F9266E7, 0x970AF9EC */ +t5 = -1.03142241298341437450e-02, /* 0xBF851F9F, 0xBA91EC6A */ +t6 = 6.10053870246291332635e-03, /* 0x3F78FCE0, 0xE370E344 */ +t7 = -3.68452016781138256760e-03, /* 0xBF6E2EFF, 0xB3E914D7 */ +t8 = 2.25964780900612472250e-03, /* 0x3F6282D3, 0x2E15C915 */ +t9 = -1.40346469989232843813e-03, /* 0xBF56FE8E, 0xBF2D1AF1 */ +t10 = 8.81081882437654011382e-04, /* 0x3F4CDF0C, 0xEF61A8E9 */ +t11 = -5.38595305356740546715e-04, /* 0xBF41A610, 0x9C73E0EC */ +t12 = 3.15632070903625950361e-04, /* 0x3F34AF6D, 0x6C0EBBF7 */ +t13 = -3.12754168375120860518e-04, /* 0xBF347F24, 0xECC38C38 */ +t14 = 3.35529192635519073543e-04, /* 0x3F35FD3E, 0xE8C2D3F4 */ +u0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */ +u1 = 6.32827064025093366517e-01, /* 0x3FE4401E, 0x8B005DFF */ +u2 = 1.45492250137234768737e+00, /* 0x3FF7475C, 0xD119BD6F */ +u3 = 9.77717527963372745603e-01, /* 0x3FEF4976, 0x44EA8450 */ +u4 = 2.28963728064692451092e-01, /* 0x3FCD4EAE, 0xF6010924 */ +u5 = 1.33810918536787660377e-02, /* 0x3F8B678B, 0xBF2BAB09 */ +v1 = 2.45597793713041134822e+00, /* 0x4003A5D7, 0xC2BD619C */ +v2 = 2.12848976379893395361e+00, /* 0x40010725, 0xA42B18F5 */ +v3 = 7.69285150456672783825e-01, /* 0x3FE89DFB, 0xE45050AF */ +v4 = 1.04222645593369134254e-01, /* 0x3FBAAE55, 0xD6537C88 */ +v5 = 3.21709242282423911810e-03, /* 0x3F6A5ABB, 0x57D0CF61 */ +s0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */ +s1 = 2.14982415960608852501e-01, /* 0x3FCB848B, 0x36E20878 */ +s2 = 3.25778796408930981787e-01, /* 0x3FD4D98F, 0x4F139F59 */ +s3 = 1.46350472652464452805e-01, /* 0x3FC2BB9C, 0xBEE5F2F7 */ +s4 = 2.66422703033638609560e-02, /* 0x3F9B481C, 0x7E939961 */ +s5 = 1.84028451407337715652e-03, /* 0x3F5E26B6, 0x7368F239 */ +s6 = 3.19475326584100867617e-05, /* 0x3F00BFEC, 0xDD17E945 */ +r1 = 1.39200533467621045958e+00, /* 0x3FF645A7, 0x62C4AB74 */ +r2 = 7.21935547567138069525e-01, /* 0x3FE71A18, 0x93D3DCDC */ +r3 = 1.71933865632803078993e-01, /* 0x3FC601ED, 0xCCFBDF27 */ +r4 = 1.86459191715652901344e-02, /* 0x3F9317EA, 0x742ED475 */ +r5 = 7.77942496381893596434e-04, /* 0x3F497DDA, 0xCA41A95B */ +r6 = 7.32668430744625636189e-06, /* 0x3EDEBAF7, 0xA5B38140 */ +w0 = 4.18938533204672725052e-01, /* 0x3FDACFE3, 0x90C97D69 */ +w1 = 8.33333333333329678849e-02, /* 0x3FB55555, 0x5555553B */ +w2 = -2.77777777728775536470e-03, /* 0xBF66C16C, 0x16B02E5C */ +w3 = 7.93650558643019558500e-04, /* 0x3F4A019F, 0x98CF38B6 */ +w4 = -5.95187557450339963135e-04, /* 0xBF4380CB, 0x8C0FE741 */ +w5 = 8.36339918996282139126e-04, /* 0x3F4B67BA, 0x4CDAD5D1 */ +w6 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ + +static const double zero= 0.00000000000000000000e+00; + + static double sin_pi(double x) +{ + double y,z; + int n,ix; + + GET_HIGH_WORD(ix,x); + ix &= 0x7fffffff; + + if(ix<0x3fd00000) return __kernel_sin(pi*x,zero,0); + y = -x; /* x is assume negative */ + + /* + * argument reduction, make sure inexact flag not raised if input + * is an integer + */ + z = floor(y); + if(z!=y) { /* inexact anyway */ + y *= 0.5; + y = 2.0*(y - floor(y)); /* y = |x| mod 2.0 */ + n = (int) (y*4.0); + } else { + if(ix>=0x43400000) { + y = zero; n = 0; /* y must be even */ + } else { + if(ix<0x43300000) z = y+two52; /* exact */ + GET_LOW_WORD(n,z); + n &= 1; + y = n; + n<<= 2; + } + } + switch (n) { + case 0: y = __kernel_sin(pi*y,zero,0); break; + case 1: + case 2: y = __kernel_cos(pi*(0.5-y),zero); break; + case 3: + case 4: y = __kernel_sin(pi*(one-y),zero,0); break; + case 5: + case 6: y = -__kernel_cos(pi*(y-1.5),zero); break; + default: y = __kernel_sin(pi*(y-2.0),zero,0); break; + } + return -y; +} + + +double +__ieee754_lgamma_r(double x, int *signgamp) +{ + double t,y,z,nadj,p,p1,p2,p3,q,r,w; + int32_t hx; + int i,lx,ix; + + EXTRACT_WORDS(hx,lx,x); + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + *signgamp = 1; + ix = hx&0x7fffffff; + if(ix>=0x7ff00000) return x*x; + if((ix|lx)==0) return one/zero; + if(ix<0x3b900000) { /* |x|<2**-70, return -log(|x|) */ + if(hx<0) { + *signgamp = -1; + return -__ieee754_log(-x); + } else return -__ieee754_log(x); + } + if(hx<0) { + if(ix>=0x43300000) /* |x|>=2**52, must be -integer */ + return one/zero; + t = sin_pi(x); + if(t==zero) return one/zero; /* -integer */ + nadj = __ieee754_log(pi/fabs(t*x)); + if(t<zero) *signgamp = -1; + x = -x; + } + + /* purge off 1 and 2 */ + if((((ix-0x3ff00000)|lx)==0)||(((ix-0x40000000)|lx)==0)) r = 0; + /* for x < 2.0 */ + else if(ix<0x40000000) { + if(ix<=0x3feccccc) { /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -__ieee754_log(x); + if(ix>=0x3FE76944) {y = one-x; i= 0;} + else if(ix>=0x3FCDA661) {y= x-(tc-one); i=1;} + else {y = x; i=2;} + } else { + r = zero; + if(ix>=0x3FFBB4C3) {y=2.0-x;i=0;} /* [1.7316,2] */ + else if(ix>=0x3FF3B4C4) {y=x-tc;i=1;} /* [1.23,1.73] */ + else {y=x-one;i=2;} + } + switch(i) { + case 0: + z = y*y; + p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10)))); + p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11))))); + p = y*p1+p2; + r += (p-0.5*y); break; + case 1: + z = y*y; + w = z*y; + p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12))); /* parallel comp */ + p2 = t1+w*(t4+w*(t7+w*(t10+w*t13))); + p3 = t2+w*(t5+w*(t8+w*(t11+w*t14))); + p = z*p1-(tt-w*(p2+y*p3)); + r += (tf + p); break; + case 2: + p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5))))); + p2 = one+y*(v1+y*(v2+y*(v3+y*(v4+y*v5)))); + r += (-0.5*y + p1/p2); + } + } + else if(ix<0x40200000) { /* x < 8.0 */ + i = (int)x; + y = x-(double)i; + p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6)))))); + q = one+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6))))); + r = half*y+p/q; + z = one; /* lgamma(1+s) = log(s) + lgamma(s) */ + switch(i) { + case 7: z *= (y+6.0); /* FALLTHRU */ + case 6: z *= (y+5.0); /* FALLTHRU */ + case 5: z *= (y+4.0); /* FALLTHRU */ + case 4: z *= (y+3.0); /* FALLTHRU */ + case 3: z *= (y+2.0); /* FALLTHRU */ + r += __ieee754_log(z); break; + } + /* 8.0 <= x < 2**58 */ + } else if (ix < 0x43900000) { + t = __ieee754_log(x); + z = one/x; + y = z*z; + w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6))))); + r = (x-half)*(t-one)+w; + } else + /* 2**58 <= x <= inf */ + r = x*(__ieee754_log(x)-one); + if(hx<0) r = nadj - r; + return r; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_lgammaf.c b/libm/upstream-freebsd/lib/msun/src/e_lgammaf.c new file mode 100644 index 0000000..1e2c552 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_lgammaf.c @@ -0,0 +1,34 @@ +/* e_lgammaf.c -- float version of e_lgamma.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* __ieee754_lgammaf(x) + * Return the logarithm of the Gamma function of x. + * + * Method: call __ieee754_lgammaf_r + */ + +#include "math.h" +#include "math_private.h" + +extern int signgam; + +float +__ieee754_lgammaf(float x) +{ + return __ieee754_lgammaf_r(x,&signgam); +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_lgammaf_r.c b/libm/upstream-freebsd/lib/msun/src/e_lgammaf_r.c new file mode 100644 index 0000000..e2d90ef --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_lgammaf_r.c @@ -0,0 +1,230 @@ +/* e_lgammaf_r.c -- float version of e_lgamma_r.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +static const float +two23= 8.3886080000e+06, /* 0x4b000000 */ +half= 5.0000000000e-01, /* 0x3f000000 */ +one = 1.0000000000e+00, /* 0x3f800000 */ +pi = 3.1415927410e+00, /* 0x40490fdb */ +a0 = 7.7215664089e-02, /* 0x3d9e233f */ +a1 = 3.2246702909e-01, /* 0x3ea51a66 */ +a2 = 6.7352302372e-02, /* 0x3d89f001 */ +a3 = 2.0580807701e-02, /* 0x3ca89915 */ +a4 = 7.3855509982e-03, /* 0x3bf2027e */ +a5 = 2.8905137442e-03, /* 0x3b3d6ec6 */ +a6 = 1.1927076848e-03, /* 0x3a9c54a1 */ +a7 = 5.1006977446e-04, /* 0x3a05b634 */ +a8 = 2.2086278477e-04, /* 0x39679767 */ +a9 = 1.0801156895e-04, /* 0x38e28445 */ +a10 = 2.5214456400e-05, /* 0x37d383a2 */ +a11 = 4.4864096708e-05, /* 0x383c2c75 */ +tc = 1.4616321325e+00, /* 0x3fbb16c3 */ +tf = -1.2148628384e-01, /* 0xbdf8cdcd */ +/* tt = -(tail of tf) */ +tt = 6.6971006518e-09, /* 0x31e61c52 */ +t0 = 4.8383611441e-01, /* 0x3ef7b95e */ +t1 = -1.4758771658e-01, /* 0xbe17213c */ +t2 = 6.4624942839e-02, /* 0x3d845a15 */ +t3 = -3.2788541168e-02, /* 0xbd064d47 */ +t4 = 1.7970675603e-02, /* 0x3c93373d */ +t5 = -1.0314224288e-02, /* 0xbc28fcfe */ +t6 = 6.1005386524e-03, /* 0x3bc7e707 */ +t7 = -3.6845202558e-03, /* 0xbb7177fe */ +t8 = 2.2596477065e-03, /* 0x3b141699 */ +t9 = -1.4034647029e-03, /* 0xbab7f476 */ +t10 = 8.8108185446e-04, /* 0x3a66f867 */ +t11 = -5.3859531181e-04, /* 0xba0d3085 */ +t12 = 3.1563205994e-04, /* 0x39a57b6b */ +t13 = -3.1275415677e-04, /* 0xb9a3f927 */ +t14 = 3.3552918467e-04, /* 0x39afe9f7 */ +u0 = -7.7215664089e-02, /* 0xbd9e233f */ +u1 = 6.3282704353e-01, /* 0x3f2200f4 */ +u2 = 1.4549225569e+00, /* 0x3fba3ae7 */ +u3 = 9.7771751881e-01, /* 0x3f7a4bb2 */ +u4 = 2.2896373272e-01, /* 0x3e6a7578 */ +u5 = 1.3381091878e-02, /* 0x3c5b3c5e */ +v1 = 2.4559779167e+00, /* 0x401d2ebe */ +v2 = 2.1284897327e+00, /* 0x4008392d */ +v3 = 7.6928514242e-01, /* 0x3f44efdf */ +v4 = 1.0422264785e-01, /* 0x3dd572af */ +v5 = 3.2170924824e-03, /* 0x3b52d5db */ +s0 = -7.7215664089e-02, /* 0xbd9e233f */ +s1 = 2.1498242021e-01, /* 0x3e5c245a */ +s2 = 3.2577878237e-01, /* 0x3ea6cc7a */ +s3 = 1.4635047317e-01, /* 0x3e15dce6 */ +s4 = 2.6642270386e-02, /* 0x3cda40e4 */ +s5 = 1.8402845599e-03, /* 0x3af135b4 */ +s6 = 3.1947532989e-05, /* 0x3805ff67 */ +r1 = 1.3920053244e+00, /* 0x3fb22d3b */ +r2 = 7.2193557024e-01, /* 0x3f38d0c5 */ +r3 = 1.7193385959e-01, /* 0x3e300f6e */ +r4 = 1.8645919859e-02, /* 0x3c98bf54 */ +r5 = 7.7794247773e-04, /* 0x3a4beed6 */ +r6 = 7.3266842264e-06, /* 0x36f5d7bd */ +w0 = 4.1893854737e-01, /* 0x3ed67f1d */ +w1 = 8.3333335817e-02, /* 0x3daaaaab */ +w2 = -2.7777778450e-03, /* 0xbb360b61 */ +w3 = 7.9365057172e-04, /* 0x3a500cfd */ +w4 = -5.9518753551e-04, /* 0xba1c065c */ +w5 = 8.3633989561e-04, /* 0x3a5b3dd2 */ +w6 = -1.6309292987e-03; /* 0xbad5c4e8 */ + +static const float zero= 0.0000000000e+00; + + static float sin_pif(float x) +{ + float y,z; + int n,ix; + + GET_FLOAT_WORD(ix,x); + ix &= 0x7fffffff; + + if(ix<0x3e800000) return __kernel_sindf(pi*x); + y = -x; /* x is assume negative */ + + /* + * argument reduction, make sure inexact flag not raised if input + * is an integer + */ + z = floorf(y); + if(z!=y) { /* inexact anyway */ + y *= (float)0.5; + y = (float)2.0*(y - floorf(y)); /* y = |x| mod 2.0 */ + n = (int) (y*(float)4.0); + } else { + if(ix>=0x4b800000) { + y = zero; n = 0; /* y must be even */ + } else { + if(ix<0x4b000000) z = y+two23; /* exact */ + GET_FLOAT_WORD(n,z); + n &= 1; + y = n; + n<<= 2; + } + } + switch (n) { + case 0: y = __kernel_sindf(pi*y); break; + case 1: + case 2: y = __kernel_cosdf(pi*((float)0.5-y)); break; + case 3: + case 4: y = __kernel_sindf(pi*(one-y)); break; + case 5: + case 6: y = -__kernel_cosdf(pi*(y-(float)1.5)); break; + default: y = __kernel_sindf(pi*(y-(float)2.0)); break; + } + return -y; +} + + +float +__ieee754_lgammaf_r(float x, int *signgamp) +{ + float t,y,z,nadj,p,p1,p2,p3,q,r,w; + int32_t hx; + int i,ix; + + GET_FLOAT_WORD(hx,x); + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + *signgamp = 1; + ix = hx&0x7fffffff; + if(ix>=0x7f800000) return x*x; + if(ix==0) return one/zero; + if(ix<0x35000000) { /* |x|<2**-21, return -log(|x|) */ + if(hx<0) { + *signgamp = -1; + return -__ieee754_logf(-x); + } else return -__ieee754_logf(x); + } + if(hx<0) { + if(ix>=0x4b000000) /* |x|>=2**23, must be -integer */ + return one/zero; + t = sin_pif(x); + if(t==zero) return one/zero; /* -integer */ + nadj = __ieee754_logf(pi/fabsf(t*x)); + if(t<zero) *signgamp = -1; + x = -x; + } + + /* purge off 1 and 2 */ + if (ix==0x3f800000||ix==0x40000000) r = 0; + /* for x < 2.0 */ + else if(ix<0x40000000) { + if(ix<=0x3f666666) { /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -__ieee754_logf(x); + if(ix>=0x3f3b4a20) {y = one-x; i= 0;} + else if(ix>=0x3e6d3308) {y= x-(tc-one); i=1;} + else {y = x; i=2;} + } else { + r = zero; + if(ix>=0x3fdda618) {y=(float)2.0-x;i=0;} /* [1.7316,2] */ + else if(ix>=0x3F9da620) {y=x-tc;i=1;} /* [1.23,1.73] */ + else {y=x-one;i=2;} + } + switch(i) { + case 0: + z = y*y; + p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10)))); + p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11))))); + p = y*p1+p2; + r += (p-(float)0.5*y); break; + case 1: + z = y*y; + w = z*y; + p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12))); /* parallel comp */ + p2 = t1+w*(t4+w*(t7+w*(t10+w*t13))); + p3 = t2+w*(t5+w*(t8+w*(t11+w*t14))); + p = z*p1-(tt-w*(p2+y*p3)); + r += (tf + p); break; + case 2: + p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5))))); + p2 = one+y*(v1+y*(v2+y*(v3+y*(v4+y*v5)))); + r += (-(float)0.5*y + p1/p2); + } + } + else if(ix<0x41000000) { /* x < 8.0 */ + i = (int)x; + y = x-(float)i; + p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6)))))); + q = one+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6))))); + r = half*y+p/q; + z = one; /* lgamma(1+s) = log(s) + lgamma(s) */ + switch(i) { + case 7: z *= (y+(float)6.0); /* FALLTHRU */ + case 6: z *= (y+(float)5.0); /* FALLTHRU */ + case 5: z *= (y+(float)4.0); /* FALLTHRU */ + case 4: z *= (y+(float)3.0); /* FALLTHRU */ + case 3: z *= (y+(float)2.0); /* FALLTHRU */ + r += __ieee754_logf(z); break; + } + /* 8.0 <= x < 2**58 */ + } else if (ix < 0x5c800000) { + t = __ieee754_logf(x); + z = one/x; + y = z*z; + w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6))))); + r = (x-half)*(t-one)+w; + } else + /* 2**58 <= x <= inf */ + r = x*(__ieee754_logf(x)-one); + if(hx<0) r = nadj - r; + return r; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_log.c b/libm/upstream-freebsd/lib/msun/src/e_log.c new file mode 100644 index 0000000..204fb48 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_log.c @@ -0,0 +1,140 @@ + +/* @(#)e_log.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* __ieee754_log(x) + * Return the logrithm of x + * + * Method : + * 1. Argument Reduction: find k and f such that + * x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * 2. Approximation of log(1+f). + * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) + * = 2s + 2/3 s**3 + 2/5 s**5 + ....., + * = 2s + s*R + * We use a special Reme algorithm on [0,0.1716] to generate + * a polynomial of degree 14 to approximate R The maximum error + * of this polynomial approximation is bounded by 2**-58.45. In + * other words, + * 2 4 6 8 10 12 14 + * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s + * (the values of Lg1 to Lg7 are listed in the program) + * and + * | 2 14 | -58.45 + * | Lg1*s +...+Lg7*s - R(z) | <= 2 + * | | + * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. + * In order to guarantee error in log below 1ulp, we compute log + * by + * log(1+f) = f - s*(f - R) (if f is not too large) + * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy) + * + * 3. Finally, log(x) = k*ln2 + log(1+f). + * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) + * Here ln2 is split into two floating point number: + * ln2_hi + ln2_lo, + * where n*ln2_hi is always exact for |n| < 2000. + * + * Special cases: + * log(x) is NaN with signal if x < 0 (including -INF) ; + * log(+INF) is +INF; log(0) is -INF with signal; + * log(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "math.h" +#include "math_private.h" + +static const double +ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */ +ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */ +two54 = 1.80143985094819840000e+16, /* 43500000 00000000 */ +Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ +Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ +Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ +Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ +Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ +Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ +Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +static const double zero = 0.0; + +double +__ieee754_log(double x) +{ + double hfsq,f,s,z,R,w,t1,t2,dk; + int32_t k,hx,i,j; + u_int32_t lx; + + EXTRACT_WORDS(hx,lx,x); + + k=0; + if (hx < 0x00100000) { /* x < 2**-1022 */ + if (((hx&0x7fffffff)|lx)==0) + return -two54/zero; /* log(+-0)=-inf */ + if (hx<0) return (x-x)/zero; /* log(-#) = NaN */ + k -= 54; x *= two54; /* subnormal number, scale up x */ + GET_HIGH_WORD(hx,x); + } + if (hx >= 0x7ff00000) return x+x; + k += (hx>>20)-1023; + hx &= 0x000fffff; + i = (hx+0x95f64)&0x100000; + SET_HIGH_WORD(x,hx|(i^0x3ff00000)); /* normalize x or x/2 */ + k += (i>>20); + f = x-1.0; + if((0x000fffff&(2+hx))<3) { /* -2**-20 <= f < 2**-20 */ + if(f==zero) { + if(k==0) { + return zero; + } else { + dk=(double)k; + return dk*ln2_hi+dk*ln2_lo; + } + } + R = f*f*(0.5-0.33333333333333333*f); + if(k==0) return f-R; else {dk=(double)k; + return dk*ln2_hi-((R-dk*ln2_lo)-f);} + } + s = f/(2.0+f); + dk = (double)k; + z = s*s; + i = hx-0x6147a; + w = z*z; + j = 0x6b851-hx; + t1= w*(Lg2+w*(Lg4+w*Lg6)); + t2= z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); + i |= j; + R = t2+t1; + if(i>0) { + hfsq=0.5*f*f; + if(k==0) return f-(hfsq-s*(hfsq+R)); else + return dk*ln2_hi-((hfsq-(s*(hfsq+R)+dk*ln2_lo))-f); + } else { + if(k==0) return f-s*(f-R); else + return dk*ln2_hi-((s*(f-R)-dk*ln2_lo)-f); + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_log10.c b/libm/upstream-freebsd/lib/msun/src/e_log10.c new file mode 100644 index 0000000..104d257 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_log10.c @@ -0,0 +1,87 @@ + +/* @(#)e_log10.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Return the base 10 logarithm of x. See e_log.c and k_log.h for most + * comments. + * + * log10(x) = (f - 0.5*f*f + k_log1p(f)) / ln10 + k * log10(2) + * in not-quite-routine extra precision. + */ + +#include "math.h" +#include "math_private.h" +#include "k_log.h" + +static const double +two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */ +ivln10hi = 4.34294481878168880939e-01, /* 0x3fdbcb7b, 0x15200000 */ +ivln10lo = 2.50829467116452752298e-11, /* 0x3dbb9438, 0xca9aadd5 */ +log10_2hi = 3.01029995663611771306e-01, /* 0x3FD34413, 0x509F6000 */ +log10_2lo = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */ + +static const double zero = 0.0; + +double +__ieee754_log10(double x) +{ + double f,hfsq,hi,lo,r,val_hi,val_lo,w,y,y2; + int32_t i,k,hx; + u_int32_t lx; + + EXTRACT_WORDS(hx,lx,x); + + k=0; + if (hx < 0x00100000) { /* x < 2**-1022 */ + if (((hx&0x7fffffff)|lx)==0) + return -two54/zero; /* log(+-0)=-inf */ + if (hx<0) return (x-x)/zero; /* log(-#) = NaN */ + k -= 54; x *= two54; /* subnormal number, scale up x */ + GET_HIGH_WORD(hx,x); + } + if (hx >= 0x7ff00000) return x+x; + if (hx == 0x3ff00000 && lx == 0) + return zero; /* log(1) = +0 */ + k += (hx>>20)-1023; + hx &= 0x000fffff; + i = (hx+0x95f64)&0x100000; + SET_HIGH_WORD(x,hx|(i^0x3ff00000)); /* normalize x or x/2 */ + k += (i>>20); + y = (double)k; + f = x - 1.0; + hfsq = 0.5*f*f; + r = k_log1p(f); + + /* See e_log2.c for most details. */ + hi = f - hfsq; + SET_LOW_WORD(hi,0); + lo = (f - hi) - hfsq + r; + val_hi = hi*ivln10hi; + y2 = y*log10_2hi; + val_lo = y*log10_2lo + (lo+hi)*ivln10lo + lo*ivln10hi; + + /* + * Extra precision in for adding y*log10_2hi is not strictly needed + * since there is no very large cancellation near x = sqrt(2) or + * x = 1/sqrt(2), but we do it anyway since it costs little on CPUs + * with some parallelism and it reduces the error for many args. + */ + w = y2 + val_hi; + val_lo += (y2 - w) + val_hi; + val_hi = w; + + return val_lo + val_hi; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_log10f.c b/libm/upstream-freebsd/lib/msun/src/e_log10f.c new file mode 100644 index 0000000..c876594 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_log10f.c @@ -0,0 +1,71 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Float version of e_log10.c. See the latter for most comments. + */ + +#include "math.h" +#include "math_private.h" +#include "k_logf.h" + +static const float +two25 = 3.3554432000e+07, /* 0x4c000000 */ +ivln10hi = 4.3432617188e-01, /* 0x3ede6000 */ +ivln10lo = -3.1689971365e-05, /* 0xb804ead9 */ +log10_2hi = 3.0102920532e-01, /* 0x3e9a2080 */ +log10_2lo = 7.9034151668e-07; /* 0x355427db */ + +static const float zero = 0.0; + +float +__ieee754_log10f(float x) +{ + float f,hfsq,hi,lo,r,y; + int32_t i,k,hx; + + GET_FLOAT_WORD(hx,x); + + k=0; + if (hx < 0x00800000) { /* x < 2**-126 */ + if ((hx&0x7fffffff)==0) + return -two25/zero; /* log(+-0)=-inf */ + if (hx<0) return (x-x)/zero; /* log(-#) = NaN */ + k -= 25; x *= two25; /* subnormal number, scale up x */ + GET_FLOAT_WORD(hx,x); + } + if (hx >= 0x7f800000) return x+x; + if (hx == 0x3f800000) + return zero; /* log(1) = +0 */ + k += (hx>>23)-127; + hx &= 0x007fffff; + i = (hx+(0x4afb0d))&0x800000; + SET_FLOAT_WORD(x,hx|(i^0x3f800000)); /* normalize x or x/2 */ + k += (i>>23); + y = (float)k; + f = x - (float)1.0; + hfsq = (float)0.5*f*f; + r = k_log1pf(f); + + /* See e_log2f.c and e_log2.c for details. */ + if (sizeof(float_t) > sizeof(float)) + return (r - hfsq + f) * ((float_t)ivln10lo + ivln10hi) + + y * ((float_t)log10_2lo + log10_2hi); + hi = f - hfsq; + GET_FLOAT_WORD(hx,hi); + SET_FLOAT_WORD(hi,hx&0xfffff000); + lo = (f - hi) - hfsq + r; + return y*log10_2lo + (lo+hi)*ivln10lo + lo*ivln10hi + hi*ivln10hi + + y*log10_2hi; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_log2.c b/libm/upstream-freebsd/lib/msun/src/e_log2.c new file mode 100644 index 0000000..1fc44a5 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_log2.c @@ -0,0 +1,110 @@ + +/* @(#)e_log10.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Return the base 2 logarithm of x. See e_log.c and k_log.h for most + * comments. + * + * This reduces x to {k, 1+f} exactly as in e_log.c, then calls the kernel, + * then does the combining and scaling steps + * log2(x) = (f - 0.5*f*f + k_log1p(f)) / ln2 + k + * in not-quite-routine extra precision. + */ + +#include "math.h" +#include "math_private.h" +#include "k_log.h" + +static const double +two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */ +ivln2hi = 1.44269504072144627571e+00, /* 0x3ff71547, 0x65200000 */ +ivln2lo = 1.67517131648865118353e-10; /* 0x3de705fc, 0x2eefa200 */ + +static const double zero = 0.0; + +double +__ieee754_log2(double x) +{ + double f,hfsq,hi,lo,r,val_hi,val_lo,w,y; + int32_t i,k,hx; + u_int32_t lx; + + EXTRACT_WORDS(hx,lx,x); + + k=0; + if (hx < 0x00100000) { /* x < 2**-1022 */ + if (((hx&0x7fffffff)|lx)==0) + return -two54/zero; /* log(+-0)=-inf */ + if (hx<0) return (x-x)/zero; /* log(-#) = NaN */ + k -= 54; x *= two54; /* subnormal number, scale up x */ + GET_HIGH_WORD(hx,x); + } + if (hx >= 0x7ff00000) return x+x; + if (hx == 0x3ff00000 && lx == 0) + return zero; /* log(1) = +0 */ + k += (hx>>20)-1023; + hx &= 0x000fffff; + i = (hx+0x95f64)&0x100000; + SET_HIGH_WORD(x,hx|(i^0x3ff00000)); /* normalize x or x/2 */ + k += (i>>20); + y = (double)k; + f = x - 1.0; + hfsq = 0.5*f*f; + r = k_log1p(f); + + /* + * f-hfsq must (for args near 1) be evaluated in extra precision + * to avoid a large cancellation when x is near sqrt(2) or 1/sqrt(2). + * This is fairly efficient since f-hfsq only depends on f, so can + * be evaluated in parallel with R. Not combining hfsq with R also + * keeps R small (though not as small as a true `lo' term would be), + * so that extra precision is not needed for terms involving R. + * + * Compiler bugs involving extra precision used to break Dekker's + * theorem for spitting f-hfsq as hi+lo, unless double_t was used + * or the multi-precision calculations were avoided when double_t + * has extra precision. These problems are now automatically + * avoided as a side effect of the optimization of combining the + * Dekker splitting step with the clear-low-bits step. + * + * y must (for args near sqrt(2) and 1/sqrt(2)) be added in extra + * precision to avoid a very large cancellation when x is very near + * these values. Unlike the above cancellations, this problem is + * specific to base 2. It is strange that adding +-1 is so much + * harder than adding +-ln2 or +-log10_2. + * + * This uses Dekker's theorem to normalize y+val_hi, so the + * compiler bugs are back in some configurations, sigh. And I + * don't want to used double_t to avoid them, since that gives a + * pessimization and the support for avoiding the pessimization + * is not yet available. + * + * The multi-precision calculations for the multiplications are + * routine. + */ + hi = f - hfsq; + SET_LOW_WORD(hi,0); + lo = (f - hi) - hfsq + r; + val_hi = hi*ivln2hi; + val_lo = (lo+hi)*ivln2lo + lo*ivln2hi; + + /* spadd(val_hi, val_lo, y), except for not using double_t: */ + w = y + val_hi; + val_lo += (y - w) + val_hi; + val_hi = w; + + return val_lo + val_hi; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_log2f.c b/libm/upstream-freebsd/lib/msun/src/e_log2f.c new file mode 100644 index 0000000..7166346 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_log2f.c @@ -0,0 +1,81 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Float version of e_log2.c. See the latter for most comments. + */ + +#include "math.h" +#include "math_private.h" +#include "k_logf.h" + +static const float +two25 = 3.3554432000e+07, /* 0x4c000000 */ +ivln2hi = 1.4428710938e+00, /* 0x3fb8b000 */ +ivln2lo = -1.7605285393e-04; /* 0xb9389ad4 */ + +static const float zero = 0.0; + +float +__ieee754_log2f(float x) +{ + float f,hfsq,hi,lo,r,y; + int32_t i,k,hx; + + GET_FLOAT_WORD(hx,x); + + k=0; + if (hx < 0x00800000) { /* x < 2**-126 */ + if ((hx&0x7fffffff)==0) + return -two25/zero; /* log(+-0)=-inf */ + if (hx<0) return (x-x)/zero; /* log(-#) = NaN */ + k -= 25; x *= two25; /* subnormal number, scale up x */ + GET_FLOAT_WORD(hx,x); + } + if (hx >= 0x7f800000) return x+x; + if (hx == 0x3f800000) + return zero; /* log(1) = +0 */ + k += (hx>>23)-127; + hx &= 0x007fffff; + i = (hx+(0x4afb0d))&0x800000; + SET_FLOAT_WORD(x,hx|(i^0x3f800000)); /* normalize x or x/2 */ + k += (i>>23); + y = (float)k; + f = x - (float)1.0; + hfsq = (float)0.5*f*f; + r = k_log1pf(f); + + /* + * We no longer need to avoid falling into the multi-precision + * calculations due to compiler bugs breaking Dekker's theorem. + * Keep avoiding this as an optimization. See e_log2.c for more + * details (some details are here only because the optimization + * is not yet available in double precision). + * + * Another compiler bug turned up. With gcc on i386, + * (ivln2lo + ivln2hi) would be evaluated in float precision + * despite runtime evaluations using double precision. So we + * must cast one of its terms to float_t. This makes the whole + * expression have type float_t, so return is forced to waste + * time clobbering its extra precision. + */ + if (sizeof(float_t) > sizeof(float)) + return (r - hfsq + f) * ((float_t)ivln2lo + ivln2hi) + y; + + hi = f - hfsq; + GET_FLOAT_WORD(hx,hi); + SET_FLOAT_WORD(hi,hx&0xfffff000); + lo = (f - hi) - hfsq + r; + return (lo+hi)*ivln2lo + lo*ivln2hi + hi*ivln2hi + y; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_logf.c b/libm/upstream-freebsd/lib/msun/src/e_logf.c new file mode 100644 index 0000000..c3be6ed --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_logf.c @@ -0,0 +1,88 @@ +/* e_logf.c -- float version of e_log.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +static const float +ln2_hi = 6.9313812256e-01, /* 0x3f317180 */ +ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */ +two25 = 3.355443200e+07, /* 0x4c000000 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */ +Lg2 = 0xccce13.0p-25, /* 0.40000972152 */ +Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */ +Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */ + +static const float zero = 0.0; + +float +__ieee754_logf(float x) +{ + float hfsq,f,s,z,R,w,t1,t2,dk; + int32_t k,ix,i,j; + + GET_FLOAT_WORD(ix,x); + + k=0; + if (ix < 0x00800000) { /* x < 2**-126 */ + if ((ix&0x7fffffff)==0) + return -two25/zero; /* log(+-0)=-inf */ + if (ix<0) return (x-x)/zero; /* log(-#) = NaN */ + k -= 25; x *= two25; /* subnormal number, scale up x */ + GET_FLOAT_WORD(ix,x); + } + if (ix >= 0x7f800000) return x+x; + k += (ix>>23)-127; + ix &= 0x007fffff; + i = (ix+(0x95f64<<3))&0x800000; + SET_FLOAT_WORD(x,ix|(i^0x3f800000)); /* normalize x or x/2 */ + k += (i>>23); + f = x-(float)1.0; + if((0x007fffff&(0x8000+ix))<0xc000) { /* -2**-9 <= f < 2**-9 */ + if(f==zero) { + if(k==0) { + return zero; + } else { + dk=(float)k; + return dk*ln2_hi+dk*ln2_lo; + } + } + R = f*f*((float)0.5-(float)0.33333333333333333*f); + if(k==0) return f-R; else {dk=(float)k; + return dk*ln2_hi-((R-dk*ln2_lo)-f);} + } + s = f/((float)2.0+f); + dk = (float)k; + z = s*s; + i = ix-(0x6147a<<3); + w = z*z; + j = (0x6b851<<3)-ix; + t1= w*(Lg2+w*Lg4); + t2= z*(Lg1+w*Lg3); + i |= j; + R = t2+t1; + if(i>0) { + hfsq=(float)0.5*f*f; + if(k==0) return f-(hfsq-s*(hfsq+R)); else + return dk*ln2_hi-((hfsq-(s*(hfsq+R)+dk*ln2_lo))-f); + } else { + if(k==0) return f-s*(f-R); else + return dk*ln2_hi-((s*(f-R)-dk*ln2_lo)-f); + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_pow.c b/libm/upstream-freebsd/lib/msun/src/e_pow.c new file mode 100644 index 0000000..7607a4a --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_pow.c @@ -0,0 +1,306 @@ +/* @(#)e_pow.c 1.5 04/04/22 SMI */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* __ieee754_pow(x,y) return x**y + * + * n + * Method: Let x = 2 * (1+f) + * 1. Compute and return log2(x) in two pieces: + * log2(x) = w1 + w2, + * where w1 has 53-24 = 29 bit trailing zeros. + * 2. Perform y*log2(x) = n+y' by simulating muti-precision + * arithmetic, where |y'|<=0.5. + * 3. Return x**y = 2**n*exp(y'*log2) + * + * Special cases: + * 1. (anything) ** 0 is 1 + * 2. (anything) ** 1 is itself + * 3. (anything) ** NAN is NAN + * 4. NAN ** (anything except 0) is NAN + * 5. +-(|x| > 1) ** +INF is +INF + * 6. +-(|x| > 1) ** -INF is +0 + * 7. +-(|x| < 1) ** +INF is +0 + * 8. +-(|x| < 1) ** -INF is +INF + * 9. +-1 ** +-INF is NAN + * 10. +0 ** (+anything except 0, NAN) is +0 + * 11. -0 ** (+anything except 0, NAN, odd integer) is +0 + * 12. +0 ** (-anything except 0, NAN) is +INF + * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF + * 14. -0 ** (odd integer) = -( +0 ** (odd integer) ) + * 15. +INF ** (+anything except 0,NAN) is +INF + * 16. +INF ** (-anything except 0,NAN) is +0 + * 17. -INF ** (anything) = -0 ** (-anything) + * 18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) + * 19. (-anything except 0 and inf) ** (non-integer) is NAN + * + * Accuracy: + * pow(x,y) returns x**y nearly rounded. In particular + * pow(integer,integer) + * always returns the correct integer provided it is + * representable. + * + * Constants : + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "math.h" +#include "math_private.h" + +static const double +bp[] = {1.0, 1.5,}, +dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */ +dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */ +zero = 0.0, +one = 1.0, +two = 2.0, +two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */ +huge = 1.0e300, +tiny = 1.0e-300, + /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ +L1 = 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */ +L2 = 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */ +L3 = 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */ +L4 = 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */ +L5 = 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */ +L6 = 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */ +P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ +P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ +P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ +P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ +P5 = 4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */ +lg2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */ +lg2_h = 6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */ +lg2_l = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */ +ovt = 8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */ +cp = 9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */ +cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */ +cp_l = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/ +ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */ +ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/ +ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/ + +double +__ieee754_pow(double x, double y) +{ + double z,ax,z_h,z_l,p_h,p_l; + double y1,t1,t2,r,s,t,u,v,w; + int32_t i,j,k,yisint,n; + int32_t hx,hy,ix,iy; + u_int32_t lx,ly; + + EXTRACT_WORDS(hx,lx,x); + EXTRACT_WORDS(hy,ly,y); + ix = hx&0x7fffffff; iy = hy&0x7fffffff; + + /* y==zero: x**0 = 1 */ + if((iy|ly)==0) return one; + + /* x==1: 1**y = 1, even if y is NaN */ + if (hx==0x3ff00000 && lx == 0) return one; + + /* y!=zero: result is NaN if either arg is NaN */ + if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) || + iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0))) + return (x+0.0)+(y+0.0); + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if(hx<0) { + if(iy>=0x43400000) yisint = 2; /* even integer y */ + else if(iy>=0x3ff00000) { + k = (iy>>20)-0x3ff; /* exponent */ + if(k>20) { + j = ly>>(52-k); + if((j<<(52-k))==ly) yisint = 2-(j&1); + } else if(ly==0) { + j = iy>>(20-k); + if((j<<(20-k))==iy) yisint = 2-(j&1); + } + } + } + + /* special value of y */ + if(ly==0) { + if (iy==0x7ff00000) { /* y is +-inf */ + if(((ix-0x3ff00000)|lx)==0) + return one; /* (-1)**+-inf is NaN */ + else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */ + return (hy>=0)? y: zero; + else /* (|x|<1)**-,+inf = inf,0 */ + return (hy<0)?-y: zero; + } + if(iy==0x3ff00000) { /* y is +-1 */ + if(hy<0) return one/x; else return x; + } + if(hy==0x40000000) return x*x; /* y is 2 */ + if(hy==0x3fe00000) { /* y is 0.5 */ + if(hx>=0) /* x >= +0 */ + return sqrt(x); + } + } + + ax = fabs(x); + /* special value of x */ + if(lx==0) { + if(ix==0x7ff00000||ix==0||ix==0x3ff00000){ + z = ax; /*x is +-0,+-inf,+-1*/ + if(hy<0) z = one/z; /* z = (1/|x|) */ + if(hx<0) { + if(((ix-0x3ff00000)|yisint)==0) { + z = (z-z)/(z-z); /* (-1)**non-int is NaN */ + } else if(yisint==1) + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + return z; + } + } + + /* CYGNUS LOCAL + fdlibm-5.3 fix: This used to be + n = (hx>>31)+1; + but ANSI C says a right shift of a signed negative quantity is + implementation defined. */ + n = ((u_int32_t)hx>>31)-1; + + /* (x<0)**(non-int) is NaN */ + if((n|yisint)==0) return (x-x)/(x-x); + + s = one; /* s (sign of result -ve**odd) = -1 else = 1 */ + if((n|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */ + + /* |y| is huge */ + if(iy>0x41e00000) { /* if |y| > 2**31 */ + if(iy>0x43f00000){ /* if |y| > 2**64, must o/uflow */ + if(ix<=0x3fefffff) return (hy<0)? huge*huge:tiny*tiny; + if(ix>=0x3ff00000) return (hy>0)? huge*huge:tiny*tiny; + } + /* over/underflow if x is not close to one */ + if(ix<0x3fefffff) return (hy<0)? s*huge*huge:s*tiny*tiny; + if(ix>0x3ff00000) return (hy>0)? s*huge*huge:s*tiny*tiny; + /* now |1-x| is tiny <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = ax-one; /* t has 20 trailing zeros */ + w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25)); + u = ivln2_h*t; /* ivln2_h has 21 sig. bits */ + v = t*ivln2_l-w*ivln2; + t1 = u+v; + SET_LOW_WORD(t1,0); + t2 = v-(t1-u); + } else { + double ss,s2,s_h,s_l,t_h,t_l; + n = 0; + /* take care subnormal number */ + if(ix<0x00100000) + {ax *= two53; n -= 53; GET_HIGH_WORD(ix,ax); } + n += ((ix)>>20)-0x3ff; + j = ix&0x000fffff; + /* determine interval */ + ix = j|0x3ff00000; /* normalize ix */ + if(j<=0x3988E) k=0; /* |x|<sqrt(3/2) */ + else if(j<0xBB67A) k=1; /* |x|<sqrt(3) */ + else {k=0;n+=1;ix -= 0x00100000;} + SET_HIGH_WORD(ax,ix); + + /* compute ss = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */ + u = ax-bp[k]; /* bp[0]=1.0, bp[1]=1.5 */ + v = one/(ax+bp[k]); + ss = u*v; + s_h = ss; + SET_LOW_WORD(s_h,0); + /* t_h=ax+bp[k] High */ + t_h = zero; + SET_HIGH_WORD(t_h,((ix>>1)|0x20000000)+0x00080000+(k<<18)); + t_l = ax - (t_h-bp[k]); + s_l = v*((u-s_h*t_h)-s_h*t_l); + /* compute log(ax) */ + s2 = ss*ss; + r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6))))); + r += s_l*(s_h+ss); + s2 = s_h*s_h; + t_h = 3.0+s2+r; + SET_LOW_WORD(t_h,0); + t_l = r-((t_h-3.0)-s2); + /* u+v = ss*(1+...) */ + u = s_h*t_h; + v = s_l*t_h+t_l*ss; + /* 2/(3log2)*(ss+...) */ + p_h = u+v; + SET_LOW_WORD(p_h,0); + p_l = v-(p_h-u); + z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = cp_l*p_h+p_l*cp+dp_l[k]; + /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = (double)n; + t1 = (((z_h+z_l)+dp_h[k])+t); + SET_LOW_WORD(t1,0); + t2 = z_l-(((t1-t)-dp_h[k])-z_h); + } + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + y1 = y; + SET_LOW_WORD(y1,0); + p_l = (y-y1)*t1+y*t2; + p_h = y1*t1; + z = p_l+p_h; + EXTRACT_WORDS(j,i,z); + if (j>=0x40900000) { /* z >= 1024 */ + if(((j-0x40900000)|i)!=0) /* if z > 1024 */ + return s*huge*huge; /* overflow */ + else { + if(p_l+ovt>z-p_h) return s*huge*huge; /* overflow */ + } + } else if((j&0x7fffffff)>=0x4090cc00 ) { /* z <= -1075 */ + if(((j-0xc090cc00)|i)!=0) /* z < -1075 */ + return s*tiny*tiny; /* underflow */ + else { + if(p_l<=z-p_h) return s*tiny*tiny; /* underflow */ + } + } + /* + * compute 2**(p_h+p_l) + */ + i = j&0x7fffffff; + k = (i>>20)-0x3ff; + n = 0; + if(i>0x3fe00000) { /* if |z| > 0.5, set n = [z+0.5] */ + n = j+(0x00100000>>(k+1)); + k = ((n&0x7fffffff)>>20)-0x3ff; /* new k for n */ + t = zero; + SET_HIGH_WORD(t,n&~(0x000fffff>>k)); + n = ((n&0x000fffff)|0x00100000)>>(20-k); + if(j<0) n = -n; + p_h -= t; + } + t = p_l+p_h; + SET_LOW_WORD(t,0); + u = t*lg2_h; + v = (p_l-(t-p_h))*lg2+t*lg2_l; + z = u+v; + w = v-(z-u); + t = z*z; + t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); + r = (z*t1)/(t1-two)-(w+z*w); + z = one-(r-z); + GET_HIGH_WORD(j,z); + j += (n<<20); + if((j>>20)<=0) z = scalbn(z,n); /* subnormal output */ + else SET_HIGH_WORD(z,j); + return s*z; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_powf.c b/libm/upstream-freebsd/lib/msun/src/e_powf.c new file mode 100644 index 0000000..5c46478 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_powf.c @@ -0,0 +1,249 @@ +/* e_powf.c -- float version of e_pow.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +static const float +bp[] = {1.0, 1.5,}, +dp_h[] = { 0.0, 5.84960938e-01,}, /* 0x3f15c000 */ +dp_l[] = { 0.0, 1.56322085e-06,}, /* 0x35d1cfdc */ +zero = 0.0, +one = 1.0, +two = 2.0, +two24 = 16777216.0, /* 0x4b800000 */ +huge = 1.0e30, +tiny = 1.0e-30, + /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ +L1 = 6.0000002384e-01, /* 0x3f19999a */ +L2 = 4.2857143283e-01, /* 0x3edb6db7 */ +L3 = 3.3333334327e-01, /* 0x3eaaaaab */ +L4 = 2.7272811532e-01, /* 0x3e8ba305 */ +L5 = 2.3066075146e-01, /* 0x3e6c3255 */ +L6 = 2.0697501302e-01, /* 0x3e53f142 */ +P1 = 1.6666667163e-01, /* 0x3e2aaaab */ +P2 = -2.7777778450e-03, /* 0xbb360b61 */ +P3 = 6.6137559770e-05, /* 0x388ab355 */ +P4 = -1.6533901999e-06, /* 0xb5ddea0e */ +P5 = 4.1381369442e-08, /* 0x3331bb4c */ +lg2 = 6.9314718246e-01, /* 0x3f317218 */ +lg2_h = 6.93145752e-01, /* 0x3f317200 */ +lg2_l = 1.42860654e-06, /* 0x35bfbe8c */ +ovt = 4.2995665694e-08, /* -(128-log2(ovfl+.5ulp)) */ +cp = 9.6179670095e-01, /* 0x3f76384f =2/(3ln2) */ +cp_h = 9.6191406250e-01, /* 0x3f764000 =12b cp */ +cp_l = -1.1736857402e-04, /* 0xb8f623c6 =tail of cp_h */ +ivln2 = 1.4426950216e+00, /* 0x3fb8aa3b =1/ln2 */ +ivln2_h = 1.4426879883e+00, /* 0x3fb8aa00 =16b 1/ln2*/ +ivln2_l = 7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/ + +float +__ieee754_powf(float x, float y) +{ + float z,ax,z_h,z_l,p_h,p_l; + float y1,t1,t2,r,s,sn,t,u,v,w; + int32_t i,j,k,yisint,n; + int32_t hx,hy,ix,iy,is; + + GET_FLOAT_WORD(hx,x); + GET_FLOAT_WORD(hy,y); + ix = hx&0x7fffffff; iy = hy&0x7fffffff; + + /* y==zero: x**0 = 1 */ + if(iy==0) return one; + + /* x==1: 1**y = 1, even if y is NaN */ + if (hx==0x3f800000) return one; + + /* y!=zero: result is NaN if either arg is NaN */ + if(ix > 0x7f800000 || + iy > 0x7f800000) + return (x+0.0F)+(y+0.0F); + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if(hx<0) { + if(iy>=0x4b800000) yisint = 2; /* even integer y */ + else if(iy>=0x3f800000) { + k = (iy>>23)-0x7f; /* exponent */ + j = iy>>(23-k); + if((j<<(23-k))==iy) yisint = 2-(j&1); + } + } + + /* special value of y */ + if (iy==0x7f800000) { /* y is +-inf */ + if (ix==0x3f800000) + return one; /* (-1)**+-inf is NaN */ + else if (ix > 0x3f800000)/* (|x|>1)**+-inf = inf,0 */ + return (hy>=0)? y: zero; + else /* (|x|<1)**-,+inf = inf,0 */ + return (hy<0)?-y: zero; + } + if(iy==0x3f800000) { /* y is +-1 */ + if(hy<0) return one/x; else return x; + } + if(hy==0x40000000) return x*x; /* y is 2 */ + if(hy==0x3f000000) { /* y is 0.5 */ + if(hx>=0) /* x >= +0 */ + return __ieee754_sqrtf(x); + } + + ax = fabsf(x); + /* special value of x */ + if(ix==0x7f800000||ix==0||ix==0x3f800000){ + z = ax; /*x is +-0,+-inf,+-1*/ + if(hy<0) z = one/z; /* z = (1/|x|) */ + if(hx<0) { + if(((ix-0x3f800000)|yisint)==0) { + z = (z-z)/(z-z); /* (-1)**non-int is NaN */ + } else if(yisint==1) + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + return z; + } + + n = ((u_int32_t)hx>>31)-1; + + /* (x<0)**(non-int) is NaN */ + if((n|yisint)==0) return (x-x)/(x-x); + + sn = one; /* s (sign of result -ve**odd) = -1 else = 1 */ + if((n|(yisint-1))==0) sn = -one;/* (-ve)**(odd int) */ + + /* |y| is huge */ + if(iy>0x4d000000) { /* if |y| > 2**27 */ + /* over/underflow if x is not close to one */ + if(ix<0x3f7ffff8) return (hy<0)? sn*huge*huge:sn*tiny*tiny; + if(ix>0x3f800007) return (hy>0)? sn*huge*huge:sn*tiny*tiny; + /* now |1-x| is tiny <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = ax-1; /* t has 20 trailing zeros */ + w = (t*t)*((float)0.5-t*((float)0.333333333333-t*(float)0.25)); + u = ivln2_h*t; /* ivln2_h has 16 sig. bits */ + v = t*ivln2_l-w*ivln2; + t1 = u+v; + GET_FLOAT_WORD(is,t1); + SET_FLOAT_WORD(t1,is&0xfffff000); + t2 = v-(t1-u); + } else { + float s2,s_h,s_l,t_h,t_l; + n = 0; + /* take care subnormal number */ + if(ix<0x00800000) + {ax *= two24; n -= 24; GET_FLOAT_WORD(ix,ax); } + n += ((ix)>>23)-0x7f; + j = ix&0x007fffff; + /* determine interval */ + ix = j|0x3f800000; /* normalize ix */ + if(j<=0x1cc471) k=0; /* |x|<sqrt(3/2) */ + else if(j<0x5db3d7) k=1; /* |x|<sqrt(3) */ + else {k=0;n+=1;ix -= 0x00800000;} + SET_FLOAT_WORD(ax,ix); + + /* compute s = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */ + u = ax-bp[k]; /* bp[0]=1.0, bp[1]=1.5 */ + v = one/(ax+bp[k]); + s = u*v; + s_h = s; + GET_FLOAT_WORD(is,s_h); + SET_FLOAT_WORD(s_h,is&0xfffff000); + /* t_h=ax+bp[k] High */ + is = ((ix>>1)&0xfffff000)|0x20000000; + SET_FLOAT_WORD(t_h,is+0x00400000+(k<<21)); + t_l = ax - (t_h-bp[k]); + s_l = v*((u-s_h*t_h)-s_h*t_l); + /* compute log(ax) */ + s2 = s*s; + r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6))))); + r += s_l*(s_h+s); + s2 = s_h*s_h; + t_h = (float)3.0+s2+r; + GET_FLOAT_WORD(is,t_h); + SET_FLOAT_WORD(t_h,is&0xfffff000); + t_l = r-((t_h-(float)3.0)-s2); + /* u+v = s*(1+...) */ + u = s_h*t_h; + v = s_l*t_h+t_l*s; + /* 2/(3log2)*(s+...) */ + p_h = u+v; + GET_FLOAT_WORD(is,p_h); + SET_FLOAT_WORD(p_h,is&0xfffff000); + p_l = v-(p_h-u); + z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = cp_l*p_h+p_l*cp+dp_l[k]; + /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = (float)n; + t1 = (((z_h+z_l)+dp_h[k])+t); + GET_FLOAT_WORD(is,t1); + SET_FLOAT_WORD(t1,is&0xfffff000); + t2 = z_l-(((t1-t)-dp_h[k])-z_h); + } + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + GET_FLOAT_WORD(is,y); + SET_FLOAT_WORD(y1,is&0xfffff000); + p_l = (y-y1)*t1+y*t2; + p_h = y1*t1; + z = p_l+p_h; + GET_FLOAT_WORD(j,z); + if (j>0x43000000) /* if z > 128 */ + return sn*huge*huge; /* overflow */ + else if (j==0x43000000) { /* if z == 128 */ + if(p_l+ovt>z-p_h) return sn*huge*huge; /* overflow */ + } + else if ((j&0x7fffffff)>0x43160000) /* z <= -150 */ + return sn*tiny*tiny; /* underflow */ + else if (j==0xc3160000){ /* z == -150 */ + if(p_l<=z-p_h) return sn*tiny*tiny; /* underflow */ + } + /* + * compute 2**(p_h+p_l) + */ + i = j&0x7fffffff; + k = (i>>23)-0x7f; + n = 0; + if(i>0x3f000000) { /* if |z| > 0.5, set n = [z+0.5] */ + n = j+(0x00800000>>(k+1)); + k = ((n&0x7fffffff)>>23)-0x7f; /* new k for n */ + SET_FLOAT_WORD(t,n&~(0x007fffff>>k)); + n = ((n&0x007fffff)|0x00800000)>>(23-k); + if(j<0) n = -n; + p_h -= t; + } + t = p_l+p_h; + GET_FLOAT_WORD(is,t); + SET_FLOAT_WORD(t,is&0xffff8000); + u = t*lg2_h; + v = (p_l-(t-p_h))*lg2+t*lg2_l; + z = u+v; + w = v-(z-u); + t = z*z; + t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); + r = (z*t1)/(t1-two)-(w+z*w); + z = one-(r-z); + GET_FLOAT_WORD(j,z); + j += (n<<23); + if((j>>23)<=0) z = scalbnf(z,n); /* subnormal output */ + else SET_FLOAT_WORD(z,j); + return sn*z; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_rem_pio2.c b/libm/upstream-freebsd/lib/msun/src/e_rem_pio2.c new file mode 100644 index 0000000..be2630b --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_rem_pio2.c @@ -0,0 +1,186 @@ + +/* @(#)e_rem_pio2.c 1.4 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * Optimized by Bruce D. Evans. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* __ieee754_rem_pio2(x,y) + * + * return the remainder of x rem pi/2 in y[0]+y[1] + * use __kernel_rem_pio2() + */ + +#include <float.h> + +#include "math.h" +#include "math_private.h" + +/* + * invpio2: 53 bits of 2/pi + * pio2_1: first 33 bit of pi/2 + * pio2_1t: pi/2 - pio2_1 + * pio2_2: second 33 bit of pi/2 + * pio2_2t: pi/2 - (pio2_1+pio2_2) + * pio2_3: third 33 bit of pi/2 + * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3) + */ + +static const double +zero = 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ +two24 = 1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */ +invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ +pio2_1 = 1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */ +pio2_1t = 6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */ +pio2_2 = 6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */ +pio2_2t = 2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */ +pio2_3 = 2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */ +pio2_3t = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ + +#ifdef INLINE_REM_PIO2 +static __inline __always_inline +#endif +int +__ieee754_rem_pio2(double x, double *y) +{ + double z,w,t,r,fn; + double tx[3],ty[2]; + int32_t e0,i,j,nx,n,ix,hx; + u_int32_t low; + + GET_HIGH_WORD(hx,x); /* high word of x */ + ix = hx&0x7fffffff; +#if 0 /* Must be handled in caller. */ + if(ix<=0x3fe921fb) /* |x| ~<= pi/4 , no need for reduction */ + {y[0] = x; y[1] = 0; return 0;} +#endif + if (ix <= 0x400f6a7a) { /* |x| ~<= 5pi/4 */ + if ((ix & 0xfffff) == 0x921fb) /* |x| ~= pi/2 or 2pi/2 */ + goto medium; /* cancellation -- use medium case */ + if (ix <= 0x4002d97c) { /* |x| ~<= 3pi/4 */ + if (hx > 0) { + z = x - pio2_1; /* one round good to 85 bits */ + y[0] = z - pio2_1t; + y[1] = (z-y[0])-pio2_1t; + return 1; + } else { + z = x + pio2_1; + y[0] = z + pio2_1t; + y[1] = (z-y[0])+pio2_1t; + return -1; + } + } else { + if (hx > 0) { + z = x - 2*pio2_1; + y[0] = z - 2*pio2_1t; + y[1] = (z-y[0])-2*pio2_1t; + return 2; + } else { + z = x + 2*pio2_1; + y[0] = z + 2*pio2_1t; + y[1] = (z-y[0])+2*pio2_1t; + return -2; + } + } + } + if (ix <= 0x401c463b) { /* |x| ~<= 9pi/4 */ + if (ix <= 0x4015fdbc) { /* |x| ~<= 7pi/4 */ + if (ix == 0x4012d97c) /* |x| ~= 3pi/2 */ + goto medium; + if (hx > 0) { + z = x - 3*pio2_1; + y[0] = z - 3*pio2_1t; + y[1] = (z-y[0])-3*pio2_1t; + return 3; + } else { + z = x + 3*pio2_1; + y[0] = z + 3*pio2_1t; + y[1] = (z-y[0])+3*pio2_1t; + return -3; + } + } else { + if (ix == 0x401921fb) /* |x| ~= 4pi/2 */ + goto medium; + if (hx > 0) { + z = x - 4*pio2_1; + y[0] = z - 4*pio2_1t; + y[1] = (z-y[0])-4*pio2_1t; + return 4; + } else { + z = x + 4*pio2_1; + y[0] = z + 4*pio2_1t; + y[1] = (z-y[0])+4*pio2_1t; + return -4; + } + } + } + if(ix<0x413921fb) { /* |x| ~< 2^20*(pi/2), medium size */ +medium: + /* Use a specialized rint() to get fn. Assume round-to-nearest. */ + STRICT_ASSIGN(double,fn,x*invpio2+0x1.8p52); + fn = fn-0x1.8p52; +#ifdef HAVE_EFFICIENT_IRINT + n = irint(fn); +#else + n = (int32_t)fn; +#endif + r = x-fn*pio2_1; + w = fn*pio2_1t; /* 1st round good to 85 bit */ + { + u_int32_t high; + j = ix>>20; + y[0] = r-w; + GET_HIGH_WORD(high,y[0]); + i = j-((high>>20)&0x7ff); + if(i>16) { /* 2nd iteration needed, good to 118 */ + t = r; + w = fn*pio2_2; + r = t-w; + w = fn*pio2_2t-((t-r)-w); + y[0] = r-w; + GET_HIGH_WORD(high,y[0]); + i = j-((high>>20)&0x7ff); + if(i>49) { /* 3rd iteration need, 151 bits acc */ + t = r; /* will cover all possible cases */ + w = fn*pio2_3; + r = t-w; + w = fn*pio2_3t-((t-r)-w); + y[0] = r-w; + } + } + } + y[1] = (r-y[0])-w; + return n; + } + /* + * all other (large) arguments + */ + if(ix>=0x7ff00000) { /* x is inf or NaN */ + y[0]=y[1]=x-x; return 0; + } + /* set z = scalbn(|x|,ilogb(x)-23) */ + GET_LOW_WORD(low,x); + e0 = (ix>>20)-1046; /* e0 = ilogb(z)-23; */ + INSERT_WORDS(z, ix - ((int32_t)(e0<<20)), low); + for(i=0;i<2;i++) { + tx[i] = (double)((int32_t)(z)); + z = (z-tx[i])*two24; + } + tx[2] = z; + nx = 3; + while(tx[nx-1]==zero) nx--; /* skip zero term */ + n = __kernel_rem_pio2(tx,ty,e0,nx,1); + if(hx<0) {y[0] = -ty[0]; y[1] = -ty[1]; return -n;} + y[0] = ty[0]; y[1] = ty[1]; return n; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_rem_pio2f.c b/libm/upstream-freebsd/lib/msun/src/e_rem_pio2f.c new file mode 100644 index 0000000..f1ee7a0 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_rem_pio2f.c @@ -0,0 +1,84 @@ +/* e_rem_pio2f.c -- float version of e_rem_pio2.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* __ieee754_rem_pio2f(x,y) + * + * return the remainder of x rem pi/2 in *y + * use double precision for everything except passing x + * use __kernel_rem_pio2() for large x + */ + +#include <float.h> + +#include "math.h" +#include "math_private.h" + +/* + * invpio2: 53 bits of 2/pi + * pio2_1: first 25 bits of pi/2 + * pio2_1t: pi/2 - pio2_1 + */ + +static const double +invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ +pio2_1 = 1.57079631090164184570e+00, /* 0x3FF921FB, 0x50000000 */ +pio2_1t = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ + +#ifdef INLINE_REM_PIO2F +static __inline __always_inline +#endif +int +__ieee754_rem_pio2f(float x, double *y) +{ + double w,r,fn; + double tx[1],ty[1]; + float z; + int32_t e0,n,ix,hx; + + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + /* 33+53 bit pi is good enough for medium size */ + if(ix<0x4dc90fdb) { /* |x| ~< 2^28*(pi/2), medium size */ + /* Use a specialized rint() to get fn. Assume round-to-nearest. */ + STRICT_ASSIGN(double,fn,x*invpio2+0x1.8p52); + fn = fn-0x1.8p52; +#ifdef HAVE_EFFICIENT_IRINT + n = irint(fn); +#else + n = (int32_t)fn; +#endif + r = x-fn*pio2_1; + w = fn*pio2_1t; + *y = r-w; + return n; + } + /* + * all other (large) arguments + */ + if(ix>=0x7f800000) { /* x is inf or NaN */ + *y=x-x; return 0; + } + /* set z = scalbn(|x|,ilogb(|x|)-23) */ + e0 = (ix>>23)-150; /* e0 = ilogb(|x|)-23; */ + SET_FLOAT_WORD(z, ix - ((int32_t)(e0<<23))); + tx[0] = z; + n = __kernel_rem_pio2(tx,ty,e0,1,0); + if(hx<0) {*y = -ty[0]; return -n;} + *y = ty[0]; return n; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_remainder.c b/libm/upstream-freebsd/lib/msun/src/e_remainder.c new file mode 100644 index 0000000..9be513b --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_remainder.c @@ -0,0 +1,79 @@ + +/* @(#)e_remainder.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* __ieee754_remainder(x,p) + * Return : + * returns x REM p = x - [x/p]*p as if in infinite + * precise arithmetic, where [x/p] is the (infinite bit) + * integer nearest x/p (in half way case choose the even one). + * Method : + * Based on fmod() return x-[x/p]chopped*p exactlp. + */ + +#include <float.h> + +#include "math.h" +#include "math_private.h" + +static const double zero = 0.0; + + +double +__ieee754_remainder(double x, double p) +{ + int32_t hx,hp; + u_int32_t sx,lx,lp; + double p_half; + + EXTRACT_WORDS(hx,lx,x); + EXTRACT_WORDS(hp,lp,p); + sx = hx&0x80000000; + hp &= 0x7fffffff; + hx &= 0x7fffffff; + + /* purge off exception values */ + if((hp|lp)==0) return (x*p)/(x*p); /* p = 0 */ + if((hx>=0x7ff00000)|| /* x not finite */ + ((hp>=0x7ff00000)&& /* p is NaN */ + (((hp-0x7ff00000)|lp)!=0))) + return ((long double)x*p)/((long double)x*p); + + + if (hp<=0x7fdfffff) x = __ieee754_fmod(x,p+p); /* now x < 2p */ + if (((hx-hp)|(lx-lp))==0) return zero*x; + x = fabs(x); + p = fabs(p); + if (hp<0x00200000) { + if(x+x>p) { + x-=p; + if(x+x>=p) x -= p; + } + } else { + p_half = 0.5*p; + if(x>p_half) { + x-=p; + if(x>=p_half) x -= p; + } + } + GET_HIGH_WORD(hx,x); + if ((hx&0x7fffffff)==0) hx = 0; + SET_HIGH_WORD(x,hx^sx); + return x; +} + +#if LDBL_MANT_DIG == 53 +__weak_reference(remainder, remainderl); +#endif diff --git a/libm/upstream-freebsd/lib/msun/src/e_remainderf.c b/libm/upstream-freebsd/lib/msun/src/e_remainderf.c new file mode 100644 index 0000000..b0014ae --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_remainderf.c @@ -0,0 +1,65 @@ +/* e_remainderf.c -- float version of e_remainder.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +static const float zero = 0.0; + + +float +__ieee754_remainderf(float x, float p) +{ + int32_t hx,hp; + u_int32_t sx; + float p_half; + + GET_FLOAT_WORD(hx,x); + GET_FLOAT_WORD(hp,p); + sx = hx&0x80000000; + hp &= 0x7fffffff; + hx &= 0x7fffffff; + + /* purge off exception values */ + if(hp==0) return (x*p)/(x*p); /* p = 0 */ + if((hx>=0x7f800000)|| /* x not finite */ + ((hp>0x7f800000))) /* p is NaN */ + return ((long double)x*p)/((long double)x*p); + + + if (hp<=0x7effffff) x = __ieee754_fmodf(x,p+p); /* now x < 2p */ + if ((hx-hp)==0) return zero*x; + x = fabsf(x); + p = fabsf(p); + if (hp<0x01000000) { + if(x+x>p) { + x-=p; + if(x+x>=p) x -= p; + } + } else { + p_half = (float)0.5*p; + if(x>p_half) { + x-=p; + if(x>=p_half) x -= p; + } + } + GET_FLOAT_WORD(hx,x); + if ((hx&0x7fffffff)==0) hx = 0; + SET_FLOAT_WORD(x,hx^sx); + return x; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_remainderl.c b/libm/upstream-freebsd/lib/msun/src/e_remainderl.c new file mode 100644 index 0000000..03327b8 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_remainderl.c @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2008 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <math.h> + +long double +remainderl(long double x, long double y) +{ + int quo; + + return (remquol(x, y, &quo)); +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_scalb.c b/libm/upstream-freebsd/lib/msun/src/e_scalb.c new file mode 100644 index 0000000..c0a7b5b --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_scalb.c @@ -0,0 +1,47 @@ + +/* @(#)e_scalb.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * __ieee754_scalb(x, fn) is provide for + * passing various standard test suite. One + * should use scalbn() instead. + */ + +#include "math.h" +#include "math_private.h" + +#ifdef _SCALB_INT +double +__ieee754_scalb(double x, int fn) +#else +double +__ieee754_scalb(double x, double fn) +#endif +{ +#ifdef _SCALB_INT + return scalbn(x,fn); +#else + if (isnan(x)||isnan(fn)) return x*fn; + if (!finite(fn)) { + if(fn>0.0) return x*fn; + else return x/(-fn); + } + if (rint(fn)!=fn) return (fn-fn)/(fn-fn); + if ( fn > 65000.0) return scalbn(x, 65000); + if (-fn > 65000.0) return scalbn(x,-65000); + return scalbn(x,(int)fn); +#endif +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_scalbf.c b/libm/upstream-freebsd/lib/msun/src/e_scalbf.c new file mode 100644 index 0000000..d49e904 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_scalbf.c @@ -0,0 +1,43 @@ +/* e_scalbf.c -- float version of e_scalb.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +#ifdef _SCALB_INT +float +__ieee754_scalbf(float x, int fn) +#else +float +__ieee754_scalbf(float x, float fn) +#endif +{ +#ifdef _SCALB_INT + return scalbnf(x,fn); +#else + if ((isnanf)(x)||(isnanf)(fn)) return x*fn; + if (!finitef(fn)) { + if(fn>(float)0.0) return x*fn; + else return x/(-fn); + } + if (rintf(fn)!=fn) return (fn-fn)/(fn-fn); + if ( fn > (float)65000.0) return scalbnf(x, 65000); + if (-fn > (float)65000.0) return scalbnf(x,-65000); + return scalbnf(x,(int)fn); +#endif +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_sinh.c b/libm/upstream-freebsd/lib/msun/src/e_sinh.c new file mode 100644 index 0000000..17442d0 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_sinh.c @@ -0,0 +1,73 @@ + +/* @(#)e_sinh.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* __ieee754_sinh(x) + * Method : + * mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2 + * 1. Replace x by |x| (sinh(-x) = -sinh(x)). + * 2. + * E + E/(E+1) + * 0 <= x <= 22 : sinh(x) := --------------, E=expm1(x) + * 2 + * + * 22 <= x <= lnovft : sinh(x) := exp(x)/2 + * lnovft <= x <= ln2ovft: sinh(x) := exp(x/2)/2 * exp(x/2) + * ln2ovft < x : sinh(x) := x*shuge (overflow) + * + * Special cases: + * sinh(x) is |x| if x is +INF, -INF, or NaN. + * only sinh(0)=0 is exact for finite x. + */ + +#include "math.h" +#include "math_private.h" + +static const double one = 1.0, shuge = 1.0e307; + +double +__ieee754_sinh(double x) +{ + double t,h; + int32_t ix,jx; + + /* High word of |x|. */ + GET_HIGH_WORD(jx,x); + ix = jx&0x7fffffff; + + /* x is INF or NaN */ + if(ix>=0x7ff00000) return x+x; + + h = 0.5; + if (jx<0) h = -h; + /* |x| in [0,22], return sign(x)*0.5*(E+E/(E+1))) */ + if (ix < 0x40360000) { /* |x|<22 */ + if (ix<0x3e300000) /* |x|<2**-28 */ + if(shuge+x>one) return x;/* sinh(tiny) = tiny with inexact */ + t = expm1(fabs(x)); + if(ix<0x3ff00000) return h*(2.0*t-t*t/(t+one)); + return h*(t+t/(t+one)); + } + + /* |x| in [22, log(maxdouble)] return 0.5*exp(|x|) */ + if (ix < 0x40862E42) return h*__ieee754_exp(fabs(x)); + + /* |x| in [log(maxdouble), overflowthresold] */ + if (ix<=0x408633CE) + return h*2.0*__ldexp_exp(fabs(x), -1); + + /* |x| > overflowthresold, sinh(x) overflow */ + return x*shuge; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_sinhf.c b/libm/upstream-freebsd/lib/msun/src/e_sinhf.c new file mode 100644 index 0000000..1be2dc3 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_sinhf.c @@ -0,0 +1,56 @@ +/* e_sinhf.c -- float version of e_sinh.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +static const float one = 1.0, shuge = 1.0e37; + +float +__ieee754_sinhf(float x) +{ + float t,h; + int32_t ix,jx; + + GET_FLOAT_WORD(jx,x); + ix = jx&0x7fffffff; + + /* x is INF or NaN */ + if(ix>=0x7f800000) return x+x; + + h = 0.5; + if (jx<0) h = -h; + /* |x| in [0,9], return sign(x)*0.5*(E+E/(E+1))) */ + if (ix < 0x41100000) { /* |x|<9 */ + if (ix<0x39800000) /* |x|<2**-12 */ + if(shuge+x>one) return x;/* sinh(tiny) = tiny with inexact */ + t = expm1f(fabsf(x)); + if(ix<0x3f800000) return h*((float)2.0*t-t*t/(t+one)); + return h*(t+t/(t+one)); + } + + /* |x| in [9, logf(maxfloat)] return 0.5*exp(|x|) */ + if (ix < 0x42b17217) return h*__ieee754_expf(fabsf(x)); + + /* |x| in [logf(maxfloat), overflowthresold] */ + if (ix<=0x42b2d4fc) + return h*2.0F*__ldexp_expf(fabsf(x), -1); + + /* |x| > overflowthresold, sinh(x) overflow */ + return x*shuge; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_sqrt.c b/libm/upstream-freebsd/lib/msun/src/e_sqrt.c new file mode 100644 index 0000000..12fb56e --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_sqrt.c @@ -0,0 +1,451 @@ + +/* @(#)e_sqrt.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* __ieee754_sqrt(x) + * Return correctly rounded sqrt. + * ------------------------------------------ + * | Use the hardware sqrt if you have one | + * ------------------------------------------ + * Method: + * Bit by bit method using integer arithmetic. (Slow, but portable) + * 1. Normalization + * Scale x to y in [1,4) with even powers of 2: + * find an integer k such that 1 <= (y=x*2^(2k)) < 4, then + * sqrt(x) = 2^k * sqrt(y) + * 2. Bit by bit computation + * Let q = sqrt(y) truncated to i bit after binary point (q = 1), + * i 0 + * i+1 2 + * s = 2*q , and y = 2 * ( y - q ). (1) + * i i i i + * + * To compute q from q , one checks whether + * i+1 i + * + * -(i+1) 2 + * (q + 2 ) <= y. (2) + * i + * -(i+1) + * If (2) is false, then q = q ; otherwise q = q + 2 . + * i+1 i i+1 i + * + * With some algebric manipulation, it is not difficult to see + * that (2) is equivalent to + * -(i+1) + * s + 2 <= y (3) + * i i + * + * The advantage of (3) is that s and y can be computed by + * i i + * the following recurrence formula: + * if (3) is false + * + * s = s , y = y ; (4) + * i+1 i i+1 i + * + * otherwise, + * -i -(i+1) + * s = s + 2 , y = y - s - 2 (5) + * i+1 i i+1 i i + * + * One may easily use induction to prove (4) and (5). + * Note. Since the left hand side of (3) contain only i+2 bits, + * it does not necessary to do a full (53-bit) comparison + * in (3). + * 3. Final rounding + * After generating the 53 bits result, we compute one more bit. + * Together with the remainder, we can decide whether the + * result is exact, bigger than 1/2ulp, or less than 1/2ulp + * (it will never equal to 1/2ulp). + * The rounding mode can be detected by checking whether + * huge + tiny is equal to huge, and whether huge - tiny is + * equal to huge for some floating point number "huge" and "tiny". + * + * Special cases: + * sqrt(+-0) = +-0 ... exact + * sqrt(inf) = inf + * sqrt(-ve) = NaN ... with invalid signal + * sqrt(NaN) = NaN ... with invalid signal for signaling NaN + * + * Other methods : see the appended file at the end of the program below. + *--------------- + */ + +#include <float.h> + +#include "math.h" +#include "math_private.h" + +static const double one = 1.0, tiny=1.0e-300; + +double +__ieee754_sqrt(double x) +{ + double z; + int32_t sign = (int)0x80000000; + int32_t ix0,s0,q,m,t,i; + u_int32_t r,t1,s1,ix1,q1; + + EXTRACT_WORDS(ix0,ix1,x); + + /* take care of Inf and NaN */ + if((ix0&0x7ff00000)==0x7ff00000) { + return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf + sqrt(-inf)=sNaN */ + } + /* take care of zero */ + if(ix0<=0) { + if(((ix0&(~sign))|ix1)==0) return x;/* sqrt(+-0) = +-0 */ + else if(ix0<0) + return (x-x)/(x-x); /* sqrt(-ve) = sNaN */ + } + /* normalize x */ + m = (ix0>>20); + if(m==0) { /* subnormal x */ + while(ix0==0) { + m -= 21; + ix0 |= (ix1>>11); ix1 <<= 21; + } + for(i=0;(ix0&0x00100000)==0;i++) ix0<<=1; + m -= i-1; + ix0 |= (ix1>>(32-i)); + ix1 <<= i; + } + m -= 1023; /* unbias exponent */ + ix0 = (ix0&0x000fffff)|0x00100000; + if(m&1){ /* odd m, double x to make it even */ + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + } + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + q = q1 = s0 = s1 = 0; /* [q,q1] = sqrt(x) */ + r = 0x00200000; /* r = moving bit from right to left */ + + while(r!=0) { + t = s0+r; + if(t<=ix0) { + s0 = t+r; + ix0 -= t; + q += r; + } + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + r>>=1; + } + + r = sign; + while(r!=0) { + t1 = s1+r; + t = s0; + if((t<ix0)||((t==ix0)&&(t1<=ix1))) { + s1 = t1+r; + if(((t1&sign)==sign)&&(s1&sign)==0) s0 += 1; + ix0 -= t; + if (ix1 < t1) ix0 -= 1; + ix1 -= t1; + q1 += r; + } + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + r>>=1; + } + + /* use floating add to find out rounding direction */ + if((ix0|ix1)!=0) { + z = one-tiny; /* trigger inexact flag */ + if (z>=one) { + z = one+tiny; + if (q1==(u_int32_t)0xffffffff) { q1=0; q += 1;} + else if (z>one) { + if (q1==(u_int32_t)0xfffffffe) q+=1; + q1+=2; + } else + q1 += (q1&1); + } + } + ix0 = (q>>1)+0x3fe00000; + ix1 = q1>>1; + if ((q&1)==1) ix1 |= sign; + ix0 += (m <<20); + INSERT_WORDS(z,ix0,ix1); + return z; +} + +#if (LDBL_MANT_DIG == 53) +__weak_reference(sqrt, sqrtl); +#endif + +/* +Other methods (use floating-point arithmetic) +------------- +(This is a copy of a drafted paper by Prof W. Kahan +and K.C. Ng, written in May, 1986) + + Two algorithms are given here to implement sqrt(x) + (IEEE double precision arithmetic) in software. + Both supply sqrt(x) correctly rounded. The first algorithm (in + Section A) uses newton iterations and involves four divisions. + The second one uses reciproot iterations to avoid division, but + requires more multiplications. Both algorithms need the ability + to chop results of arithmetic operations instead of round them, + and the INEXACT flag to indicate when an arithmetic operation + is executed exactly with no roundoff error, all part of the + standard (IEEE 754-1985). The ability to perform shift, add, + subtract and logical AND operations upon 32-bit words is needed + too, though not part of the standard. + +A. sqrt(x) by Newton Iteration + + (1) Initial approximation + + Let x0 and x1 be the leading and the trailing 32-bit words of + a floating point number x (in IEEE double format) respectively + + 1 11 52 ...widths + ------------------------------------------------------ + x: |s| e | f | + ------------------------------------------------------ + msb lsb msb lsb ...order + + + ------------------------ ------------------------ + x0: |s| e | f1 | x1: | f2 | + ------------------------ ------------------------ + + By performing shifts and subtracts on x0 and x1 (both regarded + as integers), we obtain an 8-bit approximation of sqrt(x) as + follows. + + k := (x0>>1) + 0x1ff80000; + y0 := k - T1[31&(k>>15)]. ... y ~ sqrt(x) to 8 bits + Here k is a 32-bit integer and T1[] is an integer array containing + correction terms. Now magically the floating value of y (y's + leading 32-bit word is y0, the value of its trailing word is 0) + approximates sqrt(x) to almost 8-bit. + + Value of T1: + static int T1[32]= { + 0, 1024, 3062, 5746, 9193, 13348, 18162, 23592, + 29598, 36145, 43202, 50740, 58733, 67158, 75992, 85215, + 83599, 71378, 60428, 50647, 41945, 34246, 27478, 21581, + 16499, 12183, 8588, 5674, 3403, 1742, 661, 130,}; + + (2) Iterative refinement + + Apply Heron's rule three times to y, we have y approximates + sqrt(x) to within 1 ulp (Unit in the Last Place): + + y := (y+x/y)/2 ... almost 17 sig. bits + y := (y+x/y)/2 ... almost 35 sig. bits + y := y-(y-x/y)/2 ... within 1 ulp + + + Remark 1. + Another way to improve y to within 1 ulp is: + + y := (y+x/y) ... almost 17 sig. bits to 2*sqrt(x) + y := y - 0x00100006 ... almost 18 sig. bits to sqrt(x) + + 2 + (x-y )*y + y := y + 2* ---------- ...within 1 ulp + 2 + 3y + x + + + This formula has one division fewer than the one above; however, + it requires more multiplications and additions. Also x must be + scaled in advance to avoid spurious overflow in evaluating the + expression 3y*y+x. Hence it is not recommended uless division + is slow. If division is very slow, then one should use the + reciproot algorithm given in section B. + + (3) Final adjustment + + By twiddling y's last bit it is possible to force y to be + correctly rounded according to the prevailing rounding mode + as follows. Let r and i be copies of the rounding mode and + inexact flag before entering the square root program. Also we + use the expression y+-ulp for the next representable floating + numbers (up and down) of y. Note that y+-ulp = either fixed + point y+-1, or multiply y by nextafter(1,+-inf) in chopped + mode. + + I := FALSE; ... reset INEXACT flag I + R := RZ; ... set rounding mode to round-toward-zero + z := x/y; ... chopped quotient, possibly inexact + If(not I) then { ... if the quotient is exact + if(z=y) { + I := i; ... restore inexact flag + R := r; ... restore rounded mode + return sqrt(x):=y. + } else { + z := z - ulp; ... special rounding + } + } + i := TRUE; ... sqrt(x) is inexact + If (r=RN) then z=z+ulp ... rounded-to-nearest + If (r=RP) then { ... round-toward-+inf + y = y+ulp; z=z+ulp; + } + y := y+z; ... chopped sum + y0:=y0-0x00100000; ... y := y/2 is correctly rounded. + I := i; ... restore inexact flag + R := r; ... restore rounded mode + return sqrt(x):=y. + + (4) Special cases + + Square root of +inf, +-0, or NaN is itself; + Square root of a negative number is NaN with invalid signal. + + +B. sqrt(x) by Reciproot Iteration + + (1) Initial approximation + + Let x0 and x1 be the leading and the trailing 32-bit words of + a floating point number x (in IEEE double format) respectively + (see section A). By performing shifs and subtracts on x0 and y0, + we obtain a 7.8-bit approximation of 1/sqrt(x) as follows. + + k := 0x5fe80000 - (x0>>1); + y0:= k - T2[63&(k>>14)]. ... y ~ 1/sqrt(x) to 7.8 bits + + Here k is a 32-bit integer and T2[] is an integer array + containing correction terms. Now magically the floating + value of y (y's leading 32-bit word is y0, the value of + its trailing word y1 is set to zero) approximates 1/sqrt(x) + to almost 7.8-bit. + + Value of T2: + static int T2[64]= { + 0x1500, 0x2ef8, 0x4d67, 0x6b02, 0x87be, 0xa395, 0xbe7a, 0xd866, + 0xf14a, 0x1091b,0x11fcd,0x13552,0x14999,0x15c98,0x16e34,0x17e5f, + 0x18d03,0x19a01,0x1a545,0x1ae8a,0x1b5c4,0x1bb01,0x1bfde,0x1c28d, + 0x1c2de,0x1c0db,0x1ba73,0x1b11c,0x1a4b5,0x1953d,0x18266,0x16be0, + 0x1683e,0x179d8,0x18a4d,0x19992,0x1a789,0x1b445,0x1bf61,0x1c989, + 0x1d16d,0x1d77b,0x1dddf,0x1e2ad,0x1e5bf,0x1e6e8,0x1e654,0x1e3cd, + 0x1df2a,0x1d635,0x1cb16,0x1be2c,0x1ae4e,0x19bde,0x1868e,0x16e2e, + 0x1527f,0x1334a,0x11051,0xe951, 0xbe01, 0x8e0d, 0x5924, 0x1edd,}; + + (2) Iterative refinement + + Apply Reciproot iteration three times to y and multiply the + result by x to get an approximation z that matches sqrt(x) + to about 1 ulp. To be exact, we will have + -1ulp < sqrt(x)-z<1.0625ulp. + + ... set rounding mode to Round-to-nearest + y := y*(1.5-0.5*x*y*y) ... almost 15 sig. bits to 1/sqrt(x) + y := y*((1.5-2^-30)+0.5*x*y*y)... about 29 sig. bits to 1/sqrt(x) + ... special arrangement for better accuracy + z := x*y ... 29 bits to sqrt(x), with z*y<1 + z := z + 0.5*z*(1-z*y) ... about 1 ulp to sqrt(x) + + Remark 2. The constant 1.5-2^-30 is chosen to bias the error so that + (a) the term z*y in the final iteration is always less than 1; + (b) the error in the final result is biased upward so that + -1 ulp < sqrt(x) - z < 1.0625 ulp + instead of |sqrt(x)-z|<1.03125ulp. + + (3) Final adjustment + + By twiddling y's last bit it is possible to force y to be + correctly rounded according to the prevailing rounding mode + as follows. Let r and i be copies of the rounding mode and + inexact flag before entering the square root program. Also we + use the expression y+-ulp for the next representable floating + numbers (up and down) of y. Note that y+-ulp = either fixed + point y+-1, or multiply y by nextafter(1,+-inf) in chopped + mode. + + R := RZ; ... set rounding mode to round-toward-zero + switch(r) { + case RN: ... round-to-nearest + if(x<= z*(z-ulp)...chopped) z = z - ulp; else + if(x<= z*(z+ulp)...chopped) z = z; else z = z+ulp; + break; + case RZ:case RM: ... round-to-zero or round-to--inf + R:=RP; ... reset rounding mod to round-to-+inf + if(x<z*z ... rounded up) z = z - ulp; else + if(x>=(z+ulp)*(z+ulp) ...rounded up) z = z+ulp; + break; + case RP: ... round-to-+inf + if(x>(z+ulp)*(z+ulp)...chopped) z = z+2*ulp; else + if(x>z*z ...chopped) z = z+ulp; + break; + } + + Remark 3. The above comparisons can be done in fixed point. For + example, to compare x and w=z*z chopped, it suffices to compare + x1 and w1 (the trailing parts of x and w), regarding them as + two's complement integers. + + ...Is z an exact square root? + To determine whether z is an exact square root of x, let z1 be the + trailing part of z, and also let x0 and x1 be the leading and + trailing parts of x. + + If ((z1&0x03ffffff)!=0) ... not exact if trailing 26 bits of z!=0 + I := 1; ... Raise Inexact flag: z is not exact + else { + j := 1 - [(x0>>20)&1] ... j = logb(x) mod 2 + k := z1 >> 26; ... get z's 25-th and 26-th + fraction bits + I := i or (k&j) or ((k&(j+j+1))!=(x1&3)); + } + R:= r ... restore rounded mode + return sqrt(x):=z. + + If multiplication is cheaper then the foregoing red tape, the + Inexact flag can be evaluated by + + I := i; + I := (z*z!=x) or I. + + Note that z*z can overwrite I; this value must be sensed if it is + True. + + Remark 4. If z*z = x exactly, then bit 25 to bit 0 of z1 must be + zero. + + -------------------- + z1: | f2 | + -------------------- + bit 31 bit 0 + + Further more, bit 27 and 26 of z1, bit 0 and 1 of x1, and the odd + or even of logb(x) have the following relations: + + ------------------------------------------------- + bit 27,26 of z1 bit 1,0 of x1 logb(x) + ------------------------------------------------- + 00 00 odd and even + 01 01 even + 10 10 odd + 10 00 even + 11 01 even + ------------------------------------------------- + + (4) Special cases (see (4) of Section A). + + */ + diff --git a/libm/upstream-freebsd/lib/msun/src/e_sqrtf.c b/libm/upstream-freebsd/lib/msun/src/e_sqrtf.c new file mode 100644 index 0000000..7eba4d0 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_sqrtf.c @@ -0,0 +1,89 @@ +/* e_sqrtf.c -- float version of e_sqrt.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef lint +static char rcsid[] = "$FreeBSD$"; +#endif + +#include "math.h" +#include "math_private.h" + +static const float one = 1.0, tiny=1.0e-30; + +float +__ieee754_sqrtf(float x) +{ + float z; + int32_t sign = (int)0x80000000; + int32_t ix,s,q,m,t,i; + u_int32_t r; + + GET_FLOAT_WORD(ix,x); + + /* take care of Inf and NaN */ + if((ix&0x7f800000)==0x7f800000) { + return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf + sqrt(-inf)=sNaN */ + } + /* take care of zero */ + if(ix<=0) { + if((ix&(~sign))==0) return x;/* sqrt(+-0) = +-0 */ + else if(ix<0) + return (x-x)/(x-x); /* sqrt(-ve) = sNaN */ + } + /* normalize x */ + m = (ix>>23); + if(m==0) { /* subnormal x */ + for(i=0;(ix&0x00800000)==0;i++) ix<<=1; + m -= i-1; + } + m -= 127; /* unbias exponent */ + ix = (ix&0x007fffff)|0x00800000; + if(m&1) /* odd m, double x to make it even */ + ix += ix; + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix += ix; + q = s = 0; /* q = sqrt(x) */ + r = 0x01000000; /* r = moving bit from right to left */ + + while(r!=0) { + t = s+r; + if(t<=ix) { + s = t+r; + ix -= t; + q += r; + } + ix += ix; + r>>=1; + } + + /* use floating add to find out rounding direction */ + if(ix!=0) { + z = one-tiny; /* trigger inexact flag */ + if (z>=one) { + z = one+tiny; + if (z>one) + q += 2; + else + q += (q&1); + } + } + ix = (q>>1)+0x3f000000; + ix += (m <<23); + SET_FLOAT_WORD(z,ix); + return z; +} diff --git a/libm/upstream-freebsd/lib/msun/src/e_sqrtl.c b/libm/upstream-freebsd/lib/msun/src/e_sqrtl.c new file mode 100644 index 0000000..92b84de --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/e_sqrtl.c @@ -0,0 +1,159 @@ +/*- + * Copyright (c) 2007 Steven G. Kargl + * All rights reserved. + * + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <fenv.h> +#include <float.h> + +#include "fpmath.h" +#include "math.h" + +/* Return (x + ulp) for normal positive x. Assumes no overflow. */ +static inline long double +inc(long double x) +{ + union IEEEl2bits u; + + u.e = x; + if (++u.bits.manl == 0) { + if (++u.bits.manh == 0) { + u.bits.exp++; + u.bits.manh |= LDBL_NBIT; + } + } + return (u.e); +} + +/* Return (x - ulp) for normal positive x. Assumes no underflow. */ +static inline long double +dec(long double x) +{ + union IEEEl2bits u; + + u.e = x; + if (u.bits.manl-- == 0) { + if (u.bits.manh-- == LDBL_NBIT) { + u.bits.exp--; + u.bits.manh |= LDBL_NBIT; + } + } + return (u.e); +} + +#pragma STDC FENV_ACCESS ON + +/* + * This is slow, but simple and portable. You should use hardware sqrt + * if possible. + */ + +long double +sqrtl(long double x) +{ + union IEEEl2bits u; + int k, r; + long double lo, xn; + fenv_t env; + + u.e = x; + + /* If x = NaN, then sqrt(x) = NaN. */ + /* If x = Inf, then sqrt(x) = Inf. */ + /* If x = -Inf, then sqrt(x) = NaN. */ + if (u.bits.exp == LDBL_MAX_EXP * 2 - 1) + return (x * x + x); + + /* If x = +-0, then sqrt(x) = +-0. */ + if ((u.bits.manh | u.bits.manl | u.bits.exp) == 0) + return (x); + + /* If x < 0, then raise invalid and return NaN */ + if (u.bits.sign) + return ((x - x) / (x - x)); + + feholdexcept(&env); + + if (u.bits.exp == 0) { + /* Adjust subnormal numbers. */ + u.e *= 0x1.0p514; + k = -514; + } else { + k = 0; + } + /* + * u.e is a normal number, so break it into u.e = e*2^n where + * u.e = (2*e)*2^2k for odd n and u.e = (4*e)*2^2k for even n. + */ + if ((u.bits.exp - 0x3ffe) & 1) { /* n is odd. */ + k += u.bits.exp - 0x3fff; /* 2k = n - 1. */ + u.bits.exp = 0x3fff; /* u.e in [1,2). */ + } else { + k += u.bits.exp - 0x4000; /* 2k = n - 2. */ + u.bits.exp = 0x4000; /* u.e in [2,4). */ + } + + /* + * Newton's iteration. + * Split u.e into a high and low part to achieve additional precision. + */ + xn = sqrt(u.e); /* 53-bit estimate of sqrtl(x). */ +#if LDBL_MANT_DIG > 100 + xn = (xn + (u.e / xn)) * 0.5; /* 106-bit estimate. */ +#endif + lo = u.e; + u.bits.manl = 0; /* Zero out lower bits. */ + lo = (lo - u.e) / xn; /* Low bits divided by xn. */ + xn = xn + (u.e / xn); /* High portion of estimate. */ + u.e = xn + lo; /* Combine everything. */ + u.bits.exp += (k >> 1) - 1; + + feclearexcept(FE_INEXACT); + r = fegetround(); + fesetround(FE_TOWARDZERO); /* Set to round-toward-zero. */ + xn = x / u.e; /* Chopped quotient (inexact?). */ + + if (!fetestexcept(FE_INEXACT)) { /* Quotient is exact. */ + if (xn == u.e) { + fesetenv(&env); + return (u.e); + } + /* Round correctly for inputs like x = y**2 - ulp. */ + xn = dec(xn); /* xn = xn - ulp. */ + } + + if (r == FE_TONEAREST) { + xn = inc(xn); /* xn = xn + ulp. */ + } else if (r == FE_UPWARD) { + u.e = inc(u.e); /* u.e = u.e + ulp. */ + xn = inc(xn); /* xn = xn + ulp. */ + } + u.e = u.e + xn; /* Chopped sum. */ + feupdateenv(&env); /* Restore env and raise inexact */ + u.bits.exp--; + return (u.e); +} diff --git a/libm/upstream-freebsd/lib/msun/src/fenv-softfloat.h b/libm/upstream-freebsd/lib/msun/src/fenv-softfloat.h new file mode 100644 index 0000000..02d2a2c --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/fenv-softfloat.h @@ -0,0 +1,184 @@ +/*- + * Copyright (c) 2004-2011 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef _FENV_H_ +#error "This file is meant to be included only by <fenv.h>." +#endif + +/* + * This file implements the functionality of <fenv.h> on platforms that + * lack an FPU and use softfloat in libc for floating point. To use it, + * you must write an <fenv.h> that provides the following: + * + * - a typedef for fenv_t, which may be an integer or struct type + * - a typedef for fexcept_t (XXX This file assumes fexcept_t is a + * simple integer type containing the exception mask.) + * - definitions of FE_* constants for the five exceptions and four + * rounding modes in IEEE 754, as described in fenv(3) + * - a definition, and the corresponding external symbol, for FE_DFL_ENV + * - a macro __set_env(env, flags, mask, rnd), which sets the given fenv_t + * from the exception flags, mask, and rounding mode + * - macros __env_flags(env), __env_mask(env), and __env_round(env), which + * extract fields from an fenv_t + * - a definition of __fenv_static + * + * If the architecture supports an optional FPU, it's recommended that you + * define fenv_t and fexcept_t to match the hardware ABI. Otherwise, it + * doesn't matter how you define them. + */ + +extern int __softfloat_float_exception_flags; +extern int __softfloat_float_exception_mask; +extern int __softfloat_float_rounding_mode; +void __softfloat_float_raise(int); + +__fenv_static inline int +feclearexcept(int __excepts) +{ + + __softfloat_float_exception_flags &= ~__excepts; + return (0); +} + +__fenv_static inline int +fegetexceptflag(fexcept_t *__flagp, int __excepts) +{ + + *__flagp = __softfloat_float_exception_flags & __excepts; + return (0); +} + +__fenv_static inline int +fesetexceptflag(const fexcept_t *__flagp, int __excepts) +{ + + __softfloat_float_exception_flags &= ~__excepts; + __softfloat_float_exception_flags |= *__flagp & __excepts; + return (0); +} + +__fenv_static inline int +feraiseexcept(int __excepts) +{ + + __softfloat_float_raise(__excepts); + return (0); +} + +__fenv_static inline int +fetestexcept(int __excepts) +{ + + return (__softfloat_float_exception_flags & __excepts); +} + +__fenv_static inline int +fegetround(void) +{ + + return (__softfloat_float_rounding_mode); +} + +__fenv_static inline int +fesetround(int __round) +{ + + __softfloat_float_rounding_mode = __round; + return (0); +} + +__fenv_static inline int +fegetenv(fenv_t *__envp) +{ + + __set_env(*__envp, __softfloat_float_exception_flags, + __softfloat_float_exception_mask, __softfloat_float_rounding_mode); + return (0); +} + +__fenv_static inline int +feholdexcept(fenv_t *__envp) +{ + fenv_t __env; + + fegetenv(__envp); + __softfloat_float_exception_flags = 0; + __softfloat_float_exception_mask = 0; + return (0); +} + +__fenv_static inline int +fesetenv(const fenv_t *__envp) +{ + + __softfloat_float_exception_flags = __env_flags(*__envp); + __softfloat_float_exception_mask = __env_mask(*__envp); + __softfloat_float_rounding_mode = __env_round(*__envp); + return (0); +} + +__fenv_static inline int +feupdateenv(const fenv_t *__envp) +{ + int __oflags = __softfloat_float_exception_flags; + + fesetenv(__envp); + feraiseexcept(__oflags); + return (0); +} + +#if __BSD_VISIBLE + +/* We currently provide no external definitions of the functions below. */ + +static inline int +feenableexcept(int __mask) +{ + int __omask = __softfloat_float_exception_mask; + + __softfloat_float_exception_mask |= __mask; + return (__omask); +} + +static inline int +fedisableexcept(int __mask) +{ + int __omask = __softfloat_float_exception_mask; + + __softfloat_float_exception_mask &= ~__mask; + return (__omask); +} + +static inline int +fegetexcept(void) +{ + + return (__softfloat_float_exception_mask); +} + +#endif /* __BSD_VISIBLE */ diff --git a/libm/upstream-freebsd/lib/msun/src/k_cos.c b/libm/upstream-freebsd/lib/msun/src/k_cos.c new file mode 100644 index 0000000..c4702e6 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/k_cos.c @@ -0,0 +1,79 @@ + +/* @(#)k_cos.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * __kernel_cos( x, y ) + * kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * + * Algorithm + * 1. Since cos(-x) = cos(x), we need only to consider positive x. + * 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0. + * 3. cos(x) is approximated by a polynomial of degree 14 on + * [0,pi/4] + * 4 14 + * cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x + * where the remez error is + * + * | 2 4 6 8 10 12 14 | -58 + * |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2 + * | | + * + * 4 6 8 10 12 14 + * 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then + * cos(x) ~ 1 - x*x/2 + r + * since cos(x+y) ~ cos(x) - sin(x)*y + * ~ cos(x) - x*y, + * a correction term is necessary in cos(x) and hence + * cos(x+y) = 1 - (x*x/2 - (r - x*y)) + * For better accuracy, rearrange to + * cos(x+y) ~ w + (tmp + (r-x*y)) + * where w = 1 - x*x/2 and tmp is a tiny correction term + * (1 - x*x/2 == w + tmp exactly in infinite precision). + * The exactness of w + tmp in infinite precision depends on w + * and tmp having the same precision as x. If they have extra + * precision due to compiler bugs, then the extra precision is + * only good provided it is retained in all terms of the final + * expression for cos(). Retention happens in all cases tested + * under FreeBSD, so don't pessimize things by forcibly clipping + * any extra precision in w. + */ + +#include "math.h" +#include "math_private.h" + +static const double +one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */ +C1 = 4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */ +C2 = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */ +C3 = 2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */ +C4 = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */ +C5 = 2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */ +C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ + +double +__kernel_cos(double x, double y) +{ + double hz,z,r,w; + + z = x*x; + w = z*z; + r = z*(C1+z*(C2+z*C3)) + w*w*(C4+z*(C5+z*C6)); + hz = 0.5*z; + w = one-hz; + return w + (((one-w)-hz) + (z*r-x*y)); +} diff --git a/libm/upstream-freebsd/lib/msun/src/k_cosf.c b/libm/upstream-freebsd/lib/msun/src/k_cosf.c new file mode 100644 index 0000000..f7a2c0a --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/k_cosf.c @@ -0,0 +1,46 @@ +/* k_cosf.c -- float version of k_cos.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef INLINE_KERNEL_COSDF +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); +#endif + +#include "math.h" +#include "math_private.h" + +/* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ +static const double +one = 1.0, +C0 = -0x1ffffffd0c5e81.0p-54, /* -0.499999997251031003120 */ +C1 = 0x155553e1053a42.0p-57, /* 0.0416666233237390631894 */ +C2 = -0x16c087e80f1e27.0p-62, /* -0.00138867637746099294692 */ +C3 = 0x199342e0ee5069.0p-68; /* 0.0000243904487962774090654 */ + +#ifdef INLINE_KERNEL_COSDF +static __inline +#endif +float +__kernel_cosdf(double x) +{ + double r, w, z; + + /* Try to optimize for parallel evaluation as in k_tanf.c. */ + z = x*x; + w = z*z; + r = C2+z*C3; + return ((one+z*C0) + w*C1) + (w*z)*r; +} diff --git a/libm/upstream-freebsd/lib/msun/src/k_exp.c b/libm/upstream-freebsd/lib/msun/src/k_exp.c new file mode 100644 index 0000000..f592f69 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/k_exp.c @@ -0,0 +1,108 @@ +/*- + * Copyright (c) 2011 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <complex.h> + +#include "math.h" +#include "math_private.h" + +static const uint32_t k = 1799; /* constant for reduction */ +static const double kln2 = 1246.97177782734161156; /* k * ln2 */ + +/* + * Compute exp(x), scaled to avoid spurious overflow. An exponent is + * returned separately in 'expt'. + * + * Input: ln(DBL_MAX) <= x < ln(2 * DBL_MAX / DBL_MIN_DENORM) ~= 1454.91 + * Output: 2**1023 <= y < 2**1024 + */ +static double +__frexp_exp(double x, int *expt) +{ + double exp_x; + uint32_t hx; + + /* + * We use exp(x) = exp(x - kln2) * 2**k, carefully chosen to + * minimize |exp(kln2) - 2**k|. We also scale the exponent of + * exp_x to MAX_EXP so that the result can be multiplied by + * a tiny number without losing accuracy due to denormalization. + */ + exp_x = exp(x - kln2); + GET_HIGH_WORD(hx, exp_x); + *expt = (hx >> 20) - (0x3ff + 1023) + k; + SET_HIGH_WORD(exp_x, (hx & 0xfffff) | ((0x3ff + 1023) << 20)); + return (exp_x); +} + +/* + * __ldexp_exp(x, expt) and __ldexp_cexp(x, expt) compute exp(x) * 2**expt. + * They are intended for large arguments (real part >= ln(DBL_MAX)) + * where care is needed to avoid overflow. + * + * The present implementation is narrowly tailored for our hyperbolic and + * exponential functions. We assume expt is small (0 or -1), and the caller + * has filtered out very large x, for which overflow would be inevitable. + */ + +double +__ldexp_exp(double x, int expt) +{ + double exp_x, scale; + int ex_expt; + + exp_x = __frexp_exp(x, &ex_expt); + expt += ex_expt; + INSERT_WORDS(scale, (0x3ff + expt) << 20, 0); + return (exp_x * scale); +} + +double complex +__ldexp_cexp(double complex z, int expt) +{ + double x, y, exp_x, scale1, scale2; + int ex_expt, half_expt; + + x = creal(z); + y = cimag(z); + exp_x = __frexp_exp(x, &ex_expt); + expt += ex_expt; + + /* + * Arrange so that scale1 * scale2 == 2**expt. We use this to + * compensate for scalbn being horrendously slow. + */ + half_expt = expt / 2; + INSERT_WORDS(scale1, (0x3ff + half_expt) << 20, 0); + half_expt = expt - half_expt; + INSERT_WORDS(scale2, (0x3ff + half_expt) << 20, 0); + + return (cpack(cos(y) * exp_x * scale1 * scale2, + sin(y) * exp_x * scale1 * scale2)); +} diff --git a/libm/upstream-freebsd/lib/msun/src/k_expf.c b/libm/upstream-freebsd/lib/msun/src/k_expf.c new file mode 100644 index 0000000..548a008 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/k_expf.c @@ -0,0 +1,87 @@ +/*- + * Copyright (c) 2011 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <complex.h> + +#include "math.h" +#include "math_private.h" + +static const uint32_t k = 235; /* constant for reduction */ +static const float kln2 = 162.88958740F; /* k * ln2 */ + +/* + * See k_exp.c for details. + * + * Input: ln(FLT_MAX) <= x < ln(2 * FLT_MAX / FLT_MIN_DENORM) ~= 192.7 + * Output: 2**127 <= y < 2**128 + */ +static float +__frexp_expf(float x, int *expt) +{ + float exp_x; + uint32_t hx; + + exp_x = expf(x - kln2); + GET_FLOAT_WORD(hx, exp_x); + *expt = (hx >> 23) - (0x7f + 127) + k; + SET_FLOAT_WORD(exp_x, (hx & 0x7fffff) | ((0x7f + 127) << 23)); + return (exp_x); +} + +float +__ldexp_expf(float x, int expt) +{ + float exp_x, scale; + int ex_expt; + + exp_x = __frexp_expf(x, &ex_expt); + expt += ex_expt; + SET_FLOAT_WORD(scale, (0x7f + expt) << 23); + return (exp_x * scale); +} + +float complex +__ldexp_cexpf(float complex z, int expt) +{ + float x, y, exp_x, scale1, scale2; + int ex_expt, half_expt; + + x = crealf(z); + y = cimagf(z); + exp_x = __frexp_expf(x, &ex_expt); + expt += ex_expt; + + half_expt = expt / 2; + SET_FLOAT_WORD(scale1, (0x7f + half_expt) << 23); + half_expt = expt - half_expt; + SET_FLOAT_WORD(scale2, (0x7f + half_expt) << 23); + + return (cpackf(cosf(y) * exp_x * scale1 * scale2, + sinf(y) * exp_x * scale1 * scale2)); +} diff --git a/libm/upstream-freebsd/lib/msun/src/k_log.h b/libm/upstream-freebsd/lib/msun/src/k_log.h new file mode 100644 index 0000000..aaff8bd --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/k_log.h @@ -0,0 +1,100 @@ + +/* @(#)e_log.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * k_log1p(f): + * Return log(1+f) - f for 1+f in ~[sqrt(2)/2, sqrt(2)]. + * + * The following describes the overall strategy for computing + * logarithms in base e. The argument reduction and adding the final + * term of the polynomial are done by the caller for increased accuracy + * when different bases are used. + * + * Method : + * 1. Argument Reduction: find k and f such that + * x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * 2. Approximation of log(1+f). + * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) + * = 2s + 2/3 s**3 + 2/5 s**5 + ....., + * = 2s + s*R + * We use a special Reme algorithm on [0,0.1716] to generate + * a polynomial of degree 14 to approximate R The maximum error + * of this polynomial approximation is bounded by 2**-58.45. In + * other words, + * 2 4 6 8 10 12 14 + * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s + * (the values of Lg1 to Lg7 are listed in the program) + * and + * | 2 14 | -58.45 + * | Lg1*s +...+Lg7*s - R(z) | <= 2 + * | | + * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. + * In order to guarantee error in log below 1ulp, we compute log + * by + * log(1+f) = f - s*(f - R) (if f is not too large) + * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy) + * + * 3. Finally, log(x) = k*ln2 + log(1+f). + * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) + * Here ln2 is split into two floating point number: + * ln2_hi + ln2_lo, + * where n*ln2_hi is always exact for |n| < 2000. + * + * Special cases: + * log(x) is NaN with signal if x < 0 (including -INF) ; + * log(+INF) is +INF; log(0) is -INF with signal; + * log(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +static const double +Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ +Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ +Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ +Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ +Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ +Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ +Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +/* + * We always inline k_log1p(), since doing so produces a + * substantial performance improvement (~40% on amd64). + */ +static inline double +k_log1p(double f) +{ + double hfsq,s,z,R,w,t1,t2; + + s = f/(2.0+f); + z = s*s; + w = z*z; + t1= w*(Lg2+w*(Lg4+w*Lg6)); + t2= z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); + R = t2+t1; + hfsq=0.5*f*f; + return s*(hfsq+R); +} diff --git a/libm/upstream-freebsd/lib/msun/src/k_logf.h b/libm/upstream-freebsd/lib/msun/src/k_logf.h new file mode 100644 index 0000000..71c547e --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/k_logf.h @@ -0,0 +1,39 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Float version of k_log.h. See the latter for most comments. + */ + +static const float +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */ +Lg2 = 0xccce13.0p-25, /* 0.40000972152 */ +Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */ +Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */ + +static inline float +k_log1pf(float f) +{ + float hfsq,s,z,R,w,t1,t2; + + s = f/((float)2.0+f); + z = s*s; + w = z*z; + t1= w*(Lg2+w*Lg4); + t2= z*(Lg1+w*Lg3); + R = t2+t1; + hfsq=(float)0.5*f*f; + return s*(hfsq+R); +} diff --git a/libm/upstream-freebsd/lib/msun/src/k_rem_pio2.c b/libm/upstream-freebsd/lib/msun/src/k_rem_pio2.c new file mode 100644 index 0000000..3942441 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/k_rem_pio2.c @@ -0,0 +1,443 @@ + +/* @(#)k_rem_pio2.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * __kernel_rem_pio2(x,y,e0,nx,prec) + * double x[],y[]; int e0,nx,prec; + * + * __kernel_rem_pio2 return the last three digits of N with + * y = x - N*pi/2 + * so that |y| < pi/2. + * + * The method is to compute the integer (mod 8) and fraction parts of + * (2/pi)*x without doing the full multiplication. In general we + * skip the part of the product that are known to be a huge integer ( + * more accurately, = 0 mod 8 ). Thus the number of operations are + * independent of the exponent of the input. + * + * (2/pi) is represented by an array of 24-bit integers in ipio2[]. + * + * Input parameters: + * x[] The input value (must be positive) is broken into nx + * pieces of 24-bit integers in double precision format. + * x[i] will be the i-th 24 bit of x. The scaled exponent + * of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 + * match x's up to 24 bits. + * + * Example of breaking a double positive z into x[0]+x[1]+x[2]: + * e0 = ilogb(z)-23 + * z = scalbn(z,-e0) + * for i = 0,1,2 + * x[i] = floor(z) + * z = (z-x[i])*2**24 + * + * + * y[] output result in an array of double precision numbers. + * The dimension of y[] is: + * 24-bit precision 1 + * 53-bit precision 2 + * 64-bit precision 2 + * 113-bit precision 3 + * The actual value is the sum of them. Thus for 113-bit + * precison, one may have to do something like: + * + * long double t,w,r_head, r_tail; + * t = (long double)y[2] + (long double)y[1]; + * w = (long double)y[0]; + * r_head = t+w; + * r_tail = w - (r_head - t); + * + * e0 The exponent of x[0]. Must be <= 16360 or you need to + * expand the ipio2 table. + * + * nx dimension of x[] + * + * prec an integer indicating the precision: + * 0 24 bits (single) + * 1 53 bits (double) + * 2 64 bits (extended) + * 3 113 bits (quad) + * + * External function: + * double scalbn(), floor(); + * + * + * Here is the description of some local variables: + * + * jk jk+1 is the initial number of terms of ipio2[] needed + * in the computation. The minimum and recommended value + * for jk is 3,4,4,6 for single, double, extended, and quad. + * jk+1 must be 2 larger than you might expect so that our + * recomputation test works. (Up to 24 bits in the integer + * part (the 24 bits of it that we compute) and 23 bits in + * the fraction part may be lost to cancelation before we + * recompute.) + * + * jz local integer variable indicating the number of + * terms of ipio2[] used. + * + * jx nx - 1 + * + * jv index for pointing to the suitable ipio2[] for the + * computation. In general, we want + * ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 + * is an integer. Thus + * e0-3-24*jv >= 0 or (e0-3)/24 >= jv + * Hence jv = max(0,(e0-3)/24). + * + * jp jp+1 is the number of terms in PIo2[] needed, jp = jk. + * + * q[] double array with integral value, representing the + * 24-bits chunk of the product of x and 2/pi. + * + * q0 the corresponding exponent of q[0]. Note that the + * exponent for q[i] would be q0-24*i. + * + * PIo2[] double precision array, obtained by cutting pi/2 + * into 24 bits chunks. + * + * f[] ipio2[] in floating point + * + * iq[] integer array by breaking up q[] in 24-bits chunk. + * + * fq[] final product of x*(2/pi) in fq[0],..,fq[jk] + * + * ih integer. If >0 it indicates q[] is >= 0.5, hence + * it also indicates the *sign* of the result. + * + */ + + +/* + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include <float.h> + +#include "math.h" +#include "math_private.h" + +static const int init_jk[] = {3,4,4,6}; /* initial value for jk */ + +/* + * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi + * + * integer array, contains the (24*i)-th to (24*i+23)-th + * bit of 2/pi after binary point. The corresponding + * floating value is + * + * ipio2[i] * 2^(-24(i+1)). + * + * NB: This table must have at least (e0-3)/24 + jk terms. + * For quad precision (e0 <= 16360, jk = 6), this is 686. + */ +static const int32_t ipio2[] = { +0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, +0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, +0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, +0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, +0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, +0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, +0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, +0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, +0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, +0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, +0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, + +#if LDBL_MAX_EXP > 1024 +#if LDBL_MAX_EXP > 16384 +#error "ipio2 table needs to be expanded" +#endif +0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, +0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2, +0xDE4F98, 0x327DBB, 0xC33D26, 0xEF6B1E, 0x5EF89F, 0x3A1F35, +0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, +0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C, +0x467D86, 0x2D71E3, 0x9AC69B, 0x006233, 0x7CD2B4, 0x97A7B4, +0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, +0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7, +0xCB2324, 0x778AD6, 0x23545A, 0xB91F00, 0x1B0AF1, 0xDFCE19, +0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, +0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16, +0xDE3B58, 0x929BDE, 0x2822D2, 0xE88628, 0x4D58E2, 0x32CAC6, +0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, +0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48, +0xD36710, 0xD8DDAA, 0x425FAE, 0xCE616A, 0xA4280A, 0xB499D3, +0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, +0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55, +0x36D9CA, 0xD2A828, 0x8D61C2, 0x77C912, 0x142604, 0x9B4612, +0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, +0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC, +0xC3E7B3, 0x28F8C7, 0x940593, 0x3E71C1, 0xB3092E, 0xF3450B, +0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, +0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4, +0x9794E8, 0x84E6E2, 0x973199, 0x6BED88, 0x365F5F, 0x0EFDBB, +0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, +0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C, +0x90AA47, 0x02E774, 0x24D6BD, 0xA67DF7, 0x72486E, 0xEF169F, +0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, +0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437, +0x10D86D, 0x324832, 0x754C5B, 0xD4714E, 0x6E5445, 0xC1090B, +0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, +0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD, +0x6AE290, 0x89D988, 0x50722C, 0xBEA404, 0x940777, 0x7030F3, +0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, +0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717, +0x3BDF08, 0x2B3715, 0xA0805C, 0x93805A, 0x921110, 0xD8E80F, +0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, +0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB, +0xAA140A, 0x2F2689, 0x768364, 0x333B09, 0x1A940E, 0xAA3A51, +0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, +0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C, +0x5BC3D8, 0xC492F5, 0x4BADC6, 0xA5CA4E, 0xCD37A7, 0x36A9E6, +0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, +0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED, +0x306529, 0xBF5657, 0x3AFF47, 0xB9F96A, 0xF3BE75, 0xDF9328, +0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, +0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0, +0xA8654F, 0xA5C1D2, 0x0F3F0B, 0xCD785B, 0x76F923, 0x048B7B, +0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, +0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3, +0xDA4886, 0xA05DF7, 0xF480C6, 0x2FF0AC, 0x9AECDD, 0xBC5C3F, +0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, +0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B, +0x2A1216, 0x2DB7DC, 0xFDE5FA, 0xFEDB89, 0xFDBE89, 0x6C76E4, +0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, +0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31, +0x48D784, 0x16DF30, 0x432DC7, 0x356125, 0xCE70C9, 0xB8CB30, +0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, +0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E, +0xC4F133, 0x5F6E13, 0xE4305D, 0xA92E85, 0xC3B21D, 0x3632A1, +0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, +0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4, +0xCBDA11, 0xD0BE7D, 0xC1DB9B, 0xBD17AB, 0x81A2CA, 0x5C6A08, +0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, +0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9, +0x4F6A68, 0xA82A4A, 0x5AC44F, 0xBCF82D, 0x985AD7, 0x95C7F4, +0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, +0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C, +0xD0C0B2, 0x485551, 0x0EFB1E, 0xC37295, 0x3B06A3, 0x3540C0, +0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, +0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0, +0x3C3ABA, 0x461846, 0x5F7555, 0xF5BDD2, 0xC6926E, 0x5D2EAC, +0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, +0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893, +0x745D7C, 0xB2AD6B, 0x9D6ECD, 0x7B723E, 0x6A11C6, 0xA9CFF7, +0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, +0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F, +0xBEFDFD, 0xEF4556, 0x367ED9, 0x13D9EC, 0xB9BA8B, 0xFC97C4, +0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, +0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B, +0x9C2A3E, 0xCC5F11, 0x4A0BFD, 0xFBF4E1, 0x6D3B8E, 0x2C86E2, +0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, +0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E, +0xCC2254, 0xDC552A, 0xD6C6C0, 0x96190B, 0xB8701A, 0x649569, +0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, +0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9, +0x9B5861, 0xBC57E1, 0xC68351, 0x103ED8, 0x4871DD, 0xDD1C2D, +0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, +0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855, +0x382682, 0x9BE7CA, 0xA40D51, 0xB13399, 0x0ED7A9, 0x480569, +0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, +0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE, +0x5FD45E, 0xA4677B, 0x7AACBA, 0xA2F655, 0x23882B, 0x55BA41, +0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, +0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F, +0xAE5ADB, 0x86C547, 0x624385, 0x3B8621, 0x94792C, 0x876110, +0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, +0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365, +0xB1933D, 0x0B7CBD, 0xDC51A4, 0x63DD27, 0xDDE169, 0x19949A, +0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, +0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5, +0x4D7E6F, 0x5119A5, 0xABF9B5, 0xD6DF82, 0x61DD96, 0x023616, +0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, +0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0, +#endif + +}; + +static const double PIo2[] = { + 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ + 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ + 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ + 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ + 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ + 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ + 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ + 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ +}; + +static const double +zero = 0.0, +one = 1.0, +two24 = 1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */ +twon24 = 5.96046447753906250000e-08; /* 0x3E700000, 0x00000000 */ + +int +__kernel_rem_pio2(double *x, double *y, int e0, int nx, int prec) +{ + int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih; + double z,fw,f[20],fq[20],q[20]; + + /* initialize jk*/ + jk = init_jk[prec]; + jp = jk; + + /* determine jx,jv,q0, note that 3>q0 */ + jx = nx-1; + jv = (e0-3)/24; if(jv<0) jv=0; + q0 = e0-24*(jv+1); + + /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ + j = jv-jx; m = jx+jk; + for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (double) ipio2[j]; + + /* compute q[0],q[1],...q[jk] */ + for (i=0;i<=jk;i++) { + for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw; + } + + jz = jk; +recompute: + /* distill q[] into iq[] reversingly */ + for(i=0,j=jz,z=q[jz];j>0;i++,j--) { + fw = (double)((int32_t)(twon24* z)); + iq[i] = (int32_t)(z-two24*fw); + z = q[j-1]+fw; + } + + /* compute n */ + z = scalbn(z,q0); /* actual value of z */ + z -= 8.0*floor(z*0.125); /* trim off integer >= 8 */ + n = (int32_t) z; + z -= (double)n; + ih = 0; + if(q0>0) { /* need iq[jz-1] to determine n */ + i = (iq[jz-1]>>(24-q0)); n += i; + iq[jz-1] -= i<<(24-q0); + ih = iq[jz-1]>>(23-q0); + } + else if(q0==0) ih = iq[jz-1]>>23; + else if(z>=0.5) ih=2; + + if(ih>0) { /* q > 0.5 */ + n += 1; carry = 0; + for(i=0;i<jz ;i++) { /* compute 1-q */ + j = iq[i]; + if(carry==0) { + if(j!=0) { + carry = 1; iq[i] = 0x1000000- j; + } + } else iq[i] = 0xffffff - j; + } + if(q0>0) { /* rare case: chance is 1 in 12 */ + switch(q0) { + case 1: + iq[jz-1] &= 0x7fffff; break; + case 2: + iq[jz-1] &= 0x3fffff; break; + } + } + if(ih==2) { + z = one - z; + if(carry!=0) z -= scalbn(one,q0); + } + } + + /* check if recomputation is needed */ + if(z==zero) { + j = 0; + for (i=jz-1;i>=jk;i--) j |= iq[i]; + if(j==0) { /* need recomputation */ + for(k=1;iq[jk-k]==0;k++); /* k = no. of terms needed */ + + for(i=jz+1;i<=jz+k;i++) { /* add q[jz+1] to q[jz+k] */ + f[jx+i] = (double) ipio2[jv+i]; + for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; + q[i] = fw; + } + jz += k; + goto recompute; + } + } + + /* chop off zero terms */ + if(z==0.0) { + jz -= 1; q0 -= 24; + while(iq[jz]==0) { jz--; q0-=24;} + } else { /* break z into 24-bit if necessary */ + z = scalbn(z,-q0); + if(z>=two24) { + fw = (double)((int32_t)(twon24*z)); + iq[jz] = (int32_t)(z-two24*fw); + jz += 1; q0 += 24; + iq[jz] = (int32_t) fw; + } else iq[jz] = (int32_t) z ; + } + + /* convert integer "bit" chunk to floating-point value */ + fw = scalbn(one,q0); + for(i=jz;i>=0;i--) { + q[i] = fw*(double)iq[i]; fw*=twon24; + } + + /* compute PIo2[0,...,jp]*q[jz,...,0] */ + for(i=jz;i>=0;i--) { + for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k]; + fq[jz-i] = fw; + } + + /* compress fq[] into y[] */ + switch(prec) { + case 0: + fw = 0.0; + for (i=jz;i>=0;i--) fw += fq[i]; + y[0] = (ih==0)? fw: -fw; + break; + case 1: + case 2: + fw = 0.0; + for (i=jz;i>=0;i--) fw += fq[i]; + STRICT_ASSIGN(double,fw,fw); + y[0] = (ih==0)? fw: -fw; + fw = fq[0]-fw; + for (i=1;i<=jz;i++) fw += fq[i]; + y[1] = (ih==0)? fw: -fw; + break; + case 3: /* painful */ + for (i=jz;i>0;i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (i=jz;i>1;i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (fw=0.0,i=jz;i>=2;i--) fw += fq[i]; + if(ih==0) { + y[0] = fq[0]; y[1] = fq[1]; y[2] = fw; + } else { + y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw; + } + } + return n&7; +} diff --git a/libm/upstream-freebsd/lib/msun/src/k_sin.c b/libm/upstream-freebsd/lib/msun/src/k_sin.c new file mode 100644 index 0000000..12ee8c1 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/k_sin.c @@ -0,0 +1,70 @@ + +/* @(#)k_sin.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* __kernel_sin( x, y, iy) + * kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * Input iy indicates whether y is 0. (if iy=0, y assume to be 0). + * + * Algorithm + * 1. Since sin(-x) = -sin(x), we need only to consider positive x. + * 2. Callers must return sin(-0) = -0 without calling here since our + * odd polynomial is not evaluated in a way that preserves -0. + * Callers may do the optimization sin(x) ~ x for tiny x. + * 3. sin(x) is approximated by a polynomial of degree 13 on + * [0,pi/4] + * 3 13 + * sin(x) ~ x + S1*x + ... + S6*x + * where + * + * |sin(x) 2 4 6 8 10 12 | -58 + * |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 + * | x | + * + * 4. sin(x+y) = sin(x) + sin'(x')*y + * ~ sin(x) + (1-x*x/2)*y + * For better accuracy, let + * 3 2 2 2 2 + * r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) + * then 3 2 + * sin(x) = x + (S1*x + (x *(r-y/2)+y)) + */ + +#include "math.h" +#include "math_private.h" + +static const double +half = 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */ +S1 = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */ +S2 = 8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */ +S3 = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */ +S4 = 2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */ +S5 = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */ +S6 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ + +double +__kernel_sin(double x, double y, int iy) +{ + double z,r,v,w; + + z = x*x; + w = z*z; + r = S2+z*(S3+z*S4) + z*w*(S5+z*S6); + v = z*x; + if(iy==0) return x+v*(S1+z*r); + else return x-((z*(half*y-v*r)-y)-v*S1); +} diff --git a/libm/upstream-freebsd/lib/msun/src/k_sinf.c b/libm/upstream-freebsd/lib/msun/src/k_sinf.c new file mode 100644 index 0000000..0841759 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/k_sinf.c @@ -0,0 +1,46 @@ +/* k_sinf.c -- float version of k_sin.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef INLINE_KERNEL_SINDF +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); +#endif + +#include "math.h" +#include "math_private.h" + +/* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ +static const double +S1 = -0x15555554cbac77.0p-55, /* -0.166666666416265235595 */ +S2 = 0x111110896efbb2.0p-59, /* 0.0083333293858894631756 */ +S3 = -0x1a00f9e2cae774.0p-65, /* -0.000198393348360966317347 */ +S4 = 0x16cd878c3b46a7.0p-71; /* 0.0000027183114939898219064 */ + +#ifdef INLINE_KERNEL_SINDF +static __inline +#endif +float +__kernel_sindf(double x) +{ + double r, s, w, z; + + /* Try to optimize for parallel evaluation as in k_tanf.c. */ + z = x*x; + w = z*z; + r = S3+z*S4; + s = z*x; + return (x + s*(S1+z*S2)) + s*w*r; +} diff --git a/libm/upstream-freebsd/lib/msun/src/k_tan.c b/libm/upstream-freebsd/lib/msun/src/k_tan.c new file mode 100644 index 0000000..2e86c3b --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/k_tan.c @@ -0,0 +1,132 @@ +/* @(#)k_tan.c 1.5 04/04/22 SMI */ + +/* + * ==================================================== + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* INDENT OFF */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* __kernel_tan( x, y, k ) + * kernel tan function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * Input k indicates whether tan (if k = 1) or -1/tan (if k = -1) is returned. + * + * Algorithm + * 1. Since tan(-x) = -tan(x), we need only to consider positive x. + * 2. Callers must return tan(-0) = -0 without calling here since our + * odd polynomial is not evaluated in a way that preserves -0. + * Callers may do the optimization tan(x) ~ x for tiny x. + * 3. tan(x) is approximated by a odd polynomial of degree 27 on + * [0,0.67434] + * 3 27 + * tan(x) ~ x + T1*x + ... + T13*x + * where + * + * |tan(x) 2 4 26 | -59.2 + * |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2 + * | x | + * + * Note: tan(x+y) = tan(x) + tan'(x)*y + * ~ tan(x) + (1+x*x)*y + * Therefore, for better accuracy in computing tan(x+y), let + * 3 2 2 2 2 + * r = x *(T2+x *(T3+x *(...+x *(T12+x *T13)))) + * then + * 3 2 + * tan(x+y) = x + (T1*x + (x *(r+y)+y)) + * + * 4. For x in [0.67434,pi/4], let y = pi/4 - x, then + * tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y)) + * = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y))) + */ + +#include "math.h" +#include "math_private.h" +static const double xxx[] = { + 3.33333333333334091986e-01, /* 3FD55555, 55555563 */ + 1.33333333333201242699e-01, /* 3FC11111, 1110FE7A */ + 5.39682539762260521377e-02, /* 3FABA1BA, 1BB341FE */ + 2.18694882948595424599e-02, /* 3F9664F4, 8406D637 */ + 8.86323982359930005737e-03, /* 3F8226E3, E96E8493 */ + 3.59207910759131235356e-03, /* 3F6D6D22, C9560328 */ + 1.45620945432529025516e-03, /* 3F57DBC8, FEE08315 */ + 5.88041240820264096874e-04, /* 3F4344D8, F2F26501 */ + 2.46463134818469906812e-04, /* 3F3026F7, 1A8D1068 */ + 7.81794442939557092300e-05, /* 3F147E88, A03792A6 */ + 7.14072491382608190305e-05, /* 3F12B80F, 32F0A7E9 */ + -1.85586374855275456654e-05, /* BEF375CB, DB605373 */ + 2.59073051863633712884e-05, /* 3EFB2A70, 74BF7AD4 */ +/* one */ 1.00000000000000000000e+00, /* 3FF00000, 00000000 */ +/* pio4 */ 7.85398163397448278999e-01, /* 3FE921FB, 54442D18 */ +/* pio4lo */ 3.06161699786838301793e-17 /* 3C81A626, 33145C07 */ +}; +#define one xxx[13] +#define pio4 xxx[14] +#define pio4lo xxx[15] +#define T xxx +/* INDENT ON */ + +double +__kernel_tan(double x, double y, int iy) { + double z, r, v, w, s; + int32_t ix, hx; + + GET_HIGH_WORD(hx,x); + ix = hx & 0x7fffffff; /* high word of |x| */ + if (ix >= 0x3FE59428) { /* |x| >= 0.6744 */ + if (hx < 0) { + x = -x; + y = -y; + } + z = pio4 - x; + w = pio4lo - y; + x = z + w; + y = 0.0; + } + 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])) + */ + 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]))))); + s = z * x; + r = y + z * (s * (r + v) + y); + r += T[0] * s; + w = x + r; + if (ix >= 0x3FE59428) { + v = (double) iy; + return (double) (1 - ((hx >> 30) & 2)) * + (v - 2.0 * (x - (w * w / (w + v) - r))); + } + if (iy == 1) + return w; + else { + /* + * if allow error up to 2 ulp, simply return + * -1.0 / (x+r) here + */ + /* compute -1.0 / (x+r) accurately */ + double a, t; + z = w; + SET_LOW_WORD(z,0); + v = r - (z - x); /* z+v = r+x */ + t = a = -1.0 / w; /* a = -1.0/w */ + SET_LOW_WORD(t,0); + s = 1.0 + t * z; + return t + a * (s + t * v); + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/k_tanf.c b/libm/upstream-freebsd/lib/msun/src/k_tanf.c new file mode 100644 index 0000000..52f1aaa --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/k_tanf.c @@ -0,0 +1,66 @@ +/* k_tanf.c -- float version of k_tan.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ + +/* + * ==================================================== + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef INLINE_KERNEL_TANDF +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); +#endif + +#include "math.h" +#include "math_private.h" + +/* |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). */ +static const double +T[] = { + 0x15554d3418c99f.0p-54, /* 0.333331395030791399758 */ + 0x1112fd38999f72.0p-55, /* 0.133392002712976742718 */ + 0x1b54c91d865afe.0p-57, /* 0.0533812378445670393523 */ + 0x191df3908c33ce.0p-58, /* 0.0245283181166547278873 */ + 0x185dadfcecf44e.0p-61, /* 0.00297435743359967304927 */ + 0x1362b9bf971bcd.0p-59, /* 0.00946564784943673166728 */ +}; + +#ifdef INLINE_KERNEL_TANDF +static __inline +#endif +float +__kernel_tandf(double x, int iy) +{ + double z,r,w,s,t,u; + + z = x*x; + /* + * Split up the polynomial into small independent terms to give + * opportunities for parallel evaluation. The chosen splitting is + * micro-optimized for Athlons (XP, X64). It costs 2 multiplications + * relative to Horner's method on sequential machines. + * + * We add the small terms from lowest degree up for efficiency on + * non-sequential machines (the lowest degree terms tend to be ready + * earlier). Apart from this, we don't care about order of + * operations, and don't need to to care since we have precision to + * spare. However, the chosen splitting is good for accuracy too, + * and would give results as accurate as Horner's method if the + * small terms were added from highest degree down. + */ + r = T[4]+z*T[5]; + t = T[2]+z*T[3]; + w = z*z; + s = z*x; + u = T[0]+z*T[1]; + r = (x+s*u)+(s*w)*(t+w*r); + if(iy==1) return r; + else return -1.0/r; +} diff --git a/libm/upstream-freebsd/lib/msun/src/math_private.h b/libm/upstream-freebsd/lib/msun/src/math_private.h new file mode 100644 index 0000000..5662df0 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/math_private.h @@ -0,0 +1,472 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * from: @(#)fdlibm.h 5.1 93/09/24 + * $FreeBSD$ + */ + +#ifndef _MATH_PRIVATE_H_ +#define _MATH_PRIVATE_H_ + +#include <sys/types.h> +#include <machine/endian.h> + +/* + * The original fdlibm code used statements like: + * n0 = ((*(int*)&one)>>29)^1; * index of high word * + * ix0 = *(n0+(int*)&x); * high word of x * + * ix1 = *((1-n0)+(int*)&x); * low word of x * + * to dig two 32 bit words out of the 64 bit IEEE floating point + * value. That is non-ANSI, and, moreover, the gcc instruction + * scheduler gets it wrong. We instead use the following macros. + * Unlike the original code, we determine the endianness at compile + * time, not at run time; I don't see much benefit to selecting + * endianness at run time. + */ + +/* + * A union which permits us to convert between a double and two 32 bit + * ints. + */ + +#ifdef __arm__ +#if defined(__VFP_FP__) +#define IEEE_WORD_ORDER BYTE_ORDER +#else +#define IEEE_WORD_ORDER BIG_ENDIAN +#endif +#else /* __arm__ */ +#define IEEE_WORD_ORDER BYTE_ORDER +#endif + +#if IEEE_WORD_ORDER == BIG_ENDIAN + +typedef union +{ + double value; + struct + { + u_int32_t msw; + u_int32_t lsw; + } parts; + struct + { + u_int64_t w; + } xparts; +} ieee_double_shape_type; + +#endif + +#if IEEE_WORD_ORDER == LITTLE_ENDIAN + +typedef union +{ + double value; + struct + { + u_int32_t lsw; + u_int32_t msw; + } parts; + struct + { + u_int64_t w; + } xparts; +} ieee_double_shape_type; + +#endif + +/* Get two 32 bit ints from a double. */ + +#define EXTRACT_WORDS(ix0,ix1,d) \ +do { \ + ieee_double_shape_type ew_u; \ + ew_u.value = (d); \ + (ix0) = ew_u.parts.msw; \ + (ix1) = ew_u.parts.lsw; \ +} while (0) + +/* Get a 64-bit int from a double. */ +#define EXTRACT_WORD64(ix,d) \ +do { \ + ieee_double_shape_type ew_u; \ + ew_u.value = (d); \ + (ix) = ew_u.xparts.w; \ +} while (0) + +/* Get the more significant 32 bit int from a double. */ + +#define GET_HIGH_WORD(i,d) \ +do { \ + ieee_double_shape_type gh_u; \ + gh_u.value = (d); \ + (i) = gh_u.parts.msw; \ +} while (0) + +/* Get the less significant 32 bit int from a double. */ + +#define GET_LOW_WORD(i,d) \ +do { \ + ieee_double_shape_type gl_u; \ + gl_u.value = (d); \ + (i) = gl_u.parts.lsw; \ +} while (0) + +/* Set a double from two 32 bit ints. */ + +#define INSERT_WORDS(d,ix0,ix1) \ +do { \ + ieee_double_shape_type iw_u; \ + iw_u.parts.msw = (ix0); \ + iw_u.parts.lsw = (ix1); \ + (d) = iw_u.value; \ +} while (0) + +/* Set a double from a 64-bit int. */ +#define INSERT_WORD64(d,ix) \ +do { \ + ieee_double_shape_type iw_u; \ + iw_u.xparts.w = (ix); \ + (d) = iw_u.value; \ +} while (0) + +/* Set the more significant 32 bits of a double from an int. */ + +#define SET_HIGH_WORD(d,v) \ +do { \ + ieee_double_shape_type sh_u; \ + sh_u.value = (d); \ + sh_u.parts.msw = (v); \ + (d) = sh_u.value; \ +} while (0) + +/* Set the less significant 32 bits of a double from an int. */ + +#define SET_LOW_WORD(d,v) \ +do { \ + ieee_double_shape_type sl_u; \ + sl_u.value = (d); \ + sl_u.parts.lsw = (v); \ + (d) = sl_u.value; \ +} while (0) + +/* + * A union which permits us to convert between a float and a 32 bit + * int. + */ + +typedef union +{ + float value; + /* FIXME: Assumes 32 bit int. */ + unsigned int word; +} ieee_float_shape_type; + +/* Get a 32 bit int from a float. */ + +#define GET_FLOAT_WORD(i,d) \ +do { \ + ieee_float_shape_type gf_u; \ + gf_u.value = (d); \ + (i) = gf_u.word; \ +} while (0) + +/* Set a float from a 32 bit int. */ + +#define SET_FLOAT_WORD(d,i) \ +do { \ + ieee_float_shape_type sf_u; \ + sf_u.word = (i); \ + (d) = sf_u.value; \ +} while (0) + +/* Get expsign as a 16 bit int from a long double. */ + +#define GET_LDBL_EXPSIGN(i,d) \ +do { \ + union IEEEl2bits ge_u; \ + ge_u.e = (d); \ + (i) = ge_u.xbits.expsign; \ +} while (0) + +/* Set expsign of a long double from a 16 bit int. */ + +#define SET_LDBL_EXPSIGN(d,v) \ +do { \ + union IEEEl2bits se_u; \ + se_u.e = (d); \ + se_u.xbits.expsign = (v); \ + (d) = se_u.e; \ +} while (0) + +#ifdef __i386__ +/* Long double constants are broken on i386. */ +#define LD80C(m, ex, v) { \ + .xbits.man = __CONCAT(m, ULL), \ + .xbits.expsign = (0x3fff + (ex)) | ((v) < 0 ? 0x8000 : 0), \ +} +#else +/* The above works on non-i386 too, but we use this to check v. */ +#define LD80C(m, ex, v) { .e = (v), } +#endif + +#ifdef FLT_EVAL_METHOD +/* + * Attempt to get strict C99 semantics for assignment with non-C99 compilers. + */ +#if FLT_EVAL_METHOD == 0 || __GNUC__ == 0 +#define STRICT_ASSIGN(type, lval, rval) ((lval) = (rval)) +#else +#define STRICT_ASSIGN(type, lval, rval) do { \ + volatile type __lval; \ + \ + if (sizeof(type) >= sizeof(long double)) \ + (lval) = (rval); \ + else { \ + __lval = (rval); \ + (lval) = __lval; \ + } \ +} while (0) +#endif +#endif /* FLT_EVAL_METHOD */ + +/* Support switching the mode to FP_PE if necessary. */ +#if defined(__i386__) && !defined(NO_FPSETPREC) +#define ENTERI() \ + long double __retval; \ + fp_prec_t __oprec; \ + \ + if ((__oprec = fpgetprec()) != FP_PE) \ + fpsetprec(FP_PE) +#define RETURNI(x) do { \ + __retval = (x); \ + if (__oprec != FP_PE) \ + fpsetprec(__oprec); \ + RETURNF(__retval); \ +} while (0) +#else +#define ENTERI(x) +#define RETURNI(x) RETURNF(x) +#endif + +/* Default return statement if hack*_t() is not used. */ +#define RETURNF(v) return (v) + +/* + * Common routine to process the arguments to nan(), nanf(), and nanl(). + */ +void _scan_nan(uint32_t *__words, int __num_words, const char *__s); + +#ifdef _COMPLEX_H + +/* + * C99 specifies that complex numbers have the same representation as + * an array of two elements, where the first element is the real part + * and the second element is the imaginary part. + */ +typedef union { + float complex f; + float a[2]; +} float_complex; +typedef union { + double complex f; + double a[2]; +} double_complex; +typedef union { + long double complex f; + long double a[2]; +} long_double_complex; +#define REALPART(z) ((z).a[0]) +#define IMAGPART(z) ((z).a[1]) + +/* + * Inline functions that can be used to construct complex values. + * + * The C99 standard intends x+I*y to be used for this, but x+I*y is + * currently unusable in general since gcc introduces many overflow, + * underflow, sign and efficiency bugs by rewriting I*y as + * (0.0+I)*(y+0.0*I) and laboriously computing the full complex product. + * In particular, I*Inf is corrupted to NaN+I*Inf, and I*-0 is corrupted + * to -0.0+I*0.0. + */ +static __inline float complex +cpackf(float x, float y) +{ + float_complex z; + + REALPART(z) = x; + IMAGPART(z) = y; + return (z.f); +} + +static __inline double complex +cpack(double x, double y) +{ + double_complex z; + + REALPART(z) = x; + IMAGPART(z) = y; + return (z.f); +} + +static __inline long double complex +cpackl(long double x, long double y) +{ + long_double_complex z; + + REALPART(z) = x; + IMAGPART(z) = y; + return (z.f); +} +#endif /* _COMPLEX_H */ + +#ifdef __GNUCLIKE_ASM + +/* Asm versions of some functions. */ + +#ifdef __amd64__ +static __inline int +irint(double x) +{ + int n; + + asm("cvtsd2si %1,%0" : "=r" (n) : "x" (x)); + return (n); +} +#define HAVE_EFFICIENT_IRINT +#endif + +#ifdef __i386__ +static __inline int +irint(double x) +{ + int n; + + asm("fistl %0" : "=m" (n) : "t" (x)); + return (n); +} +#define HAVE_EFFICIENT_IRINT +#endif + +#if defined(__amd64__) || defined(__i386__) +static __inline int +irintl(long double x) +{ + int n; + + asm("fistl %0" : "=m" (n) : "t" (x)); + return (n); +} +#define HAVE_EFFICIENT_IRINTL +#endif + +#endif /* __GNUCLIKE_ASM */ + +/* + * ieee style elementary functions + * + * We rename functions here to improve other sources' diffability + * against fdlibm. + */ +#define __ieee754_sqrt sqrt +#define __ieee754_acos acos +#define __ieee754_acosh acosh +#define __ieee754_log log +#define __ieee754_log2 log2 +#define __ieee754_atanh atanh +#define __ieee754_asin asin +#define __ieee754_atan2 atan2 +#define __ieee754_exp exp +#define __ieee754_cosh cosh +#define __ieee754_fmod fmod +#define __ieee754_pow pow +#define __ieee754_lgamma lgamma +#define __ieee754_gamma gamma +#define __ieee754_lgamma_r lgamma_r +#define __ieee754_gamma_r gamma_r +#define __ieee754_log10 log10 +#define __ieee754_sinh sinh +#define __ieee754_hypot hypot +#define __ieee754_j0 j0 +#define __ieee754_j1 j1 +#define __ieee754_y0 y0 +#define __ieee754_y1 y1 +#define __ieee754_jn jn +#define __ieee754_yn yn +#define __ieee754_remainder remainder +#define __ieee754_scalb scalb +#define __ieee754_sqrtf sqrtf +#define __ieee754_acosf acosf +#define __ieee754_acoshf acoshf +#define __ieee754_logf logf +#define __ieee754_atanhf atanhf +#define __ieee754_asinf asinf +#define __ieee754_atan2f atan2f +#define __ieee754_expf expf +#define __ieee754_coshf coshf +#define __ieee754_fmodf fmodf +#define __ieee754_powf powf +#define __ieee754_lgammaf lgammaf +#define __ieee754_gammaf gammaf +#define __ieee754_lgammaf_r lgammaf_r +#define __ieee754_gammaf_r gammaf_r +#define __ieee754_log10f log10f +#define __ieee754_log2f log2f +#define __ieee754_sinhf sinhf +#define __ieee754_hypotf hypotf +#define __ieee754_j0f j0f +#define __ieee754_j1f j1f +#define __ieee754_y0f y0f +#define __ieee754_y1f y1f +#define __ieee754_jnf jnf +#define __ieee754_ynf ynf +#define __ieee754_remainderf remainderf +#define __ieee754_scalbf scalbf + +/* fdlibm kernel function */ +int __kernel_rem_pio2(double*,double*,int,int,int); + +/* double precision kernel functions */ +#ifndef INLINE_REM_PIO2 +int __ieee754_rem_pio2(double,double*); +#endif +double __kernel_sin(double,double,int); +double __kernel_cos(double,double); +double __kernel_tan(double,double,int); +double __ldexp_exp(double,int); +#ifdef _COMPLEX_H +double complex __ldexp_cexp(double complex,int); +#endif + +/* float precision kernel functions */ +#ifndef INLINE_REM_PIO2F +int __ieee754_rem_pio2f(float,double*); +#endif +#ifndef INLINE_KERNEL_SINDF +float __kernel_sindf(double); +#endif +#ifndef INLINE_KERNEL_COSDF +float __kernel_cosdf(double); +#endif +#ifndef INLINE_KERNEL_TANDF +float __kernel_tandf(double,int); +#endif +float __ldexp_expf(float,int); +#ifdef _COMPLEX_H +float complex __ldexp_cexpf(float complex,int); +#endif + +/* long double precision kernel functions */ +long double __kernel_sinl(long double, long double, int); +long double __kernel_cosl(long double, long double); +long double __kernel_tanl(long double, long double, int); + +#endif /* !_MATH_PRIVATE_H_ */ diff --git a/libm/upstream-freebsd/lib/msun/src/s_asinh.c b/libm/upstream-freebsd/lib/msun/src/s_asinh.c new file mode 100644 index 0000000..f3fdf74 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_asinh.c @@ -0,0 +1,56 @@ +/* @(#)s_asinh.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* asinh(x) + * Method : + * Based on + * asinh(x) = sign(x) * log [ |x| + sqrt(x*x+1) ] + * we have + * asinh(x) := x if 1+x*x=1, + * := sign(x)*(log(x)+ln2)) for large |x|, else + * := sign(x)*log(2|x|+1/(|x|+sqrt(x*x+1))) if|x|>2, else + * := sign(x)*log1p(|x| + x^2/(1 + sqrt(1+x^2))) + */ + +#include "math.h" +#include "math_private.h" + +static const double +one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */ +ln2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */ +huge= 1.00000000000000000000e+300; + +double +asinh(double x) +{ + double t,w; + int32_t hx,ix; + GET_HIGH_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x7ff00000) return x+x; /* x is inf or NaN */ + if(ix< 0x3e300000) { /* |x|<2**-28 */ + if(huge+x>one) return x; /* return x inexact except 0 */ + } + if(ix>0x41b00000) { /* |x| > 2**28 */ + w = __ieee754_log(fabs(x))+ln2; + } else if (ix>0x40000000) { /* 2**28 > |x| > 2.0 */ + t = fabs(x); + w = __ieee754_log(2.0*t+one/(__ieee754_sqrt(x*x+one)+t)); + } else { /* 2.0 > |x| > 2**-28 */ + t = x*x; + w =log1p(fabs(x)+t/(one+__ieee754_sqrt(one+t))); + } + if(hx>0) return w; else return -w; +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_asinhf.c b/libm/upstream-freebsd/lib/msun/src/s_asinhf.c new file mode 100644 index 0000000..c1620dd --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_asinhf.c @@ -0,0 +1,48 @@ +/* s_asinhf.c -- float version of s_asinh.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +static const float +one = 1.0000000000e+00, /* 0x3F800000 */ +ln2 = 6.9314718246e-01, /* 0x3f317218 */ +huge= 1.0000000000e+30; + +float +asinhf(float x) +{ + float t,w; + int32_t hx,ix; + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x7f800000) return x+x; /* x is inf or NaN */ + if(ix< 0x31800000) { /* |x|<2**-28 */ + if(huge+x>one) return x; /* return x inexact except 0 */ + } + if(ix>0x4d800000) { /* |x| > 2**28 */ + w = __ieee754_logf(fabsf(x))+ln2; + } else if (ix>0x40000000) { /* 2**28 > |x| > 2.0 */ + t = fabsf(x); + w = __ieee754_logf((float)2.0*t+one/(__ieee754_sqrtf(x*x+one)+t)); + } else { /* 2.0 > |x| > 2**-28 */ + t = x*x; + w =log1pf(fabsf(x)+t/(one+__ieee754_sqrtf(one+t))); + } + if(hx>0) return w; else return -w; +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_atan.c b/libm/upstream-freebsd/lib/msun/src/s_atan.c new file mode 100644 index 0000000..566f5dc --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_atan.c @@ -0,0 +1,124 @@ +/* @(#)s_atan.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* atan(x) + * Method + * 1. Reduce x to positive by atan(x) = -atan(-x). + * 2. According to the integer k=4t+0.25 chopped, t=x, the argument + * is further reduced to one of the following intervals and the + * arctangent of t is evaluated by the corresponding formula: + * + * [0,7/16] atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...) + * [7/16,11/16] atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) ) + * [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) ) + * [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) ) + * [39/16,INF] atan(x) = atan(INF) + atan( -1/t ) + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include <float.h> + +#include "math.h" +#include "math_private.h" + +static const double atanhi[] = { + 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */ + 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */ + 9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */ + 1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */ +}; + +static const double atanlo[] = { + 2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */ + 3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */ + 1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */ + 6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */ +}; + +static const double aT[] = { + 3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */ + -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */ + 1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */ + -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */ + 9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */ + -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */ + 6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */ + -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */ + 4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */ + -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */ + 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */ +}; + + static const double +one = 1.0, +huge = 1.0e300; + +double +atan(double x) +{ + double w,s1,s2,z; + int32_t ix,hx,id; + + GET_HIGH_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x44100000) { /* if |x| >= 2^66 */ + u_int32_t low; + GET_LOW_WORD(low,x); + if(ix>0x7ff00000|| + (ix==0x7ff00000&&(low!=0))) + return x+x; /* NaN */ + if(hx>0) return atanhi[3]+*(volatile double *)&atanlo[3]; + else return -atanhi[3]-*(volatile double *)&atanlo[3]; + } if (ix < 0x3fdc0000) { /* |x| < 0.4375 */ + if (ix < 0x3e400000) { /* |x| < 2^-27 */ + if(huge+x>one) return x; /* raise inexact */ + } + id = -1; + } else { + x = fabs(x); + if (ix < 0x3ff30000) { /* |x| < 1.1875 */ + if (ix < 0x3fe60000) { /* 7/16 <=|x|<11/16 */ + id = 0; x = (2.0*x-one)/(2.0+x); + } else { /* 11/16<=|x|< 19/16 */ + id = 1; x = (x-one)/(x+one); + } + } else { + if (ix < 0x40038000) { /* |x| < 2.4375 */ + id = 2; x = (x-1.5)/(one+1.5*x); + } else { /* 2.4375 <= |x| < 2^66 */ + id = 3; x = -1.0/x; + } + }} + /* end of argument reduction */ + z = x*x; + w = z*z; + /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ + s1 = z*(aT[0]+w*(aT[2]+w*(aT[4]+w*(aT[6]+w*(aT[8]+w*aT[10]))))); + s2 = w*(aT[1]+w*(aT[3]+w*(aT[5]+w*(aT[7]+w*aT[9])))); + if (id<0) return x - x*(s1+s2); + else { + z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x); + return (hx<0)? -z:z; + } +} + +#if LDBL_MANT_DIG == 53 +__weak_reference(atan, atanl); +#endif diff --git a/libm/upstream-freebsd/lib/msun/src/s_atanf.c b/libm/upstream-freebsd/lib/msun/src/s_atanf.c new file mode 100644 index 0000000..b3a371f --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_atanf.c @@ -0,0 +1,92 @@ +/* s_atanf.c -- float version of s_atan.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +static const float atanhi[] = { + 4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */ + 7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */ + 9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */ + 1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */ +}; + +static const float atanlo[] = { + 5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */ + 3.7748947079e-08, /* atan(1.0)lo 0x33222168 */ + 3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */ + 7.5497894159e-08, /* atan(inf)lo 0x33a22168 */ +}; + +static const float aT[] = { + 3.3333328366e-01, + -1.9999158382e-01, + 1.4253635705e-01, + -1.0648017377e-01, + 6.1687607318e-02, +}; + +static const float +one = 1.0, +huge = 1.0e30; + +float +atanf(float x) +{ + float w,s1,s2,z; + int32_t ix,hx,id; + + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x4c800000) { /* if |x| >= 2**26 */ + if(ix>0x7f800000) + return x+x; /* NaN */ + if(hx>0) return atanhi[3]+*(volatile float *)&atanlo[3]; + else return -atanhi[3]-*(volatile float *)&atanlo[3]; + } if (ix < 0x3ee00000) { /* |x| < 0.4375 */ + if (ix < 0x39800000) { /* |x| < 2**-12 */ + if(huge+x>one) return x; /* raise inexact */ + } + id = -1; + } else { + x = fabsf(x); + if (ix < 0x3f980000) { /* |x| < 1.1875 */ + if (ix < 0x3f300000) { /* 7/16 <=|x|<11/16 */ + id = 0; x = ((float)2.0*x-one)/((float)2.0+x); + } else { /* 11/16<=|x|< 19/16 */ + id = 1; x = (x-one)/(x+one); + } + } else { + if (ix < 0x401c0000) { /* |x| < 2.4375 */ + id = 2; x = (x-(float)1.5)/(one+(float)1.5*x); + } else { /* 2.4375 <= |x| < 2**26 */ + id = 3; x = -(float)1.0/x; + } + }} + /* end of argument reduction */ + z = x*x; + w = z*z; + /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ + s1 = z*(aT[0]+w*(aT[2]+w*aT[4])); + s2 = w*(aT[1]+w*aT[3]); + if (id<0) return x - x*(s1+s2); + else { + z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x); + return (hx<0)? -z:z; + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_atanl.c b/libm/upstream-freebsd/lib/msun/src/s_atanl.c new file mode 100644 index 0000000..ff29c3c --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_atanl.c @@ -0,0 +1,85 @@ +/* @(#)s_atan.c 5.1 93/09/24 */ +/* FreeBSD: head/lib/msun/src/s_atan.c 176451 2008-02-22 02:30:36Z das */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * See comments in s_atan.c. + * Converted to long double by David Schultz <das@FreeBSD.ORG>. + */ + +#include <float.h> + +#include "invtrig.h" +#include "math.h" +#include "math_private.h" + +static const long double +one = 1.0, +huge = 1.0e300; + +long double +atanl(long double x) +{ + union IEEEl2bits u; + long double w,s1,s2,z; + int id; + int16_t expsign, expt; + int32_t expman; + + u.e = x; + expsign = u.xbits.expsign; + expt = expsign & 0x7fff; + if(expt >= ATAN_CONST) { /* if |x| is large, atan(x)~=pi/2 */ + if(expt == BIAS + LDBL_MAX_EXP && + ((u.bits.manh&~LDBL_NBIT)|u.bits.manl)!=0) + return x+x; /* NaN */ + if(expsign>0) return atanhi[3]+atanlo[3]; + else return -atanhi[3]-atanlo[3]; + } + /* Extract the exponent and the first few bits of the mantissa. */ + /* XXX There should be a more convenient way to do this. */ + expman = (expt << 8) | ((u.bits.manh >> (MANH_SIZE - 9)) & 0xff); + if (expman < ((BIAS - 2) << 8) + 0xc0) { /* |x| < 0.4375 */ + if (expt < ATAN_LINEAR) { /* if |x| is small, atanl(x)~=x */ + if(huge+x>one) return x; /* raise inexact */ + } + id = -1; + } else { + x = fabsl(x); + if (expman < (BIAS << 8) + 0x30) { /* |x| < 1.1875 */ + if (expman < ((BIAS - 1) << 8) + 0x60) { /* 7/16 <=|x|<11/16 */ + id = 0; x = (2.0*x-one)/(2.0+x); + } else { /* 11/16<=|x|< 19/16 */ + id = 1; x = (x-one)/(x+one); + } + } else { + if (expman < ((BIAS + 1) << 8) + 0x38) { /* |x| < 2.4375 */ + id = 2; x = (x-1.5)/(one+1.5*x); + } else { /* 2.4375 <= |x| < 2^ATAN_CONST */ + id = 3; x = -1.0/x; + } + }} + /* end of argument reduction */ + z = x*x; + w = z*z; + /* break sum aT[i]z**(i+1) into odd and even poly */ + s1 = z*T_even(w); + s2 = w*T_odd(w); + if (id<0) return x - x*(s1+s2); + else { + z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x); + return (expsign<0)? -z:z; + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_carg.c b/libm/upstream-freebsd/lib/msun/src/s_carg.c new file mode 100644 index 0000000..ea1a0d7 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_carg.c @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2005 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <complex.h> +#include <math.h> + +double +carg(double complex z) +{ + + return (atan2(cimag(z), creal(z))); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_cargf.c b/libm/upstream-freebsd/lib/msun/src/s_cargf.c new file mode 100644 index 0000000..90232d0 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_cargf.c @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2005 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <complex.h> +#include <math.h> + +float +cargf(float complex z) +{ + + return (atan2f(cimagf(z), crealf(z))); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_cargl.c b/libm/upstream-freebsd/lib/msun/src/s_cargl.c new file mode 100644 index 0000000..0555083 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_cargl.c @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2005-2008 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <complex.h> +#include <math.h> + +long double +cargl(long double complex z) +{ + + return (atan2l(cimagl(z), creall(z))); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_cbrt.c b/libm/upstream-freebsd/lib/msun/src/s_cbrt.c new file mode 100644 index 0000000..910f75b --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_cbrt.c @@ -0,0 +1,117 @@ +/* @(#)s_cbrt.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * Optimized by Bruce D. Evans. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +/* cbrt(x) + * Return cube root of x + */ +static const u_int32_t + B1 = 715094163, /* B1 = (1023-1023/3-0.03306235651)*2**20 */ + B2 = 696219795; /* B2 = (1023-1023/3-54/3-0.03306235651)*2**20 */ + +/* |1/cbrt(x) - p(x)| < 2**-23.5 (~[-7.93e-8, 7.929e-8]). */ +static const double +P0 = 1.87595182427177009643, /* 0x3ffe03e6, 0x0f61e692 */ +P1 = -1.88497979543377169875, /* 0xbffe28e0, 0x92f02420 */ +P2 = 1.621429720105354466140, /* 0x3ff9f160, 0x4a49d6c2 */ +P3 = -0.758397934778766047437, /* 0xbfe844cb, 0xbee751d9 */ +P4 = 0.145996192886612446982; /* 0x3fc2b000, 0xd4e4edd7 */ + +double +cbrt(double x) +{ + int32_t hx; + union { + double value; + uint64_t bits; + } u; + double r,s,t=0.0,w; + u_int32_t sign; + u_int32_t high,low; + + EXTRACT_WORDS(hx,low,x); + sign=hx&0x80000000; /* sign= sign(x) */ + hx ^=sign; + if(hx>=0x7ff00000) return(x+x); /* cbrt(NaN,INF) is itself */ + + /* + * Rough cbrt to 5 bits: + * cbrt(2**e*(1+m) ~= 2**(e/3)*(1+(e%3+m)/3) + * where e is integral and >= 0, m is real and in [0, 1), and "/" and + * "%" are integer division and modulus with rounding towards minus + * infinity. The RHS is always >= the LHS and has a maximum relative + * error of about 1 in 16. Adding a bias of -0.03306235651 to the + * (e%3+m)/3 term reduces the error to about 1 in 32. With the IEEE + * floating point representation, for finite positive normal values, + * ordinary integer divison of the value in bits magically gives + * almost exactly the RHS of the above provided we first subtract the + * exponent bias (1023 for doubles) and later add it back. We do the + * subtraction virtually to keep e >= 0 so that ordinary integer + * division rounds towards minus infinity; this is also efficient. + */ + if(hx<0x00100000) { /* zero or subnormal? */ + if((hx|low)==0) + return(x); /* cbrt(0) is itself */ + SET_HIGH_WORD(t,0x43500000); /* set t= 2**54 */ + t*=x; + GET_HIGH_WORD(high,t); + INSERT_WORDS(t,sign|((high&0x7fffffff)/3+B2),0); + } else + INSERT_WORDS(t,sign|(hx/3+B1),0); + + /* + * New cbrt to 23 bits: + * cbrt(x) = t*cbrt(x/t**3) ~= t*P(t**3/x) + * where P(r) is a polynomial of degree 4 that approximates 1/cbrt(r) + * to within 2**-23.5 when |r - 1| < 1/10. The rough approximation + * has produced t such than |t/cbrt(x) - 1| ~< 1/32, and cubing this + * gives us bounds for r = t**3/x. + * + * Try to optimize for parallel evaluation as in k_tanf.c. + */ + r=(t*t)*(t/x); + t=t*((P0+r*(P1+r*P2))+((r*r)*r)*(P3+r*P4)); + + /* + * Round t away from zero to 23 bits (sloppily except for ensuring that + * the result is larger in magnitude than cbrt(x) but not much more than + * 2 23-bit ulps larger). With rounding towards zero, the error bound + * would be ~5/6 instead of ~4/6. With a maximum error of 2 23-bit ulps + * in the rounded t, the infinite-precision error in the Newton + * approximation barely affects third digit in the final error + * 0.667; the error in the rounded t can be up to about 3 23-bit ulps + * before the final error is larger than 0.667 ulps. + */ + u.value=t; + u.bits=(u.bits+0x80000000)&0xffffffffc0000000ULL; + t=u.value; + + /* one step Newton iteration to 53 bits with error < 0.667 ulps */ + s=t*t; /* t*t is exact */ + r=x/s; /* error <= 0.5 ulps; |r| < |t| */ + w=t+t; /* t+t is exact */ + r=(r-t)/(w+r); /* r-t is exact; w+r ~= 3*t */ + t=t+t*r; /* error <= 0.5 + 0.5/3 + epsilon */ + + return(t); +} + +#if (LDBL_MANT_DIG == 53) +__weak_reference(cbrt, cbrtl); +#endif diff --git a/libm/upstream-freebsd/lib/msun/src/s_cbrtf.c b/libm/upstream-freebsd/lib/msun/src/s_cbrtf.c new file mode 100644 index 0000000..454f974 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_cbrtf.c @@ -0,0 +1,73 @@ +/* s_cbrtf.c -- float version of s_cbrt.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +/* cbrtf(x) + * Return cube root of x + */ +static const unsigned + B1 = 709958130, /* B1 = (127-127.0/3-0.03306235651)*2**23 */ + B2 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */ + +float +cbrtf(float x) +{ + double r,T; + float t; + int32_t hx; + u_int32_t sign; + u_int32_t high; + + GET_FLOAT_WORD(hx,x); + sign=hx&0x80000000; /* sign= sign(x) */ + hx ^=sign; + if(hx>=0x7f800000) return(x+x); /* cbrt(NaN,INF) is itself */ + + /* rough cbrt to 5 bits */ + if(hx<0x00800000) { /* zero or subnormal? */ + if(hx==0) + return(x); /* cbrt(+-0) is itself */ + SET_FLOAT_WORD(t,0x4b800000); /* set t= 2**24 */ + t*=x; + GET_FLOAT_WORD(high,t); + SET_FLOAT_WORD(t,sign|((high&0x7fffffff)/3+B2)); + } else + SET_FLOAT_WORD(t,sign|(hx/3+B1)); + + /* + * First step Newton iteration (solving t*t-x/t == 0) to 16 bits. In + * double precision so that its terms can be arranged for efficiency + * without causing overflow or underflow. + */ + T=t; + r=T*T*T; + T=T*((double)x+x+r)/(x+r+r); + + /* + * Second step Newton iteration to 47 bits. In double precision for + * efficiency and accuracy. + */ + r=T*T*T; + T=T*((double)x+x+r)/(x+r+r); + + /* rounding to 24 bits is perfect in round-to-nearest mode */ + return(T); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_cbrtl.c b/libm/upstream-freebsd/lib/msun/src/s_cbrtl.c new file mode 100644 index 0000000..2236c0f --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_cbrtl.c @@ -0,0 +1,143 @@ +/*- + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2009-2011, Bruce D. Evans, Steven G. Kargl, David Schultz. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * The argument reduction and testing for exceptional cases was + * written by Steven G. Kargl with input from Bruce D. Evans + * and David A. Schultz. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <float.h> +#ifdef __i386__ +#include <ieeefp.h> +#endif + +#include "fpmath.h" +#include "math.h" +#include "math_private.h" + +#define BIAS (LDBL_MAX_EXP - 1) + +static const unsigned + B1 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */ + +long double +cbrtl(long double x) +{ + union IEEEl2bits u, v; + long double r, s, t, w; + double dr, dt, dx; + float ft, fx; + uint32_t hx; + uint16_t expsign; + int k; + + u.e = x; + expsign = u.xbits.expsign; + k = expsign & 0x7fff; + + /* + * If x = +-Inf, then cbrt(x) = +-Inf. + * If x = NaN, then cbrt(x) = NaN. + */ + if (k == BIAS + LDBL_MAX_EXP) + return (x + x); + + ENTERI(); + if (k == 0) { + /* If x = +-0, then cbrt(x) = +-0. */ + if ((u.bits.manh | u.bits.manl) == 0) + RETURNI(x); + /* Adjust subnormal numbers. */ + u.e *= 0x1.0p514; + k = u.bits.exp; + k -= BIAS + 514; + } else + k -= BIAS; + u.xbits.expsign = BIAS; + v.e = 1; + + x = u.e; + switch (k % 3) { + case 1: + case -2: + x = 2*x; + k--; + break; + case 2: + case -1: + x = 4*x; + k -= 2; + break; + } + v.xbits.expsign = (expsign & 0x8000) | (BIAS + k / 3); + + /* + * The following is the guts of s_cbrtf, with the handling of + * special values removed and extra care for accuracy not taken, + * but with most of the extra accuracy not discarded. + */ + + /* ~5-bit estimate: */ + fx = x; + GET_FLOAT_WORD(hx, fx); + SET_FLOAT_WORD(ft, ((hx & 0x7fffffff) / 3 + B1)); + + /* ~16-bit estimate: */ + dx = x; + dt = ft; + dr = dt * dt * dt; + dt = dt * (dx + dx + dr) / (dx + dr + dr); + + /* ~47-bit estimate: */ + dr = dt * dt * dt; + dt = dt * (dx + dx + dr) / (dx + dr + dr); + +#if LDBL_MANT_DIG == 64 + /* + * dt is cbrtl(x) to ~47 bits (after x has been reduced to 1 <= x < 8). + * Round it away from zero to 32 bits (32 so that t*t is exact, and + * away from zero for technical reasons). + */ + volatile double vd2 = 0x1.0p32; + volatile double vd1 = 0x1.0p-31; + #define vd ((long double)vd2 + vd1) + + t = dt + vd - 0x1.0p32; +#elif LDBL_MANT_DIG == 113 + /* + * Round dt away from zero to 47 bits. Since we don't trust the 47, + * add 2 47-bit ulps instead of 1 to round up. Rounding is slow and + * might be avoidable in this case, since on most machines dt will + * have been evaluated in 53-bit precision and the technical reasons + * for rounding up might not apply to either case in cbrtl() since + * dt is much more accurate than needed. + */ + t = dt + 0x2.0p-46 + 0x1.0p60L - 0x1.0p60; +#else +#error "Unsupported long double format" +#endif + + /* + * Final step Newton iteration to 64 or 113 bits with + * error < 0.667 ulps + */ + s=t*t; /* t*t is exact */ + r=x/s; /* error <= 0.5 ulps; |r| < |t| */ + w=t+t; /* t+t is exact */ + r=(r-t)/(w+r); /* r-t is exact; w+r ~= 3*t */ + t=t+t*r; /* error <= 0.5 + 0.5/3 + epsilon */ + + t *= v.e; + RETURNI(t); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_ccosh.c b/libm/upstream-freebsd/lib/msun/src/s_ccosh.c new file mode 100644 index 0000000..9ea962b --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_ccosh.c @@ -0,0 +1,155 @@ +/*- + * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl + * All rights reserved. + * + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/* + * Hyperbolic cosine of a complex argument z = x + i y. + * + * cosh(z) = cosh(x+iy) + * = cosh(x) cos(y) + i sinh(x) sin(y). + * + * Exceptional values are noted in the comments within the source code. + * These values and the return value were taken from n1124.pdf. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <complex.h> +#include <math.h> + +#include "math_private.h" + +static const double huge = 0x1p1023; + +double complex +ccosh(double complex z) +{ + double x, y, h; + int32_t hx, hy, ix, iy, lx, ly; + + x = creal(z); + y = cimag(z); + + EXTRACT_WORDS(hx, lx, x); + EXTRACT_WORDS(hy, ly, y); + + ix = 0x7fffffff & hx; + iy = 0x7fffffff & hy; + + /* Handle the nearly-non-exceptional cases where x and y are finite. */ + if (ix < 0x7ff00000 && iy < 0x7ff00000) { + if ((iy | ly) == 0) + return (cpack(cosh(x), x * y)); + if (ix < 0x40360000) /* small x: normal case */ + return (cpack(cosh(x) * cos(y), sinh(x) * sin(y))); + + /* |x| >= 22, so cosh(x) ~= exp(|x|) */ + if (ix < 0x40862e42) { + /* x < 710: exp(|x|) won't overflow */ + h = exp(fabs(x)) * 0.5; + return (cpack(h * cos(y), copysign(h, x) * sin(y))); + } else if (ix < 0x4096bbaa) { + /* x < 1455: scale to avoid overflow */ + z = __ldexp_cexp(cpack(fabs(x), y), -1); + return (cpack(creal(z), cimag(z) * copysign(1, x))); + } else { + /* x >= 1455: the result always overflows */ + h = huge * x; + return (cpack(h * h * cos(y), h * sin(y))); + } + } + + /* + * cosh(+-0 +- I Inf) = dNaN + I sign(d(+-0, dNaN))0. + * The sign of 0 in the result is unspecified. Choice = normally + * the same as dNaN. Raise the invalid floating-point exception. + * + * cosh(+-0 +- I NaN) = d(NaN) + I sign(d(+-0, NaN))0. + * The sign of 0 in the result is unspecified. Choice = normally + * the same as d(NaN). + */ + if ((ix | lx) == 0 && iy >= 0x7ff00000) + return (cpack(y - y, copysign(0, x * (y - y)))); + + /* + * cosh(+-Inf +- I 0) = +Inf + I (+-)(+-)0. + * + * cosh(NaN +- I 0) = d(NaN) + I sign(d(NaN, +-0))0. + * The sign of 0 in the result is unspecified. + */ + if ((iy | ly) == 0 && ix >= 0x7ff00000) { + if (((hx & 0xfffff) | lx) == 0) + return (cpack(x * x, copysign(0, x) * y)); + return (cpack(x * x, copysign(0, (x + x) * y))); + } + + /* + * cosh(x +- I Inf) = dNaN + I dNaN. + * Raise the invalid floating-point exception for finite nonzero x. + * + * cosh(x + I NaN) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception for finite + * nonzero x. Choice = don't raise (except for signaling NaNs). + */ + if (ix < 0x7ff00000 && iy >= 0x7ff00000) + return (cpack(y - y, x * (y - y))); + + /* + * cosh(+-Inf + I NaN) = +Inf + I d(NaN). + * + * cosh(+-Inf +- I Inf) = +Inf + I dNaN. + * The sign of Inf in the result is unspecified. Choice = always +. + * Raise the invalid floating-point exception. + * + * cosh(+-Inf + I y) = +Inf cos(y) +- I Inf sin(y) + */ + if (ix >= 0x7ff00000 && ((hx & 0xfffff) | lx) == 0) { + if (iy >= 0x7ff00000) + return (cpack(x * x, x * (y - y))); + return (cpack((x * x) * cos(y), x * sin(y))); + } + + /* + * cosh(NaN + I NaN) = d(NaN) + I d(NaN). + * + * cosh(NaN +- I Inf) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception. + * Choice = raise. + * + * cosh(NaN + I y) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception for finite + * nonzero y. Choice = don't raise (except for signaling NaNs). + */ + return (cpack((x * x) * (y - y), (x + x) * (y - y))); +} + +double complex +ccos(double complex z) +{ + + /* ccos(z) = ccosh(I * z) */ + return (ccosh(cpack(-cimag(z), creal(z)))); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_ccoshf.c b/libm/upstream-freebsd/lib/msun/src/s_ccoshf.c new file mode 100644 index 0000000..1de9ad4 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_ccoshf.c @@ -0,0 +1,104 @@ +/*- + * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl + * All rights reserved. + * + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/* + * Hyperbolic cosine of a complex argument. See s_ccosh.c for details. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <complex.h> +#include <math.h> + +#include "math_private.h" + +static const float huge = 0x1p127; + +float complex +ccoshf(float complex z) +{ + float x, y, h; + int32_t hx, hy, ix, iy; + + x = crealf(z); + y = cimagf(z); + + GET_FLOAT_WORD(hx, x); + GET_FLOAT_WORD(hy, y); + + ix = 0x7fffffff & hx; + iy = 0x7fffffff & hy; + + if (ix < 0x7f800000 && iy < 0x7f800000) { + if (iy == 0) + return (cpackf(coshf(x), x * y)); + if (ix < 0x41100000) /* small x: normal case */ + return (cpackf(coshf(x) * cosf(y), sinhf(x) * sinf(y))); + + /* |x| >= 9, so cosh(x) ~= exp(|x|) */ + if (ix < 0x42b17218) { + /* x < 88.7: expf(|x|) won't overflow */ + h = expf(fabsf(x)) * 0.5f; + return (cpackf(h * cosf(y), copysignf(h, x) * sinf(y))); + } else if (ix < 0x4340b1e7) { + /* x < 192.7: scale to avoid overflow */ + z = __ldexp_cexpf(cpackf(fabsf(x), y), -1); + return (cpackf(crealf(z), cimagf(z) * copysignf(1, x))); + } else { + /* x >= 192.7: the result always overflows */ + h = huge * x; + return (cpackf(h * h * cosf(y), h * sinf(y))); + } + } + + if (ix == 0 && iy >= 0x7f800000) + return (cpackf(y - y, copysignf(0, x * (y - y)))); + + if (iy == 0 && ix >= 0x7f800000) { + if ((hx & 0x7fffff) == 0) + return (cpackf(x * x, copysignf(0, x) * y)); + return (cpackf(x * x, copysignf(0, (x + x) * y))); + } + + if (ix < 0x7f800000 && iy >= 0x7f800000) + return (cpackf(y - y, x * (y - y))); + + if (ix >= 0x7f800000 && (hx & 0x7fffff) == 0) { + if (iy >= 0x7f800000) + return (cpackf(x * x, x * (y - y))); + return (cpackf((x * x) * cosf(y), x * sinf(y))); + } + + return (cpackf((x * x) * (y - y), (x + x) * (y - y))); +} + +float complex +ccosf(float complex z) +{ + + return (ccoshf(cpackf(-cimagf(z), crealf(z)))); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_ceil.c b/libm/upstream-freebsd/lib/msun/src/s_ceil.c new file mode 100644 index 0000000..929f813 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_ceil.c @@ -0,0 +1,77 @@ +/* @(#)s_ceil.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * ceil(x) + * Return x rounded toward -inf to integral value + * Method: + * Bit twiddling. + * Exception: + * Inexact flag raised if x not equal to ceil(x). + */ + +#include <float.h> + +#include "math.h" +#include "math_private.h" + +static const double huge = 1.0e300; + +double +ceil(double x) +{ + int32_t i0,i1,j0; + u_int32_t i,j; + EXTRACT_WORDS(i0,i1,x); + j0 = ((i0>>20)&0x7ff)-0x3ff; + if(j0<20) { + if(j0<0) { /* raise inexact if x != 0 */ + if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */ + if(i0<0) {i0=0x80000000;i1=0;} + else if((i0|i1)!=0) { i0=0x3ff00000;i1=0;} + } + } else { + i = (0x000fffff)>>j0; + if(((i0&i)|i1)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + if(i0>0) i0 += (0x00100000)>>j0; + i0 &= (~i); i1=0; + } + } + } else if (j0>51) { + if(j0==0x400) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } else { + i = ((u_int32_t)(0xffffffff))>>(j0-20); + if((i1&i)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + if(i0>0) { + if(j0==20) i0+=1; + else { + j = i1 + (1<<(52-j0)); + if(j<i1) i0+=1; /* got a carry */ + i1 = j; + } + } + i1 &= (~i); + } + } + INSERT_WORDS(x,i0,i1); + return x; +} + +#if LDBL_MANT_DIG == 53 +__weak_reference(ceil, ceill); +#endif diff --git a/libm/upstream-freebsd/lib/msun/src/s_ceilf.c b/libm/upstream-freebsd/lib/msun/src/s_ceilf.c new file mode 100644 index 0000000..23bfe04 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_ceilf.c @@ -0,0 +1,52 @@ +/* s_ceilf.c -- float version of s_ceil.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +static const float huge = 1.0e30; + +float +ceilf(float x) +{ + int32_t i0,j0; + u_int32_t i; + + GET_FLOAT_WORD(i0,x); + j0 = ((i0>>23)&0xff)-0x7f; + if(j0<23) { + if(j0<0) { /* raise inexact if x != 0 */ + if(huge+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */ + if(i0<0) {i0=0x80000000;} + else if(i0!=0) { i0=0x3f800000;} + } + } else { + i = (0x007fffff)>>j0; + if((i0&i)==0) return x; /* x is integral */ + if(huge+x>(float)0.0) { /* raise inexact flag */ + if(i0>0) i0 += (0x00800000)>>j0; + i0 &= (~i); + } + } + } else { + if(j0==0x80) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } + SET_FLOAT_WORD(x,i0); + return x; +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_ceill.c b/libm/upstream-freebsd/lib/msun/src/s_ceill.c new file mode 100644 index 0000000..2d1045f --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_ceill.c @@ -0,0 +1,101 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * From: @(#)s_ceil.c 5.1 93/09/24 + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * ceill(x) + * Return x rounded toward -inf to integral value + * Method: + * Bit twiddling. + * Exception: + * Inexact flag raised if x not equal to ceill(x). + */ + +#include <float.h> +#include <math.h> +#include <stdint.h> + +#include "fpmath.h" + +#ifdef LDBL_IMPLICIT_NBIT +#define MANH_SIZE (LDBL_MANH_SIZE + 1) +#define INC_MANH(u, c) do { \ + uint64_t o = u.bits.manh; \ + u.bits.manh += (c); \ + if (u.bits.manh < o) \ + u.bits.exp++; \ +} while (0) +#else +#define MANH_SIZE LDBL_MANH_SIZE +#define INC_MANH(u, c) do { \ + uint64_t o = u.bits.manh; \ + u.bits.manh += (c); \ + if (u.bits.manh < o) { \ + u.bits.exp++; \ + u.bits.manh |= 1llu << (LDBL_MANH_SIZE - 1); \ + } \ +} while (0) +#endif + +static const long double huge = 1.0e300; + +long double +ceill(long double x) +{ + union IEEEl2bits u = { .e = x }; + int e = u.bits.exp - LDBL_MAX_EXP + 1; + + if (e < MANH_SIZE - 1) { + if (e < 0) { /* raise inexact if x != 0 */ + if (huge + x > 0.0) + if (u.bits.exp > 0 || + (u.bits.manh | u.bits.manl) != 0) + u.e = u.bits.sign ? -0.0 : 1.0; + } else { + uint64_t m = ((1llu << MANH_SIZE) - 1) >> (e + 1); + if (((u.bits.manh & m) | u.bits.manl) == 0) + return (x); /* x is integral */ + if (!u.bits.sign) { +#ifdef LDBL_IMPLICIT_NBIT + if (e == 0) + u.bits.exp++; + else +#endif + INC_MANH(u, 1llu << (MANH_SIZE - e - 1)); + } + if (huge + x > 0.0) { /* raise inexact flag */ + u.bits.manh &= ~m; + u.bits.manl = 0; + } + } + } else if (e < LDBL_MANT_DIG - 1) { + uint64_t m = (uint64_t)-1 >> (64 - LDBL_MANT_DIG + e + 1); + if ((u.bits.manl & m) == 0) + return (x); /* x is integral */ + if (!u.bits.sign) { + if (e == MANH_SIZE - 1) + INC_MANH(u, 1); + else { + uint64_t o = u.bits.manl; + u.bits.manl += 1llu << (LDBL_MANT_DIG - e - 1); + if (u.bits.manl < o) /* got a carry */ + INC_MANH(u, 1); + } + } + if (huge + x > 0.0) /* raise inexact flag */ + u.bits.manl &= ~m; + } + return (u.e); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_cexp.c b/libm/upstream-freebsd/lib/msun/src/s_cexp.c new file mode 100644 index 0000000..abe178f --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_cexp.c @@ -0,0 +1,89 @@ +/*- + * Copyright (c) 2011 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <complex.h> +#include <math.h> + +#include "math_private.h" + +static const uint32_t +exp_ovfl = 0x40862e42, /* high bits of MAX_EXP * ln2 ~= 710 */ +cexp_ovfl = 0x4096b8e4; /* (MAX_EXP - MIN_DENORM_EXP) * ln2 */ + +double complex +cexp(double complex z) +{ + double x, y, exp_x; + uint32_t hx, hy, lx, ly; + + x = creal(z); + y = cimag(z); + + EXTRACT_WORDS(hy, ly, y); + hy &= 0x7fffffff; + + /* cexp(x + I 0) = exp(x) + I 0 */ + if ((hy | ly) == 0) + return (cpack(exp(x), y)); + EXTRACT_WORDS(hx, lx, x); + /* cexp(0 + I y) = cos(y) + I sin(y) */ + if (((hx & 0x7fffffff) | lx) == 0) + return (cpack(cos(y), sin(y))); + + if (hy >= 0x7ff00000) { + if (lx != 0 || (hx & 0x7fffffff) != 0x7ff00000) { + /* cexp(finite|NaN +- I Inf|NaN) = NaN + I NaN */ + return (cpack(y - y, y - y)); + } else if (hx & 0x80000000) { + /* cexp(-Inf +- I Inf|NaN) = 0 + I 0 */ + return (cpack(0.0, 0.0)); + } else { + /* cexp(+Inf +- I Inf|NaN) = Inf + I NaN */ + return (cpack(x, y - y)); + } + } + + if (hx >= exp_ovfl && hx <= cexp_ovfl) { + /* + * x is between 709.7 and 1454.3, so we must scale to avoid + * overflow in exp(x). + */ + return (__ldexp_cexp(z, 0)); + } else { + /* + * Cases covered here: + * - x < exp_ovfl and exp(x) won't overflow (common case) + * - x > cexp_ovfl, so exp(x) * s overflows for all s > 0 + * - x = +-Inf (generated by exp()) + * - x = NaN (spurious inexact exception from y) + */ + exp_x = exp(x); + return (cpack(exp_x * cos(y), exp_x * sin(y))); + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_cexpf.c b/libm/upstream-freebsd/lib/msun/src/s_cexpf.c new file mode 100644 index 0000000..0e30d08 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_cexpf.c @@ -0,0 +1,89 @@ +/*- + * Copyright (c) 2011 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <complex.h> +#include <math.h> + +#include "math_private.h" + +static const uint32_t +exp_ovfl = 0x42b17218, /* MAX_EXP * ln2 ~= 88.722839355 */ +cexp_ovfl = 0x43400074; /* (MAX_EXP - MIN_DENORM_EXP) * ln2 */ + +float complex +cexpf(float complex z) +{ + float x, y, exp_x; + uint32_t hx, hy; + + x = crealf(z); + y = cimagf(z); + + GET_FLOAT_WORD(hy, y); + hy &= 0x7fffffff; + + /* cexp(x + I 0) = exp(x) + I 0 */ + if (hy == 0) + return (cpackf(expf(x), y)); + GET_FLOAT_WORD(hx, x); + /* cexp(0 + I y) = cos(y) + I sin(y) */ + if ((hx & 0x7fffffff) == 0) + return (cpackf(cosf(y), sinf(y))); + + if (hy >= 0x7f800000) { + if ((hx & 0x7fffffff) != 0x7f800000) { + /* cexp(finite|NaN +- I Inf|NaN) = NaN + I NaN */ + return (cpackf(y - y, y - y)); + } else if (hx & 0x80000000) { + /* cexp(-Inf +- I Inf|NaN) = 0 + I 0 */ + return (cpackf(0.0, 0.0)); + } else { + /* cexp(+Inf +- I Inf|NaN) = Inf + I NaN */ + return (cpackf(x, y - y)); + } + } + + if (hx >= exp_ovfl && hx <= cexp_ovfl) { + /* + * x is between 88.7 and 192, so we must scale to avoid + * overflow in expf(x). + */ + return (__ldexp_cexpf(z, 0)); + } else { + /* + * Cases covered here: + * - x < exp_ovfl and exp(x) won't overflow (common case) + * - x > cexp_ovfl, so exp(x) * s overflows for all s > 0 + * - x = +-Inf (generated by exp()) + * - x = NaN (spurious inexact exception from y) + */ + exp_x = expf(x); + return (cpackf(exp_x * cosf(y), exp_x * sinf(y))); + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_cimag.c b/libm/upstream-freebsd/lib/msun/src/s_cimag.c new file mode 100644 index 0000000..cbf6720 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_cimag.c @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2004 Stefan Farfeleder + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <complex.h> +#include "math_private.h" + +double +cimag(double complex z) +{ + const double_complex z1 = { .f = z }; + + return (IMAGPART(z1)); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_cimagf.c b/libm/upstream-freebsd/lib/msun/src/s_cimagf.c new file mode 100644 index 0000000..4e483a2 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_cimagf.c @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2004 Stefan Farfeleder + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <complex.h> +#include "math_private.h" + +float +cimagf(float complex z) +{ + const float_complex z1 = { .f = z }; + + return (IMAGPART(z1)); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_cimagl.c b/libm/upstream-freebsd/lib/msun/src/s_cimagl.c new file mode 100644 index 0000000..c50e967 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_cimagl.c @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2004 Stefan Farfeleder + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <complex.h> +#include "math_private.h" + +long double +cimagl(long double complex z) +{ + const long_double_complex z1 = { .f = z }; + + return (IMAGPART(z1)); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_conj.c b/libm/upstream-freebsd/lib/msun/src/s_conj.c new file mode 100644 index 0000000..5770c29 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_conj.c @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2004 Stefan Farfeleder + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <complex.h> + +#include "math_private.h" + +double complex +conj(double complex z) +{ + + return (cpack(creal(z), -cimag(z))); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_conjf.c b/libm/upstream-freebsd/lib/msun/src/s_conjf.c new file mode 100644 index 0000000..b090760 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_conjf.c @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2004 Stefan Farfeleder + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <complex.h> + +#include "math_private.h" + +float complex +conjf(float complex z) +{ + + return (cpackf(crealf(z), -cimagf(z))); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_conjl.c b/libm/upstream-freebsd/lib/msun/src/s_conjl.c new file mode 100644 index 0000000..0e431ef --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_conjl.c @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2004 Stefan Farfeleder + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <complex.h> + +#include "math_private.h" + +long double complex +conjl(long double complex z) +{ + + return (cpackl(creall(z), -cimagl(z))); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_copysign.c b/libm/upstream-freebsd/lib/msun/src/s_copysign.c new file mode 100644 index 0000000..a5f3870 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_copysign.c @@ -0,0 +1,33 @@ +/* @(#)s_copysign.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * copysign(double x, double y) + * copysign(x,y) returns a value with the magnitude of x and + * with the sign bit of y. + */ + +#include "math.h" +#include "math_private.h" + +double +copysign(double x, double y) +{ + u_int32_t hx,hy; + GET_HIGH_WORD(hx,x); + GET_HIGH_WORD(hy,y); + SET_HIGH_WORD(x,(hx&0x7fffffff)|(hy&0x80000000)); + return x; +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_copysignf.c b/libm/upstream-freebsd/lib/msun/src/s_copysignf.c new file mode 100644 index 0000000..05ca1e3 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_copysignf.c @@ -0,0 +1,36 @@ +/* s_copysignf.c -- float version of s_copysign.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * copysignf(float x, float y) + * copysignf(x,y) returns a value with the magnitude of x and + * with the sign bit of y. + */ + +#include "math.h" +#include "math_private.h" + +float +copysignf(float x, float y) +{ + u_int32_t ix,iy; + GET_FLOAT_WORD(ix,x); + GET_FLOAT_WORD(iy,y); + SET_FLOAT_WORD(x,(ix&0x7fffffff)|(iy&0x80000000)); + return x; +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_copysignl.c b/libm/upstream-freebsd/lib/msun/src/s_copysignl.c new file mode 100644 index 0000000..8d39f84 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_copysignl.c @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2004 Stefan Farfeleder + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <math.h> + +#include "fpmath.h" + +long double +copysignl(long double x, long double y) +{ + union IEEEl2bits ux, uy; + + ux.e = x; + uy.e = y; + ux.bits.sign = uy.bits.sign; + return (ux.e); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_cos.c b/libm/upstream-freebsd/lib/msun/src/s_cos.c new file mode 100644 index 0000000..29804f4 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_cos.c @@ -0,0 +1,89 @@ +/* @(#)s_cos.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* cos(x) + * Return cosine function of x. + * + * kernel function: + * __kernel_sin ... sine function on [-pi/4,pi/4] + * __kernel_cos ... cosine function on [-pi/4,pi/4] + * __ieee754_rem_pio2 ... argument reduction routine + * + * Method. + * Let S,C and T denote the sin, cos and tan respectively on + * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + * in [-pi/4 , +pi/4], and let n = k mod 4. + * We have + * + * n sin(x) cos(x) tan(x) + * ---------------------------------------------------------- + * 0 S C T + * 1 C -S -1/T + * 2 -S -C T + * 3 -C S -1/T + * ---------------------------------------------------------- + * + * Special cases: + * Let trig be any of sin, cos, or tan. + * trig(+-INF) is NaN, with signals; + * trig(NaN) is that NaN; + * + * Accuracy: + * TRIG(x) returns trig(x) nearly rounded + */ + +#include <float.h> + +#include "math.h" +#define INLINE_REM_PIO2 +#include "math_private.h" +#include "e_rem_pio2.c" + +double +cos(double x) +{ + double y[2],z=0.0; + int32_t n, ix; + + /* High word of x. */ + GET_HIGH_WORD(ix,x); + + /* |x| ~< pi/4 */ + ix &= 0x7fffffff; + if(ix <= 0x3fe921fb) { + if(ix<0x3e46a09e) /* if x < 2**-27 * sqrt(2) */ + if(((int)x)==0) return 1.0; /* generate inexact */ + return __kernel_cos(x,z); + } + + /* cos(Inf or NaN) is NaN */ + else if (ix>=0x7ff00000) return x-x; + + /* argument reduction needed */ + else { + n = __ieee754_rem_pio2(x,y); + switch(n&3) { + case 0: return __kernel_cos(y[0],y[1]); + case 1: return -__kernel_sin(y[0],y[1],1); + case 2: return -__kernel_cos(y[0],y[1]); + default: + return __kernel_sin(y[0],y[1],1); + } + } +} + +#if (LDBL_MANT_DIG == 53) +__weak_reference(cos, cosl); +#endif diff --git a/libm/upstream-freebsd/lib/msun/src/s_cosf.c b/libm/upstream-freebsd/lib/msun/src/s_cosf.c new file mode 100644 index 0000000..b701fd2 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_cosf.c @@ -0,0 +1,87 @@ +/* s_cosf.c -- float version of s_cos.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <float.h> + +#include "math.h" +#define INLINE_KERNEL_COSDF +#define INLINE_KERNEL_SINDF +#define INLINE_REM_PIO2F +#include "math_private.h" +#include "e_rem_pio2f.c" +#include "k_cosf.c" +#include "k_sinf.c" + +/* Small multiples of pi/2 rounded to double precision. */ +static const double +c1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ +c2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ +c3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ +c4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + +float +cosf(float x) +{ + double y; + int32_t n, hx, ix; + + GET_FLOAT_WORD(hx,x); + ix = hx & 0x7fffffff; + + if(ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if(ix<0x39800000) /* |x| < 2**-12 */ + if(((int)x)==0) return 1.0; /* 1 with inexact if x != 0 */ + return __kernel_cosdf(x); + } + if(ix<=0x407b53d1) { /* |x| ~<= 5*pi/4 */ + if(ix>0x4016cbe3) /* |x| ~> 3*pi/4 */ + return -__kernel_cosdf(x + (hx > 0 ? -c2pio2 : c2pio2)); + else { + if(hx>0) + return __kernel_sindf(c1pio2 - x); + else + return __kernel_sindf(x + c1pio2); + } + } + if(ix<=0x40e231d5) { /* |x| ~<= 9*pi/4 */ + if(ix>0x40afeddf) /* |x| ~> 7*pi/4 */ + return __kernel_cosdf(x + (hx > 0 ? -c4pio2 : c4pio2)); + else { + if(hx>0) + return __kernel_sindf(x - c3pio2); + else + return __kernel_sindf(-c3pio2 - x); + } + } + + /* cos(Inf or NaN) is NaN */ + else if (ix>=0x7f800000) return x-x; + + /* general argument reduction needed */ + else { + n = __ieee754_rem_pio2f(x,&y); + switch(n&3) { + case 0: return __kernel_cosdf(y); + case 1: return __kernel_sindf(-y); + case 2: return -__kernel_cosdf(y); + default: + return __kernel_sindf(y); + } + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_cosl.c b/libm/upstream-freebsd/lib/msun/src/s_cosl.c new file mode 100644 index 0000000..22e74cf --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_cosl.c @@ -0,0 +1,95 @@ +/*- + * Copyright (c) 2007 Steven G. Kargl + * All rights reserved. + * + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +/* + * Limited testing on pseudorandom numbers drawn within [-2e8:4e8] shows + * an accuracy of <= 0.7412 ULP. + */ + +#include <float.h> +#ifdef __i386__ +#include <ieeefp.h> +#endif + +#include "math.h" +#include "math_private.h" +#if LDBL_MANT_DIG == 64 +#include "../ld80/e_rem_pio2l.h" +#elif LDBL_MANT_DIG == 113 +#include "../ld128/e_rem_pio2l.h" +#else +#error "Unsupported long double format" +#endif + +long double +cosl(long double x) +{ + union IEEEl2bits z; + int e0; + long double y[2]; + long double hi, lo; + + z.e = x; + z.bits.sign = 0; + + /* If x = +-0 or x is a subnormal number, then cos(x) = 1 */ + if (z.bits.exp == 0) + return (1.0); + + /* If x = NaN or Inf, then cos(x) = NaN. */ + if (z.bits.exp == 32767) + return ((x - x) / (x - x)); + + ENTERI(); + + /* Optimize the case where x is already within range. */ + if (z.e < M_PI_4) + RETURNI(__kernel_cosl(z.e, 0)); + + e0 = __ieee754_rem_pio2l(x, y); + hi = y[0]; + lo = y[1]; + + switch (e0 & 3) { + case 0: + hi = __kernel_cosl(hi, lo); + break; + case 1: + hi = - __kernel_sinl(hi, lo, 1); + break; + case 2: + hi = - __kernel_cosl(hi, lo); + break; + case 3: + hi = __kernel_sinl(hi, lo, 1); + break; + } + + RETURNI(hi); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_cproj.c b/libm/upstream-freebsd/lib/msun/src/s_cproj.c new file mode 100644 index 0000000..8e9404c --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_cproj.c @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2008 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <complex.h> +#include <math.h> + +#include "math_private.h" + +double complex +cproj(double complex z) +{ + + if (!isinf(creal(z)) && !isinf(cimag(z))) + return (z); + else + return (cpack(INFINITY, copysign(0.0, cimag(z)))); +} + +#if LDBL_MANT_DIG == 53 +__weak_reference(cproj, cprojl); +#endif diff --git a/libm/upstream-freebsd/lib/msun/src/s_cprojf.c b/libm/upstream-freebsd/lib/msun/src/s_cprojf.c new file mode 100644 index 0000000..68ea77b --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_cprojf.c @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2008 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <complex.h> +#include <math.h> + +#include "math_private.h" + +float complex +cprojf(float complex z) +{ + + if (!isinf(crealf(z)) && !isinf(cimagf(z))) + return (z); + else + return (cpackf(INFINITY, copysignf(0.0, cimagf(z)))); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_cprojl.c b/libm/upstream-freebsd/lib/msun/src/s_cprojl.c new file mode 100644 index 0000000..07385bc --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_cprojl.c @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2008 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <complex.h> +#include <math.h> + +#include "math_private.h" + +long double complex +cprojl(long double complex z) +{ + + if (!isinf(creall(z)) && !isinf(cimagl(z))) + return (z); + else + return (cpackl(INFINITY, copysignl(0.0, cimagl(z)))); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_creal.c b/libm/upstream-freebsd/lib/msun/src/s_creal.c new file mode 100644 index 0000000..3295ff2 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_creal.c @@ -0,0 +1,35 @@ +/*- + * Copyright (c) 2004 Stefan Farfeleder + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <complex.h> + +double +creal(double complex z) +{ + return z; +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_crealf.c b/libm/upstream-freebsd/lib/msun/src/s_crealf.c new file mode 100644 index 0000000..5819b86 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_crealf.c @@ -0,0 +1,35 @@ +/*- + * Copyright (c) 2004 Stefan Farfeleder + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <complex.h> + +float +crealf(float complex z) +{ + return z; +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_creall.c b/libm/upstream-freebsd/lib/msun/src/s_creall.c new file mode 100644 index 0000000..e4946f9 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_creall.c @@ -0,0 +1,35 @@ +/*- + * Copyright (c) 2004 Stefan Farfeleder + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <complex.h> + +long double +creall(long double complex z) +{ + return z; +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_csinh.c b/libm/upstream-freebsd/lib/msun/src/s_csinh.c new file mode 100644 index 0000000..c192f30 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_csinh.c @@ -0,0 +1,157 @@ +/*- + * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl + * All rights reserved. + * + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/* + * Hyperbolic sine of a complex argument z = x + i y. + * + * sinh(z) = sinh(x+iy) + * = sinh(x) cos(y) + i cosh(x) sin(y). + * + * Exceptional values are noted in the comments within the source code. + * These values and the return value were taken from n1124.pdf. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <complex.h> +#include <math.h> + +#include "math_private.h" + +static const double huge = 0x1p1023; + +double complex +csinh(double complex z) +{ + double x, y, h; + int32_t hx, hy, ix, iy, lx, ly; + + x = creal(z); + y = cimag(z); + + EXTRACT_WORDS(hx, lx, x); + EXTRACT_WORDS(hy, ly, y); + + ix = 0x7fffffff & hx; + iy = 0x7fffffff & hy; + + /* Handle the nearly-non-exceptional cases where x and y are finite. */ + if (ix < 0x7ff00000 && iy < 0x7ff00000) { + if ((iy | ly) == 0) + return (cpack(sinh(x), y)); + if (ix < 0x40360000) /* small x: normal case */ + return (cpack(sinh(x) * cos(y), cosh(x) * sin(y))); + + /* |x| >= 22, so cosh(x) ~= exp(|x|) */ + if (ix < 0x40862e42) { + /* x < 710: exp(|x|) won't overflow */ + h = exp(fabs(x)) * 0.5; + return (cpack(copysign(h, x) * cos(y), h * sin(y))); + } else if (ix < 0x4096bbaa) { + /* x < 1455: scale to avoid overflow */ + z = __ldexp_cexp(cpack(fabs(x), y), -1); + return (cpack(creal(z) * copysign(1, x), cimag(z))); + } else { + /* x >= 1455: the result always overflows */ + h = huge * x; + return (cpack(h * cos(y), h * h * sin(y))); + } + } + + /* + * sinh(+-0 +- I Inf) = sign(d(+-0, dNaN))0 + I dNaN. + * The sign of 0 in the result is unspecified. Choice = normally + * the same as dNaN. Raise the invalid floating-point exception. + * + * sinh(+-0 +- I NaN) = sign(d(+-0, NaN))0 + I d(NaN). + * The sign of 0 in the result is unspecified. Choice = normally + * the same as d(NaN). + */ + if ((ix | lx) == 0 && iy >= 0x7ff00000) + return (cpack(copysign(0, x * (y - y)), y - y)); + + /* + * sinh(+-Inf +- I 0) = +-Inf + I +-0. + * + * sinh(NaN +- I 0) = d(NaN) + I +-0. + */ + if ((iy | ly) == 0 && ix >= 0x7ff00000) { + if (((hx & 0xfffff) | lx) == 0) + return (cpack(x, y)); + return (cpack(x, copysign(0, y))); + } + + /* + * sinh(x +- I Inf) = dNaN + I dNaN. + * Raise the invalid floating-point exception for finite nonzero x. + * + * sinh(x + I NaN) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception for finite + * nonzero x. Choice = don't raise (except for signaling NaNs). + */ + if (ix < 0x7ff00000 && iy >= 0x7ff00000) + return (cpack(y - y, x * (y - y))); + + /* + * sinh(+-Inf + I NaN) = +-Inf + I d(NaN). + * The sign of Inf in the result is unspecified. Choice = normally + * the same as d(NaN). + * + * sinh(+-Inf +- I Inf) = +Inf + I dNaN. + * The sign of Inf in the result is unspecified. Choice = always +. + * Raise the invalid floating-point exception. + * + * sinh(+-Inf + I y) = +-Inf cos(y) + I Inf sin(y) + */ + if (ix >= 0x7ff00000 && ((hx & 0xfffff) | lx) == 0) { + if (iy >= 0x7ff00000) + return (cpack(x * x, x * (y - y))); + return (cpack(x * cos(y), INFINITY * sin(y))); + } + + /* + * sinh(NaN + I NaN) = d(NaN) + I d(NaN). + * + * sinh(NaN +- I Inf) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception. + * Choice = raise. + * + * sinh(NaN + I y) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception for finite + * nonzero y. Choice = don't raise (except for signaling NaNs). + */ + return (cpack((x * x) * (y - y), (x + x) * (y - y))); +} + +double complex +csin(double complex z) +{ + + /* csin(z) = -I * csinh(I * z) */ + z = csinh(cpack(-cimag(z), creal(z))); + return (cpack(cimag(z), -creal(z))); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_csinhf.c b/libm/upstream-freebsd/lib/msun/src/s_csinhf.c new file mode 100644 index 0000000..c523125 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_csinhf.c @@ -0,0 +1,105 @@ +/*- + * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl + * All rights reserved. + * + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/* + * Hyperbolic sine of a complex argument z. See s_csinh.c for details. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <complex.h> +#include <math.h> + +#include "math_private.h" + +static const float huge = 0x1p127; + +float complex +csinhf(float complex z) +{ + float x, y, h; + int32_t hx, hy, ix, iy; + + x = crealf(z); + y = cimagf(z); + + GET_FLOAT_WORD(hx, x); + GET_FLOAT_WORD(hy, y); + + ix = 0x7fffffff & hx; + iy = 0x7fffffff & hy; + + if (ix < 0x7f800000 && iy < 0x7f800000) { + if (iy == 0) + return (cpackf(sinhf(x), y)); + if (ix < 0x41100000) /* small x: normal case */ + return (cpackf(sinhf(x) * cosf(y), coshf(x) * sinf(y))); + + /* |x| >= 9, so cosh(x) ~= exp(|x|) */ + if (ix < 0x42b17218) { + /* x < 88.7: expf(|x|) won't overflow */ + h = expf(fabsf(x)) * 0.5f; + return (cpackf(copysignf(h, x) * cosf(y), h * sinf(y))); + } else if (ix < 0x4340b1e7) { + /* x < 192.7: scale to avoid overflow */ + z = __ldexp_cexpf(cpackf(fabsf(x), y), -1); + return (cpackf(crealf(z) * copysignf(1, x), cimagf(z))); + } else { + /* x >= 192.7: the result always overflows */ + h = huge * x; + return (cpackf(h * cosf(y), h * h * sinf(y))); + } + } + + if (ix == 0 && iy >= 0x7f800000) + return (cpackf(copysignf(0, x * (y - y)), y - y)); + + if (iy == 0 && ix >= 0x7f800000) { + if ((hx & 0x7fffff) == 0) + return (cpackf(x, y)); + return (cpackf(x, copysignf(0, y))); + } + + if (ix < 0x7f800000 && iy >= 0x7f800000) + return (cpackf(y - y, x * (y - y))); + + if (ix >= 0x7f800000 && (hx & 0x7fffff) == 0) { + if (iy >= 0x7f800000) + return (cpackf(x * x, x * (y - y))); + return (cpackf(x * cosf(y), INFINITY * sinf(y))); + } + + return (cpackf((x * x) * (y - y), (x + x) * (y - y))); +} + +float complex +csinf(float complex z) +{ + + z = csinhf(cpackf(-cimagf(z), crealf(z))); + return (cpackf(cimagf(z), -crealf(z))); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_csqrt.c b/libm/upstream-freebsd/lib/msun/src/s_csqrt.c new file mode 100644 index 0000000..18a7ae3 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_csqrt.c @@ -0,0 +1,112 @@ +/*- + * Copyright (c) 2007 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <complex.h> +#include <float.h> +#include <math.h> + +#include "math_private.h" + +/* + * gcc doesn't implement complex multiplication or division correctly, + * so we need to handle infinities specially. We turn on this pragma to + * notify conforming c99 compilers that the fast-but-incorrect code that + * gcc generates is acceptable, since the special cases have already been + * handled. + */ +#pragma STDC CX_LIMITED_RANGE ON + +/* We risk spurious overflow for components >= DBL_MAX / (1 + sqrt(2)). */ +#define THRESH 0x1.a827999fcef32p+1022 + +double complex +csqrt(double complex z) +{ + double complex result; + double a, b; + double t; + int scale; + + a = creal(z); + b = cimag(z); + + /* Handle special cases. */ + if (z == 0) + return (cpack(0, b)); + if (isinf(b)) + return (cpack(INFINITY, b)); + if (isnan(a)) { + t = (b - b) / (b - b); /* raise invalid if b is not a NaN */ + return (cpack(a, t)); /* return NaN + NaN i */ + } + if (isinf(a)) { + /* + * csqrt(inf + NaN i) = inf + NaN i + * csqrt(inf + y i) = inf + 0 i + * csqrt(-inf + NaN i) = NaN +- inf i + * csqrt(-inf + y i) = 0 + inf i + */ + if (signbit(a)) + return (cpack(fabs(b - b), copysign(a, b))); + else + return (cpack(a, copysign(b - b, b))); + } + /* + * The remaining special case (b is NaN) is handled just fine by + * the normal code path below. + */ + + /* Scale to avoid overflow. */ + if (fabs(a) >= THRESH || fabs(b) >= THRESH) { + a *= 0.25; + b *= 0.25; + scale = 1; + } else { + scale = 0; + } + + /* Algorithm 312, CACM vol 10, Oct 1967. */ + if (a >= 0) { + t = sqrt((a + hypot(a, b)) * 0.5); + result = cpack(t, b / (2 * t)); + } else { + t = sqrt((-a + hypot(a, b)) * 0.5); + result = cpack(fabs(b) / (2 * t), copysign(t, b)); + } + + /* Rescale. */ + if (scale) + return (result * 2); + else + return (result); +} + +#if LDBL_MANT_DIG == 53 +__weak_reference(csqrt, csqrtl); +#endif diff --git a/libm/upstream-freebsd/lib/msun/src/s_csqrtf.c b/libm/upstream-freebsd/lib/msun/src/s_csqrtf.c new file mode 100644 index 0000000..da7fe18 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_csqrtf.c @@ -0,0 +1,88 @@ +/*- + * Copyright (c) 2007 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <complex.h> +#include <math.h> + +#include "math_private.h" + +/* + * gcc doesn't implement complex multiplication or division correctly, + * so we need to handle infinities specially. We turn on this pragma to + * notify conforming c99 compilers that the fast-but-incorrect code that + * gcc generates is acceptable, since the special cases have already been + * handled. + */ +#pragma STDC CX_LIMITED_RANGE ON + +float complex +csqrtf(float complex z) +{ + float a = crealf(z), b = cimagf(z); + double t; + + /* Handle special cases. */ + if (z == 0) + return (cpackf(0, b)); + if (isinf(b)) + return (cpackf(INFINITY, b)); + if (isnan(a)) { + t = (b - b) / (b - b); /* raise invalid if b is not a NaN */ + return (cpackf(a, t)); /* return NaN + NaN i */ + } + if (isinf(a)) { + /* + * csqrtf(inf + NaN i) = inf + NaN i + * csqrtf(inf + y i) = inf + 0 i + * csqrtf(-inf + NaN i) = NaN +- inf i + * csqrtf(-inf + y i) = 0 + inf i + */ + if (signbit(a)) + return (cpackf(fabsf(b - b), copysignf(a, b))); + else + return (cpackf(a, copysignf(b - b, b))); + } + /* + * The remaining special case (b is NaN) is handled just fine by + * the normal code path below. + */ + + /* + * We compute t in double precision to avoid overflow and to + * provide correct rounding in nearly all cases. + * This is Algorithm 312, CACM vol 10, Oct 1967. + */ + if (a >= 0) { + t = sqrt((a + hypot(a, b)) * 0.5); + return (cpackf(t, b / (2.0 * t))); + } else { + t = sqrt((-a + hypot(a, b)) * 0.5); + return (cpackf(fabsf(b) / (2.0 * t), copysignf(t, b))); + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_csqrtl.c b/libm/upstream-freebsd/lib/msun/src/s_csqrtl.c new file mode 100644 index 0000000..dd18e1e --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_csqrtl.c @@ -0,0 +1,108 @@ +/*- + * Copyright (c) 2007-2008 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <complex.h> +#include <float.h> +#include <math.h> + +#include "math_private.h" + +/* + * gcc doesn't implement complex multiplication or division correctly, + * so we need to handle infinities specially. We turn on this pragma to + * notify conforming c99 compilers that the fast-but-incorrect code that + * gcc generates is acceptable, since the special cases have already been + * handled. + */ +#pragma STDC CX_LIMITED_RANGE ON + +/* We risk spurious overflow for components >= LDBL_MAX / (1 + sqrt(2)). */ +#define THRESH (LDBL_MAX / 2.414213562373095048801688724209698L) + +long double complex +csqrtl(long double complex z) +{ + long double complex result; + long double a, b; + long double t; + int scale; + + a = creall(z); + b = cimagl(z); + + /* Handle special cases. */ + if (z == 0) + return (cpackl(0, b)); + if (isinf(b)) + return (cpackl(INFINITY, b)); + if (isnan(a)) { + t = (b - b) / (b - b); /* raise invalid if b is not a NaN */ + return (cpackl(a, t)); /* return NaN + NaN i */ + } + if (isinf(a)) { + /* + * csqrt(inf + NaN i) = inf + NaN i + * csqrt(inf + y i) = inf + 0 i + * csqrt(-inf + NaN i) = NaN +- inf i + * csqrt(-inf + y i) = 0 + inf i + */ + if (signbit(a)) + return (cpackl(fabsl(b - b), copysignl(a, b))); + else + return (cpackl(a, copysignl(b - b, b))); + } + /* + * The remaining special case (b is NaN) is handled just fine by + * the normal code path below. + */ + + /* Scale to avoid overflow. */ + if (fabsl(a) >= THRESH || fabsl(b) >= THRESH) { + a *= 0.25; + b *= 0.25; + scale = 1; + } else { + scale = 0; + } + + /* Algorithm 312, CACM vol 10, Oct 1967. */ + if (a >= 0) { + t = sqrtl((a + hypotl(a, b)) * 0.5); + result = cpackl(t, b / (2 * t)); + } else { + t = sqrtl((-a + hypotl(a, b)) * 0.5); + result = cpackl(fabsl(b) / (2 * t), copysignl(t, b)); + } + + /* Rescale. */ + if (scale) + return (result * 2); + else + return (result); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_ctanh.c b/libm/upstream-freebsd/lib/msun/src/s_ctanh.c new file mode 100644 index 0000000..d427e28 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_ctanh.c @@ -0,0 +1,144 @@ +/*- + * Copyright (c) 2011 David Schultz + * All rights reserved. + * + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/* + * Hyperbolic tangent of a complex argument z = x + i y. + * + * The algorithm is from: + * + * W. Kahan. Branch Cuts for Complex Elementary Functions or Much + * Ado About Nothing's Sign Bit. In The State of the Art in + * Numerical Analysis, pp. 165 ff. Iserles and Powell, eds., 1987. + * + * Method: + * + * Let t = tan(x) + * beta = 1/cos^2(y) + * s = sinh(x) + * rho = cosh(x) + * + * We have: + * + * tanh(z) = sinh(z) / cosh(z) + * + * sinh(x) cos(y) + i cosh(x) sin(y) + * = --------------------------------- + * cosh(x) cos(y) + i sinh(x) sin(y) + * + * cosh(x) sinh(x) / cos^2(y) + i tan(y) + * = ------------------------------------- + * 1 + sinh^2(x) / cos^2(y) + * + * beta rho s + i t + * = ---------------- + * 1 + beta s^2 + * + * Modifications: + * + * I omitted the original algorithm's handling of overflow in tan(x) after + * verifying with nearpi.c that this can't happen in IEEE single or double + * precision. I also handle large x differently. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <complex.h> +#include <math.h> + +#include "math_private.h" + +double complex +ctanh(double complex z) +{ + double x, y; + double t, beta, s, rho, denom; + uint32_t hx, ix, lx; + + x = creal(z); + y = cimag(z); + + EXTRACT_WORDS(hx, lx, x); + ix = hx & 0x7fffffff; + + /* + * ctanh(NaN + i 0) = NaN + i 0 + * + * ctanh(NaN + i y) = NaN + i NaN for y != 0 + * + * The imaginary part has the sign of x*sin(2*y), but there's no + * special effort to get this right. + * + * ctanh(+-Inf +- i Inf) = +-1 +- 0 + * + * ctanh(+-Inf + i y) = +-1 + 0 sin(2y) for y finite + * + * The imaginary part of the sign is unspecified. This special + * case is only needed to avoid a spurious invalid exception when + * y is infinite. + */ + if (ix >= 0x7ff00000) { + if ((ix & 0xfffff) | lx) /* x is NaN */ + return (cpack(x, (y == 0 ? y : x * y))); + SET_HIGH_WORD(x, hx - 0x40000000); /* x = copysign(1, x) */ + return (cpack(x, copysign(0, isinf(y) ? y : sin(y) * cos(y)))); + } + + /* + * ctanh(x + i NAN) = NaN + i NaN + * ctanh(x +- i Inf) = NaN + i NaN + */ + if (!isfinite(y)) + return (cpack(y - y, y - y)); + + /* + * ctanh(+-huge + i +-y) ~= +-1 +- i 2sin(2y)/exp(2x), using the + * approximation sinh^2(huge) ~= exp(2*huge) / 4. + * We use a modified formula to avoid spurious overflow. + */ + if (ix >= 0x40360000) { /* x >= 22 */ + double exp_mx = exp(-fabs(x)); + return (cpack(copysign(1, x), + 4 * sin(y) * cos(y) * exp_mx * exp_mx)); + } + + /* Kahan's algorithm */ + t = tan(y); + beta = 1.0 + t * t; /* = 1 / cos^2(y) */ + s = sinh(x); + rho = sqrt(1 + s * s); /* = cosh(x) */ + denom = 1 + beta * s * s; + return (cpack((beta * rho * s) / denom, t / denom)); +} + +double complex +ctan(double complex z) +{ + + /* ctan(z) = -I * ctanh(I * z) */ + z = ctanh(cpack(-cimag(z), creal(z))); + return (cpack(cimag(z), -creal(z))); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_ctanhf.c b/libm/upstream-freebsd/lib/msun/src/s_ctanhf.c new file mode 100644 index 0000000..4be28d8 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_ctanhf.c @@ -0,0 +1,84 @@ +/*- + * Copyright (c) 2011 David Schultz + * All rights reserved. + * + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/* + * Hyperbolic tangent of a complex argument z. See s_ctanh.c for details. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <complex.h> +#include <math.h> + +#include "math_private.h" + +float complex +ctanhf(float complex z) +{ + float x, y; + float t, beta, s, rho, denom; + uint32_t hx, ix; + + x = crealf(z); + y = cimagf(z); + + GET_FLOAT_WORD(hx, x); + ix = hx & 0x7fffffff; + + if (ix >= 0x7f800000) { + if (ix & 0x7fffff) + return (cpackf(x, (y == 0 ? y : x * y))); + SET_FLOAT_WORD(x, hx - 0x40000000); + return (cpackf(x, + copysignf(0, isinf(y) ? y : sinf(y) * cosf(y)))); + } + + if (!isfinite(y)) + return (cpackf(y - y, y - y)); + + if (ix >= 0x41300000) { /* x >= 11 */ + float exp_mx = expf(-fabsf(x)); + return (cpackf(copysignf(1, x), + 4 * sinf(y) * cosf(y) * exp_mx * exp_mx)); + } + + t = tanf(y); + beta = 1.0 + t * t; + s = sinhf(x); + rho = sqrtf(1 + s * s); + denom = 1 + beta * s * s; + return (cpackf((beta * rho * s) / denom, t / denom)); +} + +float complex +ctanf(float complex z) +{ + + z = ctanhf(cpackf(-cimagf(z), crealf(z))); + return (cpackf(cimagf(z), -crealf(z))); +} + diff --git a/libm/upstream-freebsd/lib/msun/src/s_erf.c b/libm/upstream-freebsd/lib/msun/src/s_erf.c new file mode 100644 index 0000000..0886e5e --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_erf.c @@ -0,0 +1,301 @@ +/* @(#)s_erf.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* double erf(double x) + * double erfc(double x) + * x + * 2 |\ + * erf(x) = --------- | exp(-t*t)dt + * sqrt(pi) \| + * 0 + * + * erfc(x) = 1-erf(x) + * Note that + * erf(-x) = -erf(x) + * erfc(-x) = 2 - erfc(x) + * + * Method: + * 1. For |x| in [0, 0.84375] + * erf(x) = x + x*R(x^2) + * erfc(x) = 1 - erf(x) if x in [-.84375,0.25] + * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375] + * where R = P/Q where P is an odd poly of degree 8 and + * Q is an odd poly of degree 10. + * -57.90 + * | R - (erf(x)-x)/x | <= 2 + * + * + * Remark. The formula is derived by noting + * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) + * and that + * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 + * is close to one. The interval is chosen because the fix + * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is + * near 0.6174), and by some experiment, 0.84375 is chosen to + * guarantee the error is less than one ulp for erf. + * + * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and + * c = 0.84506291151 rounded to single (24 bits) + * erf(x) = sign(x) * (c + P1(s)/Q1(s)) + * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0 + * 1+(c+P1(s)/Q1(s)) if x < 0 + * |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06 + * Remark: here we use the taylor series expansion at x=1. + * erf(1+s) = erf(1) + s*Poly(s) + * = 0.845.. + P1(s)/Q1(s) + * That is, we use rational approximation to approximate + * erf(1+s) - (c = (single)0.84506291151) + * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] + * where + * P1(s) = degree 6 poly in s + * Q1(s) = degree 6 poly in s + * + * 3. For x in [1.25,1/0.35(~2.857143)], + * erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1) + * erf(x) = 1 - erfc(x) + * where + * R1(z) = degree 7 poly in z, (z=1/x^2) + * S1(z) = degree 8 poly in z + * + * 4. For x in [1/0.35,28] + * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0 + * = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6<x<0 + * = 2.0 - tiny (if x <= -6) + * erf(x) = sign(x)*(1.0 - erfc(x)) if x < 6, else + * erf(x) = sign(x)*(1.0 - tiny) + * where + * R2(z) = degree 6 poly in z, (z=1/x^2) + * S2(z) = degree 7 poly in z + * + * Note1: + * To compute exp(-x*x-0.5625+R/S), let s be a single + * precision number and s := x; then + * -x*x = -s*s + (s-x)*(s+x) + * exp(-x*x-0.5626+R/S) = + * exp(-s*s-0.5625)*exp((s-x)*(s+x)+R/S); + * Note2: + * Here 4 and 5 make use of the asymptotic series + * exp(-x*x) + * erfc(x) ~ ---------- * ( 1 + Poly(1/x^2) ) + * x*sqrt(pi) + * We use rational approximation to approximate + * g(s)=f(1/x^2) = log(erfc(x)*x) - x*x + 0.5625 + * Here is the error bound for R1/S1 and R2/S2 + * |R1/S1 - f(x)| < 2**(-62.57) + * |R2/S2 - f(x)| < 2**(-61.52) + * + * 5. For inf > x >= 28 + * erf(x) = sign(x) *(1 - tiny) (raise inexact) + * erfc(x) = tiny*tiny (raise underflow) if x > 0 + * = 2 - tiny if x<0 + * + * 7. Special case: + * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, + * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, + * erfc/erf(NaN) is NaN + */ + + +#include "math.h" +#include "math_private.h" + +static const double +tiny = 1e-300, +half= 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */ +one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */ +two = 2.00000000000000000000e+00, /* 0x40000000, 0x00000000 */ + /* c = (float)0.84506291151 */ +erx = 8.45062911510467529297e-01, /* 0x3FEB0AC1, 0x60000000 */ +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +efx = 1.28379167095512586316e-01, /* 0x3FC06EBA, 0x8214DB69 */ +efx8= 1.02703333676410069053e+00, /* 0x3FF06EBA, 0x8214DB69 */ +pp0 = 1.28379167095512558561e-01, /* 0x3FC06EBA, 0x8214DB68 */ +pp1 = -3.25042107247001499370e-01, /* 0xBFD4CD7D, 0x691CB913 */ +pp2 = -2.84817495755985104766e-02, /* 0xBF9D2A51, 0xDBD7194F */ +pp3 = -5.77027029648944159157e-03, /* 0xBF77A291, 0x236668E4 */ +pp4 = -2.37630166566501626084e-05, /* 0xBEF8EAD6, 0x120016AC */ +qq1 = 3.97917223959155352819e-01, /* 0x3FD97779, 0xCDDADC09 */ +qq2 = 6.50222499887672944485e-02, /* 0x3FB0A54C, 0x5536CEBA */ +qq3 = 5.08130628187576562776e-03, /* 0x3F74D022, 0xC4D36B0F */ +qq4 = 1.32494738004321644526e-04, /* 0x3F215DC9, 0x221C1A10 */ +qq5 = -3.96022827877536812320e-06, /* 0xBED09C43, 0x42A26120 */ +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +pa0 = -2.36211856075265944077e-03, /* 0xBF6359B8, 0xBEF77538 */ +pa1 = 4.14856118683748331666e-01, /* 0x3FDA8D00, 0xAD92B34D */ +pa2 = -3.72207876035701323847e-01, /* 0xBFD7D240, 0xFBB8C3F1 */ +pa3 = 3.18346619901161753674e-01, /* 0x3FD45FCA, 0x805120E4 */ +pa4 = -1.10894694282396677476e-01, /* 0xBFBC6398, 0x3D3E28EC */ +pa5 = 3.54783043256182359371e-02, /* 0x3FA22A36, 0x599795EB */ +pa6 = -2.16637559486879084300e-03, /* 0xBF61BF38, 0x0A96073F */ +qa1 = 1.06420880400844228286e-01, /* 0x3FBB3E66, 0x18EEE323 */ +qa2 = 5.40397917702171048937e-01, /* 0x3FE14AF0, 0x92EB6F33 */ +qa3 = 7.18286544141962662868e-02, /* 0x3FB2635C, 0xD99FE9A7 */ +qa4 = 1.26171219808761642112e-01, /* 0x3FC02660, 0xE763351F */ +qa5 = 1.36370839120290507362e-02, /* 0x3F8BEDC2, 0x6B51DD1C */ +qa6 = 1.19844998467991074170e-02, /* 0x3F888B54, 0x5735151D */ +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +ra0 = -9.86494403484714822705e-03, /* 0xBF843412, 0x600D6435 */ +ra1 = -6.93858572707181764372e-01, /* 0xBFE63416, 0xE4BA7360 */ +ra2 = -1.05586262253232909814e+01, /* 0xC0251E04, 0x41B0E726 */ +ra3 = -6.23753324503260060396e+01, /* 0xC04F300A, 0xE4CBA38D */ +ra4 = -1.62396669462573470355e+02, /* 0xC0644CB1, 0x84282266 */ +ra5 = -1.84605092906711035994e+02, /* 0xC067135C, 0xEBCCABB2 */ +ra6 = -8.12874355063065934246e+01, /* 0xC0545265, 0x57E4D2F2 */ +ra7 = -9.81432934416914548592e+00, /* 0xC023A0EF, 0xC69AC25C */ +sa1 = 1.96512716674392571292e+01, /* 0x4033A6B9, 0xBD707687 */ +sa2 = 1.37657754143519042600e+02, /* 0x4061350C, 0x526AE721 */ +sa3 = 4.34565877475229228821e+02, /* 0x407B290D, 0xD58A1A71 */ +sa4 = 6.45387271733267880336e+02, /* 0x40842B19, 0x21EC2868 */ +sa5 = 4.29008140027567833386e+02, /* 0x407AD021, 0x57700314 */ +sa6 = 1.08635005541779435134e+02, /* 0x405B28A3, 0xEE48AE2C */ +sa7 = 6.57024977031928170135e+00, /* 0x401A47EF, 0x8E484A93 */ +sa8 = -6.04244152148580987438e-02, /* 0xBFAEEFF2, 0xEE749A62 */ +/* + * Coefficients for approximation to erfc in [1/.35,28] + */ +rb0 = -9.86494292470009928597e-03, /* 0xBF843412, 0x39E86F4A */ +rb1 = -7.99283237680523006574e-01, /* 0xBFE993BA, 0x70C285DE */ +rb2 = -1.77579549177547519889e+01, /* 0xC031C209, 0x555F995A */ +rb3 = -1.60636384855821916062e+02, /* 0xC064145D, 0x43C5ED98 */ +rb4 = -6.37566443368389627722e+02, /* 0xC083EC88, 0x1375F228 */ +rb5 = -1.02509513161107724954e+03, /* 0xC0900461, 0x6A2E5992 */ +rb6 = -4.83519191608651397019e+02, /* 0xC07E384E, 0x9BDC383F */ +sb1 = 3.03380607434824582924e+01, /* 0x403E568B, 0x261D5190 */ +sb2 = 3.25792512996573918826e+02, /* 0x40745CAE, 0x221B9F0A */ +sb3 = 1.53672958608443695994e+03, /* 0x409802EB, 0x189D5118 */ +sb4 = 3.19985821950859553908e+03, /* 0x40A8FFB7, 0x688C246A */ +sb5 = 2.55305040643316442583e+03, /* 0x40A3F219, 0xCEDF3BE6 */ +sb6 = 4.74528541206955367215e+02, /* 0x407DA874, 0xE79FE763 */ +sb7 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */ + +double +erf(double x) +{ + int32_t hx,ix,i; + double R,S,P,Q,s,y,z,r; + GET_HIGH_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x7ff00000) { /* erf(nan)=nan */ + i = ((u_int32_t)hx>>31)<<1; + return (double)(1-i)+one/x; /* erf(+-inf)=+-1 */ + } + + if(ix < 0x3feb0000) { /* |x|<0.84375 */ + if(ix < 0x3e300000) { /* |x|<2**-28 */ + if (ix < 0x00800000) + return 0.125*(8.0*x+efx8*x); /*avoid underflow */ + return x + efx*x; + } + z = x*x; + r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4))); + s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))); + y = r/s; + return x + x*y; + } + if(ix < 0x3ff40000) { /* 0.84375 <= |x| < 1.25 */ + s = fabs(x)-one; + P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6))))); + Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6))))); + if(hx>=0) return erx + P/Q; else return -erx - P/Q; + } + if (ix >= 0x40180000) { /* inf>|x|>=6 */ + if(hx>=0) return one-tiny; else return tiny-one; + } + x = fabs(x); + s = one/(x*x); + if(ix< 0x4006DB6E) { /* |x| < 1/0.35 */ + R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*( + ra5+s*(ra6+s*ra7)))))); + S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*( + sa5+s*(sa6+s*(sa7+s*sa8))))))); + } else { /* |x| >= 1/0.35 */ + R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*( + rb5+s*rb6))))); + S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*( + sb5+s*(sb6+s*sb7)))))); + } + z = x; + SET_LOW_WORD(z,0); + r = __ieee754_exp(-z*z-0.5625)*__ieee754_exp((z-x)*(z+x)+R/S); + if(hx>=0) return one-r/x; else return r/x-one; +} + +double +erfc(double x) +{ + int32_t hx,ix; + double R,S,P,Q,s,y,z,r; + GET_HIGH_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x7ff00000) { /* erfc(nan)=nan */ + /* erfc(+-inf)=0,2 */ + return (double)(((u_int32_t)hx>>31)<<1)+one/x; + } + + if(ix < 0x3feb0000) { /* |x|<0.84375 */ + if(ix < 0x3c700000) /* |x|<2**-56 */ + return one-x; + z = x*x; + r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4))); + s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))); + y = r/s; + if(hx < 0x3fd00000) { /* x<1/4 */ + return one-(x+x*y); + } else { + r = x*y; + r += (x-half); + return half - r ; + } + } + if(ix < 0x3ff40000) { /* 0.84375 <= |x| < 1.25 */ + s = fabs(x)-one; + P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6))))); + Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6))))); + if(hx>=0) { + z = one-erx; return z - P/Q; + } else { + z = erx+P/Q; return one+z; + } + } + if (ix < 0x403c0000) { /* |x|<28 */ + x = fabs(x); + s = one/(x*x); + if(ix< 0x4006DB6D) { /* |x| < 1/.35 ~ 2.857143*/ + R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*( + ra5+s*(ra6+s*ra7)))))); + S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*( + sa5+s*(sa6+s*(sa7+s*sa8))))))); + } else { /* |x| >= 1/.35 ~ 2.857143 */ + if(hx<0&&ix>=0x40180000) return two-tiny;/* x < -6 */ + R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*( + rb5+s*rb6))))); + S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*( + sb5+s*(sb6+s*sb7)))))); + } + z = x; + SET_LOW_WORD(z,0); + r = __ieee754_exp(-z*z-0.5625)* + __ieee754_exp((z-x)*(z+x)+R/S); + if(hx>0) return r/x; else return two-r/x; + } else { + if(hx>0) return tiny*tiny; else return two-tiny; + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_erff.c b/libm/upstream-freebsd/lib/msun/src/s_erff.c new file mode 100644 index 0000000..a44e135 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_erff.c @@ -0,0 +1,210 @@ +/* s_erff.c -- float version of s_erf.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +static const float +tiny = 1e-30, +half= 5.0000000000e-01, /* 0x3F000000 */ +one = 1.0000000000e+00, /* 0x3F800000 */ +two = 2.0000000000e+00, /* 0x40000000 */ + /* c = (subfloat)0.84506291151 */ +erx = 8.4506291151e-01, /* 0x3f58560b */ +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +efx = 1.2837916613e-01, /* 0x3e0375d4 */ +efx8= 1.0270333290e+00, /* 0x3f8375d4 */ +pp0 = 1.2837916613e-01, /* 0x3e0375d4 */ +pp1 = -3.2504209876e-01, /* 0xbea66beb */ +pp2 = -2.8481749818e-02, /* 0xbce9528f */ +pp3 = -5.7702702470e-03, /* 0xbbbd1489 */ +pp4 = -2.3763017452e-05, /* 0xb7c756b1 */ +qq1 = 3.9791721106e-01, /* 0x3ecbbbce */ +qq2 = 6.5022252500e-02, /* 0x3d852a63 */ +qq3 = 5.0813062117e-03, /* 0x3ba68116 */ +qq4 = 1.3249473704e-04, /* 0x390aee49 */ +qq5 = -3.9602282413e-06, /* 0xb684e21a */ +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +pa0 = -2.3621185683e-03, /* 0xbb1acdc6 */ +pa1 = 4.1485610604e-01, /* 0x3ed46805 */ +pa2 = -3.7220788002e-01, /* 0xbebe9208 */ +pa3 = 3.1834661961e-01, /* 0x3ea2fe54 */ +pa4 = -1.1089469492e-01, /* 0xbde31cc2 */ +pa5 = 3.5478305072e-02, /* 0x3d1151b3 */ +pa6 = -2.1663755178e-03, /* 0xbb0df9c0 */ +qa1 = 1.0642088205e-01, /* 0x3dd9f331 */ +qa2 = 5.4039794207e-01, /* 0x3f0a5785 */ +qa3 = 7.1828655899e-02, /* 0x3d931ae7 */ +qa4 = 1.2617121637e-01, /* 0x3e013307 */ +qa5 = 1.3637083583e-02, /* 0x3c5f6e13 */ +qa6 = 1.1984500103e-02, /* 0x3c445aa3 */ +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +ra0 = -9.8649440333e-03, /* 0xbc21a093 */ +ra1 = -6.9385856390e-01, /* 0xbf31a0b7 */ +ra2 = -1.0558626175e+01, /* 0xc128f022 */ +ra3 = -6.2375331879e+01, /* 0xc2798057 */ +ra4 = -1.6239666748e+02, /* 0xc322658c */ +ra5 = -1.8460508728e+02, /* 0xc3389ae7 */ +ra6 = -8.1287437439e+01, /* 0xc2a2932b */ +ra7 = -9.8143291473e+00, /* 0xc11d077e */ +sa1 = 1.9651271820e+01, /* 0x419d35ce */ +sa2 = 1.3765776062e+02, /* 0x4309a863 */ +sa3 = 4.3456588745e+02, /* 0x43d9486f */ +sa4 = 6.4538726807e+02, /* 0x442158c9 */ +sa5 = 4.2900814819e+02, /* 0x43d6810b */ +sa6 = 1.0863500214e+02, /* 0x42d9451f */ +sa7 = 6.5702495575e+00, /* 0x40d23f7c */ +sa8 = -6.0424413532e-02, /* 0xbd777f97 */ +/* + * Coefficients for approximation to erfc in [1/.35,28] + */ +rb0 = -9.8649431020e-03, /* 0xbc21a092 */ +rb1 = -7.9928326607e-01, /* 0xbf4c9dd4 */ +rb2 = -1.7757955551e+01, /* 0xc18e104b */ +rb3 = -1.6063638306e+02, /* 0xc320a2ea */ +rb4 = -6.3756646729e+02, /* 0xc41f6441 */ +rb5 = -1.0250950928e+03, /* 0xc480230b */ +rb6 = -4.8351919556e+02, /* 0xc3f1c275 */ +sb1 = 3.0338060379e+01, /* 0x41f2b459 */ +sb2 = 3.2579251099e+02, /* 0x43a2e571 */ +sb3 = 1.5367296143e+03, /* 0x44c01759 */ +sb4 = 3.1998581543e+03, /* 0x4547fdbb */ +sb5 = 2.5530502930e+03, /* 0x451f90ce */ +sb6 = 4.7452853394e+02, /* 0x43ed43a7 */ +sb7 = -2.2440952301e+01; /* 0xc1b38712 */ + +float +erff(float x) +{ + int32_t hx,ix,i; + float R,S,P,Q,s,y,z,r; + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x7f800000) { /* erf(nan)=nan */ + i = ((u_int32_t)hx>>31)<<1; + return (float)(1-i)+one/x; /* erf(+-inf)=+-1 */ + } + + if(ix < 0x3f580000) { /* |x|<0.84375 */ + if(ix < 0x31800000) { /* |x|<2**-28 */ + if (ix < 0x04000000) + /*avoid underflow */ + return (float)0.125*((float)8.0*x+efx8*x); + return x + efx*x; + } + z = x*x; + r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4))); + s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))); + y = r/s; + return x + x*y; + } + if(ix < 0x3fa00000) { /* 0.84375 <= |x| < 1.25 */ + s = fabsf(x)-one; + P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6))))); + Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6))))); + if(hx>=0) return erx + P/Q; else return -erx - P/Q; + } + if (ix >= 0x40c00000) { /* inf>|x|>=6 */ + if(hx>=0) return one-tiny; else return tiny-one; + } + x = fabsf(x); + s = one/(x*x); + if(ix< 0x4036DB6E) { /* |x| < 1/0.35 */ + R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*( + ra5+s*(ra6+s*ra7)))))); + S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*( + sa5+s*(sa6+s*(sa7+s*sa8))))))); + } else { /* |x| >= 1/0.35 */ + R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*( + rb5+s*rb6))))); + S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*( + sb5+s*(sb6+s*sb7)))))); + } + GET_FLOAT_WORD(ix,x); + SET_FLOAT_WORD(z,ix&0xfffff000); + r = __ieee754_expf(-z*z-(float)0.5625)*__ieee754_expf((z-x)*(z+x)+R/S); + if(hx>=0) return one-r/x; else return r/x-one; +} + +float +erfcf(float x) +{ + int32_t hx,ix; + float R,S,P,Q,s,y,z,r; + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x7f800000) { /* erfc(nan)=nan */ + /* erfc(+-inf)=0,2 */ + return (float)(((u_int32_t)hx>>31)<<1)+one/x; + } + + if(ix < 0x3f580000) { /* |x|<0.84375 */ + if(ix < 0x23800000) /* |x|<2**-56 */ + return one-x; + z = x*x; + r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4))); + s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))); + y = r/s; + if(hx < 0x3e800000) { /* x<1/4 */ + return one-(x+x*y); + } else { + r = x*y; + r += (x-half); + return half - r ; + } + } + if(ix < 0x3fa00000) { /* 0.84375 <= |x| < 1.25 */ + s = fabsf(x)-one; + P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6))))); + Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6))))); + if(hx>=0) { + z = one-erx; return z - P/Q; + } else { + z = erx+P/Q; return one+z; + } + } + if (ix < 0x41e00000) { /* |x|<28 */ + x = fabsf(x); + s = one/(x*x); + if(ix< 0x4036DB6D) { /* |x| < 1/.35 ~ 2.857143*/ + R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*( + ra5+s*(ra6+s*ra7)))))); + S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*( + sa5+s*(sa6+s*(sa7+s*sa8))))))); + } else { /* |x| >= 1/.35 ~ 2.857143 */ + if(hx<0&&ix>=0x40c00000) return two-tiny;/* x < -6 */ + R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*( + rb5+s*rb6))))); + S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*( + sb5+s*(sb6+s*sb7)))))); + } + GET_FLOAT_WORD(ix,x); + SET_FLOAT_WORD(z,ix&0xfffff000); + r = __ieee754_expf(-z*z-(float)0.5625)* + __ieee754_expf((z-x)*(z+x)+R/S); + if(hx>0) return r/x; else return two-r/x; + } else { + if(hx>0) return tiny*tiny; else return two-tiny; + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_exp2.c b/libm/upstream-freebsd/lib/msun/src/s_exp2.c new file mode 100644 index 0000000..485b4e3 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_exp2.c @@ -0,0 +1,396 @@ +/*- + * Copyright (c) 2005 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <float.h> + +#include "math.h" +#include "math_private.h" + +#define TBLBITS 8 +#define TBLSIZE (1 << TBLBITS) + +static const double + huge = 0x1p1000, + redux = 0x1.8p52 / TBLSIZE, + P1 = 0x1.62e42fefa39efp-1, + P2 = 0x1.ebfbdff82c575p-3, + P3 = 0x1.c6b08d704a0a6p-5, + P4 = 0x1.3b2ab88f70400p-7, + P5 = 0x1.5d88003875c74p-10; + +static volatile double twom1000 = 0x1p-1000; + +static const double tbl[TBLSIZE * 2] = { +/* exp2(z + eps) eps */ + 0x1.6a09e667f3d5dp-1, 0x1.9880p-44, + 0x1.6b052fa751744p-1, 0x1.8000p-50, + 0x1.6c012750bd9fep-1, -0x1.8780p-45, + 0x1.6cfdcddd476bfp-1, 0x1.ec00p-46, + 0x1.6dfb23c651a29p-1, -0x1.8000p-50, + 0x1.6ef9298593ae3p-1, -0x1.c000p-52, + 0x1.6ff7df9519386p-1, -0x1.fd80p-45, + 0x1.70f7466f42da3p-1, -0x1.c880p-45, + 0x1.71f75e8ec5fc3p-1, 0x1.3c00p-46, + 0x1.72f8286eacf05p-1, -0x1.8300p-44, + 0x1.73f9a48a58152p-1, -0x1.0c00p-47, + 0x1.74fbd35d7ccfcp-1, 0x1.f880p-45, + 0x1.75feb564267f1p-1, 0x1.3e00p-47, + 0x1.77024b1ab6d48p-1, -0x1.7d00p-45, + 0x1.780694fde5d38p-1, -0x1.d000p-50, + 0x1.790b938ac1d00p-1, 0x1.3000p-49, + 0x1.7a11473eb0178p-1, -0x1.d000p-49, + 0x1.7b17b0976d060p-1, 0x1.0400p-45, + 0x1.7c1ed0130c133p-1, 0x1.0000p-53, + 0x1.7d26a62ff8636p-1, -0x1.6900p-45, + 0x1.7e2f336cf4e3bp-1, -0x1.2e00p-47, + 0x1.7f3878491c3e8p-1, -0x1.4580p-45, + 0x1.80427543e1b4ep-1, 0x1.3000p-44, + 0x1.814d2add1071ap-1, 0x1.f000p-47, + 0x1.82589994ccd7ep-1, -0x1.1c00p-45, + 0x1.8364c1eb942d0p-1, 0x1.9d00p-45, + 0x1.8471a4623cab5p-1, 0x1.7100p-43, + 0x1.857f4179f5bbcp-1, 0x1.2600p-45, + 0x1.868d99b4491afp-1, -0x1.2c40p-44, + 0x1.879cad931a395p-1, -0x1.3000p-45, + 0x1.88ac7d98a65b8p-1, -0x1.a800p-45, + 0x1.89bd0a4785800p-1, -0x1.d000p-49, + 0x1.8ace5422aa223p-1, 0x1.3280p-44, + 0x1.8be05bad619fap-1, 0x1.2b40p-43, + 0x1.8cf3216b54383p-1, -0x1.ed00p-45, + 0x1.8e06a5e08664cp-1, -0x1.0500p-45, + 0x1.8f1ae99157807p-1, 0x1.8280p-45, + 0x1.902fed0282c0ep-1, -0x1.cb00p-46, + 0x1.9145b0b91ff96p-1, -0x1.5e00p-47, + 0x1.925c353aa2ff9p-1, 0x1.5400p-48, + 0x1.93737b0cdc64ap-1, 0x1.7200p-46, + 0x1.948b82b5f98aep-1, -0x1.9000p-47, + 0x1.95a44cbc852cbp-1, 0x1.5680p-45, + 0x1.96bdd9a766f21p-1, -0x1.6d00p-44, + 0x1.97d829fde4e2ap-1, -0x1.1000p-47, + 0x1.98f33e47a23a3p-1, 0x1.d000p-45, + 0x1.9a0f170ca0604p-1, -0x1.8a40p-44, + 0x1.9b2bb4d53ff89p-1, 0x1.55c0p-44, + 0x1.9c49182a3f15bp-1, 0x1.6b80p-45, + 0x1.9d674194bb8c5p-1, -0x1.c000p-49, + 0x1.9e86319e3238ep-1, 0x1.7d00p-46, + 0x1.9fa5e8d07f302p-1, 0x1.6400p-46, + 0x1.a0c667b5de54dp-1, -0x1.5000p-48, + 0x1.a1e7aed8eb8f6p-1, 0x1.9e00p-47, + 0x1.a309bec4a2e27p-1, 0x1.ad80p-45, + 0x1.a42c980460a5dp-1, -0x1.af00p-46, + 0x1.a5503b23e259bp-1, 0x1.b600p-47, + 0x1.a674a8af46213p-1, 0x1.8880p-44, + 0x1.a799e1330b3a7p-1, 0x1.1200p-46, + 0x1.a8bfe53c12e8dp-1, 0x1.6c00p-47, + 0x1.a9e6b5579fcd2p-1, -0x1.9b80p-45, + 0x1.ab0e521356fb8p-1, 0x1.b700p-45, + 0x1.ac36bbfd3f381p-1, 0x1.9000p-50, + 0x1.ad5ff3a3c2780p-1, 0x1.4000p-49, + 0x1.ae89f995ad2a3p-1, -0x1.c900p-45, + 0x1.afb4ce622f367p-1, 0x1.6500p-46, + 0x1.b0e07298db790p-1, 0x1.fd40p-45, + 0x1.b20ce6c9a89a9p-1, 0x1.2700p-46, + 0x1.b33a2b84f1a4bp-1, 0x1.d470p-43, + 0x1.b468415b747e7p-1, -0x1.8380p-44, + 0x1.b59728de5593ap-1, 0x1.8000p-54, + 0x1.b6c6e29f1c56ap-1, 0x1.ad00p-47, + 0x1.b7f76f2fb5e50p-1, 0x1.e800p-50, + 0x1.b928cf22749b2p-1, -0x1.4c00p-47, + 0x1.ba5b030a10603p-1, -0x1.d700p-47, + 0x1.bb8e0b79a6f66p-1, 0x1.d900p-47, + 0x1.bcc1e904bc1ffp-1, 0x1.2a00p-47, + 0x1.bdf69c3f3a16fp-1, -0x1.f780p-46, + 0x1.bf2c25bd71db8p-1, -0x1.0a00p-46, + 0x1.c06286141b2e9p-1, -0x1.1400p-46, + 0x1.c199bdd8552e0p-1, 0x1.be00p-47, + 0x1.c2d1cd9fa64eep-1, -0x1.9400p-47, + 0x1.c40ab5fffd02fp-1, -0x1.ed00p-47, + 0x1.c544778fafd15p-1, 0x1.9660p-44, + 0x1.c67f12e57d0cbp-1, -0x1.a100p-46, + 0x1.c7ba88988c1b6p-1, -0x1.8458p-42, + 0x1.c8f6d9406e733p-1, -0x1.a480p-46, + 0x1.ca3405751c4dfp-1, 0x1.b000p-51, + 0x1.cb720dcef9094p-1, 0x1.1400p-47, + 0x1.ccb0f2e6d1689p-1, 0x1.0200p-48, + 0x1.cdf0b555dc412p-1, 0x1.3600p-48, + 0x1.cf3155b5bab3bp-1, -0x1.6900p-47, + 0x1.d072d4a0789bcp-1, 0x1.9a00p-47, + 0x1.d1b532b08c8fap-1, -0x1.5e00p-46, + 0x1.d2f87080d8a85p-1, 0x1.d280p-46, + 0x1.d43c8eacaa203p-1, 0x1.1a00p-47, + 0x1.d5818dcfba491p-1, 0x1.f000p-50, + 0x1.d6c76e862e6a1p-1, -0x1.3a00p-47, + 0x1.d80e316c9834ep-1, -0x1.cd80p-47, + 0x1.d955d71ff6090p-1, 0x1.4c00p-48, + 0x1.da9e603db32aep-1, 0x1.f900p-48, + 0x1.dbe7cd63a8325p-1, 0x1.9800p-49, + 0x1.dd321f301b445p-1, -0x1.5200p-48, + 0x1.de7d5641c05bfp-1, -0x1.d700p-46, + 0x1.dfc97337b9aecp-1, -0x1.6140p-46, + 0x1.e11676b197d5ep-1, 0x1.b480p-47, + 0x1.e264614f5a3e7p-1, 0x1.0ce0p-43, + 0x1.e3b333b16ee5cp-1, 0x1.c680p-47, + 0x1.e502ee78b3fb4p-1, -0x1.9300p-47, + 0x1.e653924676d68p-1, -0x1.5000p-49, + 0x1.e7a51fbc74c44p-1, -0x1.7f80p-47, + 0x1.e8f7977cdb726p-1, -0x1.3700p-48, + 0x1.ea4afa2a490e8p-1, 0x1.5d00p-49, + 0x1.eb9f4867ccae4p-1, 0x1.61a0p-46, + 0x1.ecf482d8e680dp-1, 0x1.5500p-48, + 0x1.ee4aaa2188514p-1, 0x1.6400p-51, + 0x1.efa1bee615a13p-1, -0x1.e800p-49, + 0x1.f0f9c1cb64106p-1, -0x1.a880p-48, + 0x1.f252b376bb963p-1, -0x1.c900p-45, + 0x1.f3ac948dd7275p-1, 0x1.a000p-53, + 0x1.f50765b6e4524p-1, -0x1.4f00p-48, + 0x1.f6632798844fdp-1, 0x1.a800p-51, + 0x1.f7bfdad9cbe38p-1, 0x1.abc0p-48, + 0x1.f91d802243c82p-1, -0x1.4600p-50, + 0x1.fa7c1819e908ep-1, -0x1.b0c0p-47, + 0x1.fbdba3692d511p-1, -0x1.0e00p-51, + 0x1.fd3c22b8f7194p-1, -0x1.0de8p-46, + 0x1.fe9d96b2a23eep-1, 0x1.e430p-49, + 0x1.0000000000000p+0, 0x0.0000p+0, + 0x1.00b1afa5abcbep+0, -0x1.3400p-52, + 0x1.0163da9fb3303p+0, -0x1.2170p-46, + 0x1.02168143b0282p+0, 0x1.a400p-52, + 0x1.02c9a3e77806cp+0, 0x1.f980p-49, + 0x1.037d42e11bbcap+0, -0x1.7400p-51, + 0x1.04315e86e7f89p+0, 0x1.8300p-50, + 0x1.04e5f72f65467p+0, -0x1.a3f0p-46, + 0x1.059b0d315855ap+0, -0x1.2840p-47, + 0x1.0650a0e3c1f95p+0, 0x1.1600p-48, + 0x1.0706b29ddf71ap+0, 0x1.5240p-46, + 0x1.07bd42b72a82dp+0, -0x1.9a00p-49, + 0x1.0874518759bd0p+0, 0x1.6400p-49, + 0x1.092bdf66607c8p+0, -0x1.0780p-47, + 0x1.09e3ecac6f383p+0, -0x1.8000p-54, + 0x1.0a9c79b1f3930p+0, 0x1.fa00p-48, + 0x1.0b5586cf988fcp+0, -0x1.ac80p-48, + 0x1.0c0f145e46c8ap+0, 0x1.9c00p-50, + 0x1.0cc922b724816p+0, 0x1.5200p-47, + 0x1.0d83b23395dd8p+0, -0x1.ad00p-48, + 0x1.0e3ec32d3d1f3p+0, 0x1.bac0p-46, + 0x1.0efa55fdfa9a6p+0, -0x1.4e80p-47, + 0x1.0fb66affed2f0p+0, -0x1.d300p-47, + 0x1.1073028d7234bp+0, 0x1.1500p-48, + 0x1.11301d0125b5bp+0, 0x1.c000p-49, + 0x1.11edbab5e2af9p+0, 0x1.6bc0p-46, + 0x1.12abdc06c31d5p+0, 0x1.8400p-49, + 0x1.136a814f2047dp+0, -0x1.ed00p-47, + 0x1.1429aaea92de9p+0, 0x1.8e00p-49, + 0x1.14e95934f3138p+0, 0x1.b400p-49, + 0x1.15a98c8a58e71p+0, 0x1.5300p-47, + 0x1.166a45471c3dfp+0, 0x1.3380p-47, + 0x1.172b83c7d5211p+0, 0x1.8d40p-45, + 0x1.17ed48695bb9fp+0, -0x1.5d00p-47, + 0x1.18af9388c8d93p+0, -0x1.c880p-46, + 0x1.1972658375d66p+0, 0x1.1f00p-46, + 0x1.1a35beb6fcba7p+0, 0x1.0480p-46, + 0x1.1af99f81387e3p+0, -0x1.7390p-43, + 0x1.1bbe084045d54p+0, 0x1.4e40p-45, + 0x1.1c82f95281c43p+0, -0x1.a200p-47, + 0x1.1d4873168b9b2p+0, 0x1.3800p-49, + 0x1.1e0e75eb44031p+0, 0x1.ac00p-49, + 0x1.1ed5022fcd938p+0, 0x1.1900p-47, + 0x1.1f9c18438cdf7p+0, -0x1.b780p-46, + 0x1.2063b88628d8fp+0, 0x1.d940p-45, + 0x1.212be3578a81ep+0, 0x1.8000p-50, + 0x1.21f49917ddd41p+0, 0x1.b340p-45, + 0x1.22bdda2791323p+0, 0x1.9f80p-46, + 0x1.2387a6e7561e7p+0, -0x1.9c80p-46, + 0x1.2451ffb821427p+0, 0x1.2300p-47, + 0x1.251ce4fb2a602p+0, -0x1.3480p-46, + 0x1.25e85711eceb0p+0, 0x1.2700p-46, + 0x1.26b4565e27d16p+0, 0x1.1d00p-46, + 0x1.2780e341de00fp+0, 0x1.1ee0p-44, + 0x1.284dfe1f5633ep+0, -0x1.4c00p-46, + 0x1.291ba7591bb30p+0, -0x1.3d80p-46, + 0x1.29e9df51fdf09p+0, 0x1.8b00p-47, + 0x1.2ab8a66d10e9bp+0, -0x1.27c0p-45, + 0x1.2b87fd0dada3ap+0, 0x1.a340p-45, + 0x1.2c57e39771af9p+0, -0x1.0800p-46, + 0x1.2d285a6e402d9p+0, -0x1.ed00p-47, + 0x1.2df961f641579p+0, -0x1.4200p-48, + 0x1.2ecafa93e2ecfp+0, -0x1.4980p-45, + 0x1.2f9d24abd8822p+0, -0x1.6300p-46, + 0x1.306fe0a31b625p+0, -0x1.2360p-44, + 0x1.31432edeea50bp+0, -0x1.0df8p-40, + 0x1.32170fc4cd7b8p+0, -0x1.2480p-45, + 0x1.32eb83ba8e9a2p+0, -0x1.5980p-45, + 0x1.33c08b2641766p+0, 0x1.ed00p-46, + 0x1.3496266e3fa27p+0, -0x1.c000p-50, + 0x1.356c55f929f0fp+0, -0x1.0d80p-44, + 0x1.36431a2de88b9p+0, 0x1.2c80p-45, + 0x1.371a7373aaa39p+0, 0x1.0600p-45, + 0x1.37f26231e74fep+0, -0x1.6600p-46, + 0x1.38cae6d05d838p+0, -0x1.ae00p-47, + 0x1.39a401b713ec3p+0, -0x1.4720p-43, + 0x1.3a7db34e5a020p+0, 0x1.8200p-47, + 0x1.3b57fbfec6e95p+0, 0x1.e800p-44, + 0x1.3c32dc313a8f2p+0, 0x1.f800p-49, + 0x1.3d0e544ede122p+0, -0x1.7a00p-46, + 0x1.3dea64c1234bbp+0, 0x1.6300p-45, + 0x1.3ec70df1c4eccp+0, -0x1.8a60p-43, + 0x1.3fa4504ac7e8cp+0, -0x1.cdc0p-44, + 0x1.40822c367a0bbp+0, 0x1.5b80p-45, + 0x1.4160a21f72e95p+0, 0x1.ec00p-46, + 0x1.423fb27094646p+0, -0x1.3600p-46, + 0x1.431f5d950a920p+0, 0x1.3980p-45, + 0x1.43ffa3f84b9ebp+0, 0x1.a000p-48, + 0x1.44e0860618919p+0, -0x1.6c00p-48, + 0x1.45c2042a7d201p+0, -0x1.bc00p-47, + 0x1.46a41ed1d0016p+0, -0x1.2800p-46, + 0x1.4786d668b3326p+0, 0x1.0e00p-44, + 0x1.486a2b5c13c00p+0, -0x1.d400p-45, + 0x1.494e1e192af04p+0, 0x1.c200p-47, + 0x1.4a32af0d7d372p+0, -0x1.e500p-46, + 0x1.4b17dea6db801p+0, 0x1.7800p-47, + 0x1.4bfdad53629e1p+0, -0x1.3800p-46, + 0x1.4ce41b817c132p+0, 0x1.0800p-47, + 0x1.4dcb299fddddbp+0, 0x1.c700p-45, + 0x1.4eb2d81d8ab96p+0, -0x1.ce00p-46, + 0x1.4f9b2769d2d02p+0, 0x1.9200p-46, + 0x1.508417f4531c1p+0, -0x1.8c00p-47, + 0x1.516daa2cf662ap+0, -0x1.a000p-48, + 0x1.5257de83f51eap+0, 0x1.a080p-43, + 0x1.5342b569d4edap+0, -0x1.6d80p-45, + 0x1.542e2f4f6ac1ap+0, -0x1.2440p-44, + 0x1.551a4ca5d94dbp+0, 0x1.83c0p-43, + 0x1.56070dde9116bp+0, 0x1.4b00p-45, + 0x1.56f4736b529dep+0, 0x1.15a0p-43, + 0x1.57e27dbe2c40ep+0, -0x1.9e00p-45, + 0x1.58d12d497c76fp+0, -0x1.3080p-45, + 0x1.59c0827ff0b4cp+0, 0x1.dec0p-43, + 0x1.5ab07dd485427p+0, -0x1.4000p-51, + 0x1.5ba11fba87af4p+0, 0x1.0080p-44, + 0x1.5c9268a59460bp+0, -0x1.6c80p-45, + 0x1.5d84590998e3fp+0, 0x1.69a0p-43, + 0x1.5e76f15ad20e1p+0, -0x1.b400p-46, + 0x1.5f6a320dcebcap+0, 0x1.7700p-46, + 0x1.605e1b976dcb8p+0, 0x1.6f80p-45, + 0x1.6152ae6cdf715p+0, 0x1.1000p-47, + 0x1.6247eb03a5531p+0, -0x1.5d00p-46, + 0x1.633dd1d1929b5p+0, -0x1.2d00p-46, + 0x1.6434634ccc313p+0, -0x1.a800p-49, + 0x1.652b9febc8efap+0, -0x1.8600p-45, + 0x1.6623882553397p+0, 0x1.1fe0p-40, + 0x1.671c1c708328ep+0, -0x1.7200p-44, + 0x1.68155d44ca97ep+0, 0x1.6800p-49, + 0x1.690f4b19e9471p+0, -0x1.9780p-45, +}; + +/* + * exp2(x): compute the base 2 exponential of x + * + * Accuracy: Peak error < 0.503 ulp for normalized results. + * + * Method: (accurate tables) + * + * Reduce x: + * x = 2**k + y, for integer k and |y| <= 1/2. + * Thus we have exp2(x) = 2**k * exp2(y). + * + * Reduce y: + * y = i/TBLSIZE + z - eps[i] for integer i near y * TBLSIZE. + * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z - eps[i]), + * with |z - eps[i]| <= 2**-9 + 2**-39 for the table used. + * + * We compute exp2(i/TBLSIZE) via table lookup and exp2(z - eps[i]) via + * a degree-5 minimax polynomial with maximum error under 1.3 * 2**-61. + * The values in exp2t[] and eps[] are chosen such that + * exp2t[i] = exp2(i/TBLSIZE + eps[i]), and eps[i] is a small offset such + * that exp2t[i] is accurate to 2**-64. + * + * Note that the range of i is +-TBLSIZE/2, so we actually index the tables + * by i0 = i + TBLSIZE/2. For cache efficiency, exp2t[] and eps[] are + * virtual tables, interleaved in the real table tbl[]. + * + * This method is due to Gal, with many details due to Gal and Bachelis: + * + * Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library + * for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). + */ +double +exp2(double x) +{ + double r, t, twopk, twopkp1000, z; + uint32_t hx, ix, lx, i0; + int k; + + /* Filter out exceptional cases. */ + GET_HIGH_WORD(hx,x); + ix = hx & 0x7fffffff; /* high word of |x| */ + if(ix >= 0x40900000) { /* |x| >= 1024 */ + if(ix >= 0x7ff00000) { + GET_LOW_WORD(lx,x); + if(((ix & 0xfffff) | lx) != 0 || (hx & 0x80000000) == 0) + return (x + x); /* x is NaN or +Inf */ + else + return (0.0); /* x is -Inf */ + } + if(x >= 0x1.0p10) + return (huge * huge); /* overflow */ + if(x <= -0x1.0ccp10) + return (twom1000 * twom1000); /* underflow */ + } else if (ix < 0x3c900000) { /* |x| < 0x1p-54 */ + return (1.0 + x); + } + + /* Reduce x, computing z, i0, and k. */ + STRICT_ASSIGN(double, t, x + redux); + GET_LOW_WORD(i0, t); + i0 += TBLSIZE / 2; + k = (i0 >> TBLBITS) << 20; + i0 = (i0 & (TBLSIZE - 1)) << 1; + t -= redux; + z = x - t; + + /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */ + t = tbl[i0]; /* exp2t[i0] */ + z -= tbl[i0 + 1]; /* eps[i0] */ + if (k >= -1021 << 20) + INSERT_WORDS(twopk, 0x3ff00000 + k, 0); + else + INSERT_WORDS(twopkp1000, 0x3ff00000 + k + (1000 << 20), 0); + r = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5)))); + + /* Scale by 2**(k>>20). */ + if(k >= -1021 << 20) { + if (k == 1024 << 20) + return (r * 2.0 * 0x1p1023); + return (r * twopk); + } else { + return (r * twopkp1000 * twom1000); + } +} + +#if (LDBL_MANT_DIG == 53) +__weak_reference(exp2, exp2l); +#endif diff --git a/libm/upstream-freebsd/lib/msun/src/s_exp2f.c b/libm/upstream-freebsd/lib/msun/src/s_exp2f.c new file mode 100644 index 0000000..0a97bf6 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_exp2f.c @@ -0,0 +1,136 @@ +/*- + * Copyright (c) 2005 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <float.h> + +#include "math.h" +#include "math_private.h" + +#define TBLBITS 4 +#define TBLSIZE (1 << TBLBITS) + +static const float + huge = 0x1p100f, + redux = 0x1.8p23f / TBLSIZE, + P1 = 0x1.62e430p-1f, + P2 = 0x1.ebfbe0p-3f, + P3 = 0x1.c6b348p-5f, + P4 = 0x1.3b2c9cp-7f; + +static volatile float twom100 = 0x1p-100f; + +static const double exp2ft[TBLSIZE] = { + 0x1.6a09e667f3bcdp-1, + 0x1.7a11473eb0187p-1, + 0x1.8ace5422aa0dbp-1, + 0x1.9c49182a3f090p-1, + 0x1.ae89f995ad3adp-1, + 0x1.c199bdd85529cp-1, + 0x1.d5818dcfba487p-1, + 0x1.ea4afa2a490dap-1, + 0x1.0000000000000p+0, + 0x1.0b5586cf9890fp+0, + 0x1.172b83c7d517bp+0, + 0x1.2387a6e756238p+0, + 0x1.306fe0a31b715p+0, + 0x1.3dea64c123422p+0, + 0x1.4bfdad5362a27p+0, + 0x1.5ab07dd485429p+0, +}; + +/* + * exp2f(x): compute the base 2 exponential of x + * + * Accuracy: Peak error < 0.501 ulp; location of peak: -0.030110927. + * + * Method: (equally-spaced tables) + * + * Reduce x: + * x = 2**k + y, for integer k and |y| <= 1/2. + * Thus we have exp2f(x) = 2**k * exp2(y). + * + * Reduce y: + * y = i/TBLSIZE + z for integer i near y * TBLSIZE. + * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z), + * with |z| <= 2**-(TBLSIZE+1). + * + * We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a + * degree-4 minimax polynomial with maximum error under 1.4 * 2**-33. + * Using double precision for everything except the reduction makes + * roundoff error insignificant and simplifies the scaling step. + * + * This method is due to Tang, but I do not use his suggested parameters: + * + * Tang, P. Table-driven Implementation of the Exponential Function + * in IEEE Floating-Point Arithmetic. TOMS 15(2), 144-157 (1989). + */ +float +exp2f(float x) +{ + double tv, twopk, u, z; + float t; + uint32_t hx, ix, i0; + int32_t k; + + /* Filter out exceptional cases. */ + GET_FLOAT_WORD(hx, x); + ix = hx & 0x7fffffff; /* high word of |x| */ + if(ix >= 0x43000000) { /* |x| >= 128 */ + if(ix >= 0x7f800000) { + if ((ix & 0x7fffff) != 0 || (hx & 0x80000000) == 0) + return (x + x); /* x is NaN or +Inf */ + else + return (0.0); /* x is -Inf */ + } + if(x >= 0x1.0p7f) + return (huge * huge); /* overflow */ + if(x <= -0x1.2cp7f) + return (twom100 * twom100); /* underflow */ + } else if (ix <= 0x33000000) { /* |x| <= 0x1p-25 */ + return (1.0f + x); + } + + /* Reduce x, computing z, i0, and k. */ + STRICT_ASSIGN(float, t, x + redux); + GET_FLOAT_WORD(i0, t); + i0 += TBLSIZE / 2; + k = (i0 >> TBLBITS) << 20; + i0 &= TBLSIZE - 1; + t -= redux; + z = x - t; + INSERT_WORDS(twopk, 0x3ff00000 + k, 0); + + /* Compute r = exp2(y) = exp2ft[i0] * p(z). */ + tv = exp2ft[i0]; + u = tv * z; + tv = tv + u * (P1 + z * P2) + u * (z * z) * (P3 + z * P4); + + /* Scale by 2**(k>>20). */ + return (tv * twopk); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_expm1.c b/libm/upstream-freebsd/lib/msun/src/s_expm1.c new file mode 100644 index 0000000..5aa1917 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_expm1.c @@ -0,0 +1,217 @@ +/* @(#)s_expm1.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* expm1(x) + * Returns exp(x)-1, the exponential of x minus 1. + * + * Method + * 1. Argument reduction: + * Given x, find r and integer k such that + * + * x = k*ln2 + r, |r| <= 0.5*ln2 ~ 0.34658 + * + * Here a correction term c will be computed to compensate + * the error in r when rounded to a floating-point number. + * + * 2. Approximating expm1(r) by a special rational function on + * the interval [0,0.34658]: + * Since + * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ... + * we define R1(r*r) by + * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r) + * That is, + * R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r) + * = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r)) + * = 1 - r^2/60 + r^4/2520 - r^6/100800 + ... + * We use a special Reme algorithm on [0,0.347] to generate + * a polynomial of degree 5 in r*r to approximate R1. The + * maximum error of this polynomial approximation is bounded + * by 2**-61. In other words, + * R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5 + * where Q1 = -1.6666666666666567384E-2, + * Q2 = 3.9682539681370365873E-4, + * Q3 = -9.9206344733435987357E-6, + * Q4 = 2.5051361420808517002E-7, + * Q5 = -6.2843505682382617102E-9; + * z = r*r, + * with error bounded by + * | 5 | -61 + * | 1.0+Q1*z+...+Q5*z - R1(z) | <= 2 + * | | + * + * expm1(r) = exp(r)-1 is then computed by the following + * specific way which minimize the accumulation rounding error: + * 2 3 + * r r [ 3 - (R1 + R1*r/2) ] + * expm1(r) = r + --- + --- * [--------------------] + * 2 2 [ 6 - r*(3 - R1*r/2) ] + * + * To compensate the error in the argument reduction, we use + * expm1(r+c) = expm1(r) + c + expm1(r)*c + * ~ expm1(r) + c + r*c + * Thus c+r*c will be added in as the correction terms for + * expm1(r+c). Now rearrange the term to avoid optimization + * screw up: + * ( 2 2 ) + * ({ ( r [ R1 - (3 - R1*r/2) ] ) } r ) + * expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- ) + * ({ ( 2 [ 6 - r*(3 - R1*r/2) ] ) } 2 ) + * ( ) + * + * = r - E + * 3. Scale back to obtain expm1(x): + * From step 1, we have + * expm1(x) = either 2^k*[expm1(r)+1] - 1 + * = or 2^k*[expm1(r) + (1-2^-k)] + * 4. Implementation notes: + * (A). To save one multiplication, we scale the coefficient Qi + * to Qi*2^i, and replace z by (x^2)/2. + * (B). To achieve maximum accuracy, we compute expm1(x) by + * (i) if x < -56*ln2, return -1.0, (raise inexact if x!=inf) + * (ii) if k=0, return r-E + * (iii) if k=-1, return 0.5*(r-E)-0.5 + * (iv) if k=1 if r < -0.25, return 2*((r+0.5)- E) + * else return 1.0+2.0*(r-E); + * (v) if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1) + * (vi) if k <= 20, return 2^k((1-2^-k)-(E-r)), else + * (vii) return 2^k(1-((E+2^-k)-r)) + * + * Special cases: + * expm1(INF) is INF, expm1(NaN) is NaN; + * expm1(-INF) is -1, and + * for finite argument, only expm1(0)=0 is exact. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Misc. info. + * For IEEE double + * if x > 7.09782712893383973096e+02 then expm1(x) overflow + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include <float.h> + +#include "math.h" +#include "math_private.h" + +static const double +one = 1.0, +huge = 1.0e+300, +tiny = 1.0e-300, +o_threshold = 7.09782712893383973096e+02,/* 0x40862E42, 0xFEFA39EF */ +ln2_hi = 6.93147180369123816490e-01,/* 0x3fe62e42, 0xfee00000 */ +ln2_lo = 1.90821492927058770002e-10,/* 0x3dea39ef, 0x35793c76 */ +invln2 = 1.44269504088896338700e+00,/* 0x3ff71547, 0x652b82fe */ +/* Scaled Q's: Qn_here = 2**n * Qn_above, for R(2*z) where z = hxs = x*x/2: */ +Q1 = -3.33333333333331316428e-02, /* BFA11111 111110F4 */ +Q2 = 1.58730158725481460165e-03, /* 3F5A01A0 19FE5585 */ +Q3 = -7.93650757867487942473e-05, /* BF14CE19 9EAADBB7 */ +Q4 = 4.00821782732936239552e-06, /* 3ED0CFCA 86E65239 */ +Q5 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ + +double +expm1(double x) +{ + double y,hi,lo,c,t,e,hxs,hfx,r1,twopk; + int32_t k,xsb; + u_int32_t hx; + + GET_HIGH_WORD(hx,x); + xsb = hx&0x80000000; /* sign bit of x */ + hx &= 0x7fffffff; /* high word of |x| */ + + /* filter out huge and non-finite argument */ + if(hx >= 0x4043687A) { /* if |x|>=56*ln2 */ + if(hx >= 0x40862E42) { /* if |x|>=709.78... */ + if(hx>=0x7ff00000) { + u_int32_t low; + GET_LOW_WORD(low,x); + if(((hx&0xfffff)|low)!=0) + return x+x; /* NaN */ + else return (xsb==0)? x:-1.0;/* exp(+-inf)={inf,-1} */ + } + if(x > o_threshold) return huge*huge; /* overflow */ + } + if(xsb!=0) { /* x < -56*ln2, return -1.0 with inexact */ + if(x+tiny<0.0) /* raise inexact */ + return tiny-one; /* return -1 */ + } + } + + /* argument reduction */ + if(hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */ + if(hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */ + if(xsb==0) + {hi = x - ln2_hi; lo = ln2_lo; k = 1;} + else + {hi = x + ln2_hi; lo = -ln2_lo; k = -1;} + } else { + k = invln2*x+((xsb==0)?0.5:-0.5); + t = k; + hi = x - t*ln2_hi; /* t*ln2_hi is exact here */ + lo = t*ln2_lo; + } + STRICT_ASSIGN(double, x, hi - lo); + c = (hi-x)-lo; + } + else if(hx < 0x3c900000) { /* when |x|<2**-54, return x */ + t = huge+x; /* return x with inexact flags when x!=0 */ + return x - (t-(huge+x)); + } + else k = 0; + + /* x is now in primary range */ + hfx = 0.5*x; + hxs = x*hfx; + r1 = one+hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5)))); + t = 3.0-r1*hfx; + e = hxs*((r1-t)/(6.0 - x*t)); + if(k==0) return x - (x*e-hxs); /* c is 0 */ + else { + INSERT_WORDS(twopk,0x3ff00000+(k<<20),0); /* 2^k */ + e = (x*(e-c)-c); + e -= hxs; + if(k== -1) return 0.5*(x-e)-0.5; + if(k==1) { + if(x < -0.25) return -2.0*(e-(x+0.5)); + else return one+2.0*(x-e); + } + if (k <= -2 || k>56) { /* suffice to return exp(x)-1 */ + y = one-(e-x); + if (k == 1024) y = y*2.0*0x1p1023; + else y = y*twopk; + return y-one; + } + t = one; + if(k<20) { + SET_HIGH_WORD(t,0x3ff00000 - (0x200000>>k)); /* t=1-2^-k */ + y = t-(e-x); + y = y*twopk; + } else { + SET_HIGH_WORD(t,((0x3ff-k)<<20)); /* 2^-k */ + y = x-(e+t); + y += one; + y = y*twopk; + } + } + return y; +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_expm1f.c b/libm/upstream-freebsd/lib/msun/src/s_expm1f.c new file mode 100644 index 0000000..fb37494 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_expm1f.c @@ -0,0 +1,123 @@ +/* s_expm1f.c -- float version of s_expm1.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <float.h> + +#include "math.h" +#include "math_private.h" + +static const float +one = 1.0, +huge = 1.0e+30, +tiny = 1.0e-30, +o_threshold = 8.8721679688e+01,/* 0x42b17180 */ +ln2_hi = 6.9313812256e-01,/* 0x3f317180 */ +ln2_lo = 9.0580006145e-06,/* 0x3717f7d1 */ +invln2 = 1.4426950216e+00,/* 0x3fb8aa3b */ +/* + * Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]: + * |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04 + * Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c): + */ +Q1 = -3.3333212137e-2, /* -0x888868.0p-28 */ +Q2 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ + +float +expm1f(float x) +{ + float y,hi,lo,c,t,e,hxs,hfx,r1,twopk; + int32_t k,xsb; + u_int32_t hx; + + GET_FLOAT_WORD(hx,x); + xsb = hx&0x80000000; /* sign bit of x */ + hx &= 0x7fffffff; /* high word of |x| */ + + /* filter out huge and non-finite argument */ + if(hx >= 0x4195b844) { /* if |x|>=27*ln2 */ + if(hx >= 0x42b17218) { /* if |x|>=88.721... */ + if(hx>0x7f800000) + return x+x; /* NaN */ + if(hx==0x7f800000) + return (xsb==0)? x:-1.0;/* exp(+-inf)={inf,-1} */ + if(x > o_threshold) return huge*huge; /* overflow */ + } + if(xsb!=0) { /* x < -27*ln2, return -1.0 with inexact */ + if(x+tiny<(float)0.0) /* raise inexact */ + return tiny-one; /* return -1 */ + } + } + + /* argument reduction */ + if(hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */ + if(hx < 0x3F851592) { /* and |x| < 1.5 ln2 */ + if(xsb==0) + {hi = x - ln2_hi; lo = ln2_lo; k = 1;} + else + {hi = x + ln2_hi; lo = -ln2_lo; k = -1;} + } else { + k = invln2*x+((xsb==0)?(float)0.5:(float)-0.5); + t = k; + hi = x - t*ln2_hi; /* t*ln2_hi is exact here */ + lo = t*ln2_lo; + } + STRICT_ASSIGN(float, x, hi - lo); + c = (hi-x)-lo; + } + else if(hx < 0x33000000) { /* when |x|<2**-25, return x */ + t = huge+x; /* return x with inexact flags when x!=0 */ + return x - (t-(huge+x)); + } + else k = 0; + + /* x is now in primary range */ + hfx = (float)0.5*x; + hxs = x*hfx; + r1 = one+hxs*(Q1+hxs*Q2); + t = (float)3.0-r1*hfx; + e = hxs*((r1-t)/((float)6.0 - x*t)); + if(k==0) return x - (x*e-hxs); /* c is 0 */ + else { + SET_FLOAT_WORD(twopk,0x3f800000+(k<<23)); /* 2^k */ + e = (x*(e-c)-c); + e -= hxs; + if(k== -1) return (float)0.5*(x-e)-(float)0.5; + if(k==1) { + if(x < (float)-0.25) return -(float)2.0*(e-(x+(float)0.5)); + else return one+(float)2.0*(x-e); + } + if (k <= -2 || k>56) { /* suffice to return exp(x)-1 */ + y = one-(e-x); + if (k == 128) y = y*2.0F*0x1p127F; + else y = y*twopk; + return y-one; + } + t = one; + if(k<23) { + SET_FLOAT_WORD(t,0x3f800000 - (0x1000000>>k)); /* t=1-2^-k */ + y = t-(e-x); + y = y*twopk; + } else { + SET_FLOAT_WORD(t,((0x7f-k)<<23)); /* 2^-k */ + y = x-(e+t); + y += one; + y = y*twopk; + } + } + return y; +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_fabs.c b/libm/upstream-freebsd/lib/msun/src/s_fabs.c new file mode 100644 index 0000000..15529e5 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_fabs.c @@ -0,0 +1,31 @@ +/* @(#)s_fabs.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef lint +static char rcsid[] = "$FreeBSD$"; +#endif + +/* + * fabs(x) returns the absolute value of x. + */ + +#include "math.h" +#include "math_private.h" + +double +fabs(double x) +{ + u_int32_t high; + GET_HIGH_WORD(high,x); + SET_HIGH_WORD(x,high&0x7fffffff); + return x; +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_fabsf.c b/libm/upstream-freebsd/lib/msun/src/s_fabsf.c new file mode 100644 index 0000000..e9383d0 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_fabsf.c @@ -0,0 +1,33 @@ +/* s_fabsf.c -- float version of s_fabs.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * fabsf(x) returns the absolute value of x. + */ + +#include "math.h" +#include "math_private.h" + +float +fabsf(float x) +{ + u_int32_t ix; + GET_FLOAT_WORD(ix,x); + SET_FLOAT_WORD(x,ix&0x7fffffff); + return x; +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_fabsl.c b/libm/upstream-freebsd/lib/msun/src/s_fabsl.c new file mode 100644 index 0000000..29831d2 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_fabsl.c @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2003 Dag-Erling Smørgrav + * All rights reserved. + * + * 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 + * in this position and unchanged. + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <math.h> + +#include "fpmath.h" + +long double +fabsl(long double x) +{ + union IEEEl2bits u; + + u.e = x; + u.bits.sign = 0; + return (u.e); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_fdim.c b/libm/upstream-freebsd/lib/msun/src/s_fdim.c new file mode 100644 index 0000000..2f347fd --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_fdim.c @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <math.h> + +#define DECL(type, fn) \ +type \ +fn(type x, type y) \ +{ \ + \ + if (isnan(x)) \ + return (x); \ + if (isnan(y)) \ + return (y); \ + return (x > y ? x - y : 0.0); \ +} + +DECL(double, fdim) +DECL(float, fdimf) +DECL(long double, fdiml) diff --git a/libm/upstream-freebsd/lib/msun/src/s_finite.c b/libm/upstream-freebsd/lib/msun/src/s_finite.c new file mode 100644 index 0000000..4c51352 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_finite.c @@ -0,0 +1,29 @@ +/* @(#)s_finite.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * finite(x) returns 1 is x is finite, else 0; + * no branching! + */ + +#include "math.h" +#include "math_private.h" + + int finite(double x) +{ + int32_t hx; + GET_HIGH_WORD(hx,x); + return (int)((u_int32_t)((hx&0x7fffffff)-0x7ff00000)>>31); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_finitef.c b/libm/upstream-freebsd/lib/msun/src/s_finitef.c new file mode 100644 index 0000000..c62239e --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_finitef.c @@ -0,0 +1,32 @@ +/* s_finitef.c -- float version of s_finite.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * finitef(x) returns 1 is x is finite, else 0; + * no branching! + */ + +#include "math.h" +#include "math_private.h" + + int finitef(float x) +{ + int32_t ix; + GET_FLOAT_WORD(ix,x); + return (int)((u_int32_t)((ix&0x7fffffff)-0x7f800000)>>31); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_floor.c b/libm/upstream-freebsd/lib/msun/src/s_floor.c new file mode 100644 index 0000000..65f696a --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_floor.c @@ -0,0 +1,78 @@ +/* @(#)s_floor.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * floor(x) + * Return x rounded toward -inf to integral value + * Method: + * Bit twiddling. + * Exception: + * Inexact flag raised if x not equal to floor(x). + */ + +#include <float.h> + +#include "math.h" +#include "math_private.h" + +static const double huge = 1.0e300; + +double +floor(double x) +{ + int32_t i0,i1,j0; + u_int32_t i,j; + EXTRACT_WORDS(i0,i1,x); + j0 = ((i0>>20)&0x7ff)-0x3ff; + if(j0<20) { + if(j0<0) { /* raise inexact if x != 0 */ + if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */ + if(i0>=0) {i0=i1=0;} + else if(((i0&0x7fffffff)|i1)!=0) + { i0=0xbff00000;i1=0;} + } + } else { + i = (0x000fffff)>>j0; + if(((i0&i)|i1)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + if(i0<0) i0 += (0x00100000)>>j0; + i0 &= (~i); i1=0; + } + } + } else if (j0>51) { + if(j0==0x400) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } else { + i = ((u_int32_t)(0xffffffff))>>(j0-20); + if((i1&i)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + if(i0<0) { + if(j0==20) i0+=1; + else { + j = i1+(1<<(52-j0)); + if(j<i1) i0 +=1 ; /* got a carry */ + i1=j; + } + } + i1 &= (~i); + } + } + INSERT_WORDS(x,i0,i1); + return x; +} + +#if LDBL_MANT_DIG == 53 +__weak_reference(floor, floorl); +#endif diff --git a/libm/upstream-freebsd/lib/msun/src/s_floorf.c b/libm/upstream-freebsd/lib/msun/src/s_floorf.c new file mode 100644 index 0000000..6b510de --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_floorf.c @@ -0,0 +1,61 @@ +/* s_floorf.c -- float version of s_floor.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * floorf(x) + * Return x rounded toward -inf to integral value + * Method: + * Bit twiddling. + * Exception: + * Inexact flag raised if x not equal to floorf(x). + */ + +#include "math.h" +#include "math_private.h" + +static const float huge = 1.0e30; + +float +floorf(float x) +{ + int32_t i0,j0; + u_int32_t i; + GET_FLOAT_WORD(i0,x); + j0 = ((i0>>23)&0xff)-0x7f; + if(j0<23) { + if(j0<0) { /* raise inexact if x != 0 */ + if(huge+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */ + if(i0>=0) {i0=0;} + else if((i0&0x7fffffff)!=0) + { i0=0xbf800000;} + } + } else { + i = (0x007fffff)>>j0; + if((i0&i)==0) return x; /* x is integral */ + if(huge+x>(float)0.0) { /* raise inexact flag */ + if(i0<0) i0 += (0x00800000)>>j0; + i0 &= (~i); + } + } + } else { + if(j0==0x80) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } + SET_FLOAT_WORD(x,i0); + return x; +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_floorl.c b/libm/upstream-freebsd/lib/msun/src/s_floorl.c new file mode 100644 index 0000000..6cec3e7 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_floorl.c @@ -0,0 +1,101 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * From: @(#)s_floor.c 5.1 93/09/24 + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * floorl(x) + * Return x rounded toward -inf to integral value + * Method: + * Bit twiddling. + * Exception: + * Inexact flag raised if x not equal to floorl(x). + */ + +#include <float.h> +#include <math.h> +#include <stdint.h> + +#include "fpmath.h" + +#ifdef LDBL_IMPLICIT_NBIT +#define MANH_SIZE (LDBL_MANH_SIZE + 1) +#define INC_MANH(u, c) do { \ + uint64_t o = u.bits.manh; \ + u.bits.manh += (c); \ + if (u.bits.manh < o) \ + u.bits.exp++; \ +} while (0) +#else +#define MANH_SIZE LDBL_MANH_SIZE +#define INC_MANH(u, c) do { \ + uint64_t o = u.bits.manh; \ + u.bits.manh += (c); \ + if (u.bits.manh < o) { \ + u.bits.exp++; \ + u.bits.manh |= 1llu << (LDBL_MANH_SIZE - 1); \ + } \ +} while (0) +#endif + +static const long double huge = 1.0e300; + +long double +floorl(long double x) +{ + union IEEEl2bits u = { .e = x }; + int e = u.bits.exp - LDBL_MAX_EXP + 1; + + if (e < MANH_SIZE - 1) { + if (e < 0) { /* raise inexact if x != 0 */ + if (huge + x > 0.0) + if (u.bits.exp > 0 || + (u.bits.manh | u.bits.manl) != 0) + u.e = u.bits.sign ? -1.0 : 0.0; + } else { + uint64_t m = ((1llu << MANH_SIZE) - 1) >> (e + 1); + if (((u.bits.manh & m) | u.bits.manl) == 0) + return (x); /* x is integral */ + if (u.bits.sign) { +#ifdef LDBL_IMPLICIT_NBIT + if (e == 0) + u.bits.exp++; + else +#endif + INC_MANH(u, 1llu << (MANH_SIZE - e - 1)); + } + if (huge + x > 0.0) { /* raise inexact flag */ + u.bits.manh &= ~m; + u.bits.manl = 0; + } + } + } else if (e < LDBL_MANT_DIG - 1) { + uint64_t m = (uint64_t)-1 >> (64 - LDBL_MANT_DIG + e + 1); + if ((u.bits.manl & m) == 0) + return (x); /* x is integral */ + if (u.bits.sign) { + if (e == MANH_SIZE - 1) + INC_MANH(u, 1); + else { + uint64_t o = u.bits.manl; + u.bits.manl += 1llu << (LDBL_MANT_DIG - e - 1); + if (u.bits.manl < o) /* got a carry */ + INC_MANH(u, 1); + } + } + if (huge + x > 0.0) /* raise inexact flag */ + u.bits.manl &= ~m; + } + return (u.e); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_fma.c b/libm/upstream-freebsd/lib/msun/src/s_fma.c new file mode 100644 index 0000000..dfbd13c --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_fma.c @@ -0,0 +1,284 @@ +/*- + * Copyright (c) 2005-2011 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <fenv.h> +#include <float.h> +#include <math.h> + +#include "math_private.h" + +/* + * A struct dd represents a floating-point number with twice the precision + * of a double. We maintain the invariant that "hi" stores the 53 high-order + * bits of the result. + */ +struct dd { + double hi; + double lo; +}; + +/* + * Compute a+b exactly, returning the exact result in a struct dd. We assume + * that both a and b are finite, but make no assumptions about their relative + * magnitudes. + */ +static inline struct dd +dd_add(double a, double b) +{ + struct dd ret; + double s; + + ret.hi = a + b; + s = ret.hi - a; + ret.lo = (a - (ret.hi - s)) + (b - s); + return (ret); +} + +/* + * Compute a+b, with a small tweak: The least significant bit of the + * result is adjusted into a sticky bit summarizing all the bits that + * were lost to rounding. This adjustment negates the effects of double + * rounding when the result is added to another number with a higher + * exponent. For an explanation of round and sticky bits, see any reference + * on FPU design, e.g., + * + * J. Coonen. An Implementation Guide to a Proposed Standard for + * Floating-Point Arithmetic. Computer, vol. 13, no. 1, Jan 1980. + */ +static inline double +add_adjusted(double a, double b) +{ + struct dd sum; + uint64_t hibits, lobits; + + sum = dd_add(a, b); + if (sum.lo != 0) { + EXTRACT_WORD64(hibits, sum.hi); + if ((hibits & 1) == 0) { + /* hibits += (int)copysign(1.0, sum.hi * sum.lo) */ + EXTRACT_WORD64(lobits, sum.lo); + hibits += 1 - ((hibits ^ lobits) >> 62); + INSERT_WORD64(sum.hi, hibits); + } + } + return (sum.hi); +} + +/* + * Compute ldexp(a+b, scale) with a single rounding error. It is assumed + * that the result will be subnormal, and care is taken to ensure that + * double rounding does not occur. + */ +static inline double +add_and_denormalize(double a, double b, int scale) +{ + struct dd sum; + uint64_t hibits, lobits; + int bits_lost; + + sum = dd_add(a, b); + + /* + * If we are losing at least two bits of accuracy to denormalization, + * then the first lost bit becomes a round bit, and we adjust the + * lowest bit of sum.hi to make it a sticky bit summarizing all the + * bits in sum.lo. With the sticky bit adjusted, the hardware will + * break any ties in the correct direction. + * + * If we are losing only one bit to denormalization, however, we must + * break the ties manually. + */ + if (sum.lo != 0) { + EXTRACT_WORD64(hibits, sum.hi); + bits_lost = -((int)(hibits >> 52) & 0x7ff) - scale + 1; + if (bits_lost != 1 ^ (int)(hibits & 1)) { + /* hibits += (int)copysign(1.0, sum.hi * sum.lo) */ + EXTRACT_WORD64(lobits, sum.lo); + hibits += 1 - (((hibits ^ lobits) >> 62) & 2); + INSERT_WORD64(sum.hi, hibits); + } + } + return (ldexp(sum.hi, scale)); +} + +/* + * Compute a*b exactly, returning the exact result in a struct dd. We assume + * that both a and b are normalized, so no underflow or overflow will occur. + * The current rounding mode must be round-to-nearest. + */ +static inline struct dd +dd_mul(double a, double b) +{ + static const double split = 0x1p27 + 1.0; + struct dd ret; + double ha, hb, la, lb, p, q; + + p = a * split; + ha = a - p; + ha += p; + la = a - ha; + + p = b * split; + hb = b - p; + hb += p; + lb = b - hb; + + p = ha * hb; + q = ha * lb + la * hb; + + ret.hi = p + q; + ret.lo = p - ret.hi + q + la * lb; + return (ret); +} + +/* + * Fused multiply-add: Compute x * y + z with a single rounding error. + * + * We use scaling to avoid overflow/underflow, along with the + * canonical precision-doubling technique adapted from: + * + * Dekker, T. A Floating-Point Technique for Extending the + * Available Precision. Numer. Math. 18, 224-242 (1971). + * + * This algorithm is sensitive to the rounding precision. FPUs such + * as the i387 must be set in double-precision mode if variables are + * to be stored in FP registers in order to avoid incorrect results. + * This is the default on FreeBSD, but not on many other systems. + * + * Hardware instructions should be used on architectures that support it, + * since this implementation will likely be several times slower. + */ +double +fma(double x, double y, double z) +{ + double xs, ys, zs, adj; + struct dd xy, r; + int oround; + int ex, ey, ez; + int spread; + + /* + * Handle special cases. The order of operations and the particular + * return values here are crucial in handling special cases involving + * infinities, NaNs, overflows, and signed zeroes correctly. + */ + if (x == 0.0 || y == 0.0) + return (x * y + z); + if (z == 0.0) + return (x * y); + if (!isfinite(x) || !isfinite(y)) + return (x * y + z); + if (!isfinite(z)) + return (z); + + xs = frexp(x, &ex); + ys = frexp(y, &ey); + zs = frexp(z, &ez); + oround = fegetround(); + spread = ex + ey - ez; + + /* + * If x * y and z are many orders of magnitude apart, the scaling + * will overflow, so we handle these cases specially. Rounding + * modes other than FE_TONEAREST are painful. + */ + if (spread < -DBL_MANT_DIG) { + feraiseexcept(FE_INEXACT); + if (!isnormal(z)) + feraiseexcept(FE_UNDERFLOW); + switch (oround) { + case FE_TONEAREST: + return (z); + case FE_TOWARDZERO: + if (x > 0.0 ^ y < 0.0 ^ z < 0.0) + return (z); + else + return (nextafter(z, 0)); + case FE_DOWNWARD: + if (x > 0.0 ^ y < 0.0) + return (z); + else + return (nextafter(z, -INFINITY)); + default: /* FE_UPWARD */ + if (x > 0.0 ^ y < 0.0) + return (nextafter(z, INFINITY)); + else + return (z); + } + } + if (spread <= DBL_MANT_DIG * 2) + zs = ldexp(zs, -spread); + else + zs = copysign(DBL_MIN, zs); + + fesetround(FE_TONEAREST); + + /* + * Basic approach for round-to-nearest: + * + * (xy.hi, xy.lo) = x * y (exact) + * (r.hi, r.lo) = xy.hi + z (exact) + * adj = xy.lo + r.lo (inexact; low bit is sticky) + * result = r.hi + adj (correctly rounded) + */ + xy = dd_mul(xs, ys); + r = dd_add(xy.hi, zs); + + spread = ex + ey; + + if (r.hi == 0.0) { + /* + * When the addends cancel to 0, ensure that the result has + * the correct sign. + */ + fesetround(oround); + volatile double vzs = zs; /* XXX gcc CSE bug workaround */ + return (xy.hi + vzs + ldexp(xy.lo, spread)); + } + + if (oround != FE_TONEAREST) { + /* + * There is no need to worry about double rounding in directed + * rounding modes. + */ + fesetround(oround); + adj = r.lo + xy.lo; + return (ldexp(r.hi + adj, spread)); + } + + adj = add_adjusted(r.lo, xy.lo); + if (spread + ilogb(r.hi) > -1023) + return (ldexp(r.hi + adj, spread)); + else + return (add_and_denormalize(r.hi, adj, spread)); +} + +#if (LDBL_MANT_DIG == 53) +__weak_reference(fma, fmal); +#endif diff --git a/libm/upstream-freebsd/lib/msun/src/s_fmaf.c b/libm/upstream-freebsd/lib/msun/src/s_fmaf.c new file mode 100644 index 0000000..3695823 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_fmaf.c @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 2005-2011 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <fenv.h> + +#include "math.h" +#include "math_private.h" + +/* + * Fused multiply-add: Compute x * y + z with a single rounding error. + * + * A double has more than twice as much precision than a float, so + * direct double-precision arithmetic suffices, except where double + * rounding occurs. + */ +float +fmaf(float x, float y, float z) +{ + double xy, result; + uint32_t hr, lr; + + xy = (double)x * y; + result = xy + z; + EXTRACT_WORDS(hr, lr, result); + /* Common case: The double precision result is fine. */ + if ((lr & 0x1fffffff) != 0x10000000 || /* not a halfway case */ + (hr & 0x7ff00000) == 0x7ff00000 || /* NaN */ + result - xy == z || /* exact */ + fegetround() != FE_TONEAREST) /* not round-to-nearest */ + return (result); + + /* + * If result is inexact, and exactly halfway between two float values, + * we need to adjust the low-order bit in the direction of the error. + */ + fesetround(FE_TOWARDZERO); + volatile double vxy = xy; /* XXX work around gcc CSE bug */ + double adjusted_result = vxy + z; + fesetround(FE_TONEAREST); + if (result == adjusted_result) + SET_LOW_WORD(adjusted_result, lr + 1); + return (adjusted_result); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_fmal.c b/libm/upstream-freebsd/lib/msun/src/s_fmal.c new file mode 100644 index 0000000..c2a6913 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_fmal.c @@ -0,0 +1,268 @@ +/*- + * Copyright (c) 2005-2011 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <fenv.h> +#include <float.h> +#include <math.h> + +#include "fpmath.h" + +/* + * A struct dd represents a floating-point number with twice the precision + * of a long double. We maintain the invariant that "hi" stores the high-order + * bits of the result. + */ +struct dd { + long double hi; + long double lo; +}; + +/* + * Compute a+b exactly, returning the exact result in a struct dd. We assume + * that both a and b are finite, but make no assumptions about their relative + * magnitudes. + */ +static inline struct dd +dd_add(long double a, long double b) +{ + struct dd ret; + long double s; + + ret.hi = a + b; + s = ret.hi - a; + ret.lo = (a - (ret.hi - s)) + (b - s); + return (ret); +} + +/* + * Compute a+b, with a small tweak: The least significant bit of the + * result is adjusted into a sticky bit summarizing all the bits that + * were lost to rounding. This adjustment negates the effects of double + * rounding when the result is added to another number with a higher + * exponent. For an explanation of round and sticky bits, see any reference + * on FPU design, e.g., + * + * J. Coonen. An Implementation Guide to a Proposed Standard for + * Floating-Point Arithmetic. Computer, vol. 13, no. 1, Jan 1980. + */ +static inline long double +add_adjusted(long double a, long double b) +{ + struct dd sum; + union IEEEl2bits u; + + sum = dd_add(a, b); + if (sum.lo != 0) { + u.e = sum.hi; + if ((u.bits.manl & 1) == 0) + sum.hi = nextafterl(sum.hi, INFINITY * sum.lo); + } + return (sum.hi); +} + +/* + * Compute ldexp(a+b, scale) with a single rounding error. It is assumed + * that the result will be subnormal, and care is taken to ensure that + * double rounding does not occur. + */ +static inline long double +add_and_denormalize(long double a, long double b, int scale) +{ + struct dd sum; + int bits_lost; + union IEEEl2bits u; + + sum = dd_add(a, b); + + /* + * If we are losing at least two bits of accuracy to denormalization, + * then the first lost bit becomes a round bit, and we adjust the + * lowest bit of sum.hi to make it a sticky bit summarizing all the + * bits in sum.lo. With the sticky bit adjusted, the hardware will + * break any ties in the correct direction. + * + * If we are losing only one bit to denormalization, however, we must + * break the ties manually. + */ + if (sum.lo != 0) { + u.e = sum.hi; + bits_lost = -u.bits.exp - scale + 1; + if (bits_lost != 1 ^ (int)(u.bits.manl & 1)) + sum.hi = nextafterl(sum.hi, INFINITY * sum.lo); + } + return (ldexp(sum.hi, scale)); +} + +/* + * Compute a*b exactly, returning the exact result in a struct dd. We assume + * that both a and b are normalized, so no underflow or overflow will occur. + * The current rounding mode must be round-to-nearest. + */ +static inline struct dd +dd_mul(long double a, long double b) +{ +#if LDBL_MANT_DIG == 64 + static const long double split = 0x1p32L + 1.0; +#elif LDBL_MANT_DIG == 113 + static const long double split = 0x1p57L + 1.0; +#endif + struct dd ret; + long double ha, hb, la, lb, p, q; + + p = a * split; + ha = a - p; + ha += p; + la = a - ha; + + p = b * split; + hb = b - p; + hb += p; + lb = b - hb; + + p = ha * hb; + q = ha * lb + la * hb; + + ret.hi = p + q; + ret.lo = p - ret.hi + q + la * lb; + return (ret); +} + +/* + * Fused multiply-add: Compute x * y + z with a single rounding error. + * + * We use scaling to avoid overflow/underflow, along with the + * canonical precision-doubling technique adapted from: + * + * Dekker, T. A Floating-Point Technique for Extending the + * Available Precision. Numer. Math. 18, 224-242 (1971). + */ +long double +fmal(long double x, long double y, long double z) +{ + long double xs, ys, zs, adj; + struct dd xy, r; + int oround; + int ex, ey, ez; + int spread; + + /* + * Handle special cases. The order of operations and the particular + * return values here are crucial in handling special cases involving + * infinities, NaNs, overflows, and signed zeroes correctly. + */ + if (x == 0.0 || y == 0.0) + return (x * y + z); + if (z == 0.0) + return (x * y); + if (!isfinite(x) || !isfinite(y)) + return (x * y + z); + if (!isfinite(z)) + return (z); + + xs = frexpl(x, &ex); + ys = frexpl(y, &ey); + zs = frexpl(z, &ez); + oround = fegetround(); + spread = ex + ey - ez; + + /* + * If x * y and z are many orders of magnitude apart, the scaling + * will overflow, so we handle these cases specially. Rounding + * modes other than FE_TONEAREST are painful. + */ + if (spread < -LDBL_MANT_DIG) { + feraiseexcept(FE_INEXACT); + if (!isnormal(z)) + feraiseexcept(FE_UNDERFLOW); + switch (oround) { + case FE_TONEAREST: + return (z); + case FE_TOWARDZERO: + if (x > 0.0 ^ y < 0.0 ^ z < 0.0) + return (z); + else + return (nextafterl(z, 0)); + case FE_DOWNWARD: + if (x > 0.0 ^ y < 0.0) + return (z); + else + return (nextafterl(z, -INFINITY)); + default: /* FE_UPWARD */ + if (x > 0.0 ^ y < 0.0) + return (nextafterl(z, INFINITY)); + else + return (z); + } + } + if (spread <= LDBL_MANT_DIG * 2) + zs = ldexpl(zs, -spread); + else + zs = copysignl(LDBL_MIN, zs); + + fesetround(FE_TONEAREST); + + /* + * Basic approach for round-to-nearest: + * + * (xy.hi, xy.lo) = x * y (exact) + * (r.hi, r.lo) = xy.hi + z (exact) + * adj = xy.lo + r.lo (inexact; low bit is sticky) + * result = r.hi + adj (correctly rounded) + */ + xy = dd_mul(xs, ys); + r = dd_add(xy.hi, zs); + + spread = ex + ey; + + if (r.hi == 0.0) { + /* + * When the addends cancel to 0, ensure that the result has + * the correct sign. + */ + fesetround(oround); + volatile long double vzs = zs; /* XXX gcc CSE bug workaround */ + return (xy.hi + vzs + ldexpl(xy.lo, spread)); + } + + if (oround != FE_TONEAREST) { + /* + * There is no need to worry about double rounding in directed + * rounding modes. + */ + fesetround(oround); + adj = r.lo + xy.lo; + return (ldexpl(r.hi + adj, spread)); + } + + adj = add_adjusted(r.lo, xy.lo); + if (spread + ilogbl(r.hi) > -16383) + return (ldexpl(r.hi + adj, spread)); + else + return (add_and_denormalize(r.hi, adj, spread)); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_fmax.c b/libm/upstream-freebsd/lib/msun/src/s_fmax.c new file mode 100644 index 0000000..b51b865 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_fmax.c @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <math.h> + +#include "fpmath.h" + +double +fmax(double x, double y) +{ + union IEEEd2bits u[2]; + + u[0].d = x; + u[1].d = y; + + /* Check for NaNs to avoid raising spurious exceptions. */ + if (u[0].bits.exp == 2047 && (u[0].bits.manh | u[0].bits.manl) != 0) + return (y); + if (u[1].bits.exp == 2047 && (u[1].bits.manh | u[1].bits.manl) != 0) + return (x); + + /* Handle comparisons of signed zeroes. */ + if (u[0].bits.sign != u[1].bits.sign) + return (u[u[0].bits.sign].d); + + return (x > y ? x : y); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_fmaxf.c b/libm/upstream-freebsd/lib/msun/src/s_fmaxf.c new file mode 100644 index 0000000..423da54 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_fmaxf.c @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <math.h> + +#include "fpmath.h" + +float +fmaxf(float x, float y) +{ + union IEEEf2bits u[2]; + + u[0].f = x; + u[1].f = y; + + /* Check for NaNs to avoid raising spurious exceptions. */ + if (u[0].bits.exp == 255 && u[0].bits.man != 0) + return (y); + if (u[1].bits.exp == 255 && u[1].bits.man != 0) + return (x); + + /* Handle comparisons of signed zeroes. */ + if (u[0].bits.sign != u[1].bits.sign) + return (u[u[0].bits.sign].f); + + return (x > y ? x : y); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_fmaxl.c b/libm/upstream-freebsd/lib/msun/src/s_fmaxl.c new file mode 100644 index 0000000..0ac48a9 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_fmaxl.c @@ -0,0 +1,55 @@ +/*- + * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <math.h> + +#include "fpmath.h" + +long double +fmaxl(long double x, long double y) +{ + union IEEEl2bits u[2]; + + u[0].e = x; + mask_nbit_l(u[0]); + u[1].e = y; + mask_nbit_l(u[1]); + + /* Check for NaNs to avoid raising spurious exceptions. */ + if (u[0].bits.exp == 32767 && (u[0].bits.manh | u[0].bits.manl) != 0) + return (y); + if (u[1].bits.exp == 32767 && (u[1].bits.manh | u[1].bits.manl) != 0) + return (x); + + /* Handle comparisons of signed zeroes. */ + if (u[0].bits.sign != u[1].bits.sign) + return (u[0].bits.sign ? y : x); + + return (x > y ? x : y); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_fmin.c b/libm/upstream-freebsd/lib/msun/src/s_fmin.c new file mode 100644 index 0000000..3500c84 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_fmin.c @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <math.h> + +#include "fpmath.h" + +double +fmin(double x, double y) +{ + union IEEEd2bits u[2]; + + u[0].d = x; + u[1].d = y; + + /* Check for NaNs to avoid raising spurious exceptions. */ + if (u[0].bits.exp == 2047 && (u[0].bits.manh | u[0].bits.manl) != 0) + return (y); + if (u[1].bits.exp == 2047 && (u[1].bits.manh | u[1].bits.manl) != 0) + return (x); + + /* Handle comparisons of signed zeroes. */ + if (u[0].bits.sign != u[1].bits.sign) + return (u[u[1].bits.sign].d); + + return (x < y ? x : y); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_fminf.c b/libm/upstream-freebsd/lib/msun/src/s_fminf.c new file mode 100644 index 0000000..76a5c76 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_fminf.c @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <math.h> + +#include "fpmath.h" + +float +fminf(float x, float y) +{ + union IEEEf2bits u[2]; + + u[0].f = x; + u[1].f = y; + + /* Check for NaNs to avoid raising spurious exceptions. */ + if (u[0].bits.exp == 255 && u[0].bits.man != 0) + return (y); + if (u[1].bits.exp == 255 && u[1].bits.man != 0) + return (x); + + /* Handle comparisons of signed zeroes. */ + if (u[0].bits.sign != u[1].bits.sign) + return (u[u[1].bits.sign].f); + + return (x < y ? x : y); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_fminl.c b/libm/upstream-freebsd/lib/msun/src/s_fminl.c new file mode 100644 index 0000000..f9d3ebb --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_fminl.c @@ -0,0 +1,55 @@ +/*- + * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <math.h> + +#include "fpmath.h" + +long double +fminl(long double x, long double y) +{ + union IEEEl2bits u[2]; + + u[0].e = x; + mask_nbit_l(u[0]); + u[1].e = y; + mask_nbit_l(u[1]); + + /* Check for NaNs to avoid raising spurious exceptions. */ + if (u[0].bits.exp == 32767 && (u[0].bits.manh | u[0].bits.manl) != 0) + return (y); + if (u[1].bits.exp == 32767 && (u[1].bits.manh | u[1].bits.manl) != 0) + return (x); + + /* Handle comparisons of signed zeroes. */ + if (u[0].bits.sign != u[1].bits.sign) + return (u[1].bits.sign ? y : x); + + return (x < y ? x : y); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_frexp.c b/libm/upstream-freebsd/lib/msun/src/s_frexp.c new file mode 100644 index 0000000..318a991 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_frexp.c @@ -0,0 +1,56 @@ +/* @(#)s_frexp.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * for non-zero x + * x = frexp(arg,&exp); + * return a double fp quantity x such that 0.5 <= |x| <1.0 + * and the corresponding binary exponent "exp". That is + * arg = x*2^exp. + * If arg is inf, 0.0, or NaN, then frexp(arg,&exp) returns arg + * with *exp=0. + */ + +#include <float.h> + +#include "math.h" +#include "math_private.h" + +static const double +two54 = 1.80143985094819840000e+16; /* 0x43500000, 0x00000000 */ + +double +frexp(double x, int *eptr) +{ + int32_t hx, ix, lx; + EXTRACT_WORDS(hx,lx,x); + ix = 0x7fffffff&hx; + *eptr = 0; + if(ix>=0x7ff00000||((ix|lx)==0)) return x; /* 0,inf,nan */ + if (ix<0x00100000) { /* subnormal */ + x *= two54; + GET_HIGH_WORD(hx,x); + ix = hx&0x7fffffff; + *eptr = -54; + } + *eptr += (ix>>20)-1022; + hx = (hx&0x800fffff)|0x3fe00000; + SET_HIGH_WORD(x,hx); + return x; +} + +#if (LDBL_MANT_DIG == 53) +__weak_reference(frexp, frexpl); +#endif diff --git a/libm/upstream-freebsd/lib/msun/src/s_frexpf.c b/libm/upstream-freebsd/lib/msun/src/s_frexpf.c new file mode 100644 index 0000000..5a7c486 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_frexpf.c @@ -0,0 +1,43 @@ +/* s_frexpf.c -- float version of s_frexp.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +static const float +two25 = 3.3554432000e+07; /* 0x4c000000 */ + +float +frexpf(float x, int *eptr) +{ + int32_t hx,ix; + GET_FLOAT_WORD(hx,x); + ix = 0x7fffffff&hx; + *eptr = 0; + if(ix>=0x7f800000||(ix==0)) return x; /* 0,inf,nan */ + if (ix<0x00800000) { /* subnormal */ + x *= two25; + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + *eptr = -25; + } + *eptr += (ix>>23)-126; + hx = (hx&0x807fffff)|0x3f000000; + SET_FLOAT_WORD(x,hx); + return x; +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_frexpl.c b/libm/upstream-freebsd/lib/msun/src/s_frexpl.c new file mode 100644 index 0000000..d34f55d --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_frexpl.c @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <float.h> +#include <math.h> + +#include "fpmath.h" + +#if LDBL_MAX_EXP != 0x4000 +#error "Unsupported long double format" +#endif + +long double +frexpl(long double x, int *ex) +{ + union IEEEl2bits u; + + u.e = x; + switch (u.bits.exp) { + case 0: /* 0 or subnormal */ + if ((u.bits.manl | u.bits.manh) == 0) { + *ex = 0; + } else { + u.e *= 0x1.0p514; + *ex = u.bits.exp - 0x4200; + u.bits.exp = 0x3ffe; + } + break; + case 0x7fff: /* infinity or NaN; value of *ex is unspecified */ + break; + default: /* normal */ + *ex = u.bits.exp - 0x3ffe; + u.bits.exp = 0x3ffe; + break; + } + return (u.e); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_ilogb.c b/libm/upstream-freebsd/lib/msun/src/s_ilogb.c new file mode 100644 index 0000000..a930bc9 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_ilogb.c @@ -0,0 +1,48 @@ +/* @(#)s_ilogb.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* ilogb(double x) + * return the binary exponent of non-zero x + * ilogb(0) = FP_ILOGB0 + * ilogb(NaN) = FP_ILOGBNAN (no signal is raised) + * ilogb(inf) = INT_MAX (no signal is raised) + */ + +#include <limits.h> + +#include "math.h" +#include "math_private.h" + + int ilogb(double x) +{ + int32_t hx,lx,ix; + + EXTRACT_WORDS(hx,lx,x); + hx &= 0x7fffffff; + if(hx<0x00100000) { + if((hx|lx)==0) + return FP_ILOGB0; + else /* subnormal x */ + if(hx==0) { + for (ix = -1043; lx>0; lx<<=1) ix -=1; + } else { + for (ix = -1022,hx<<=11; hx>0; hx<<=1) ix -=1; + } + return ix; + } + else if (hx<0x7ff00000) return (hx>>20)-1023; + else if (hx>0x7ff00000 || lx!=0) return FP_ILOGBNAN; + else return INT_MAX; +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_ilogbf.c b/libm/upstream-freebsd/lib/msun/src/s_ilogbf.c new file mode 100644 index 0000000..93fe295 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_ilogbf.c @@ -0,0 +1,40 @@ +/* s_ilogbf.c -- float version of s_ilogb.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <limits.h> + +#include "math.h" +#include "math_private.h" + + int ilogbf(float x) +{ + int32_t hx,ix; + + GET_FLOAT_WORD(hx,x); + hx &= 0x7fffffff; + if(hx<0x00800000) { + if(hx==0) + return FP_ILOGB0; + else /* subnormal x */ + for (ix = -126,hx<<=8; hx>0; hx<<=1) ix -=1; + return ix; + } + else if (hx<0x7f800000) return (hx>>23)-127; + else if (hx>0x7f800000) return FP_ILOGBNAN; + else return INT_MAX; +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_ilogbl.c b/libm/upstream-freebsd/lib/msun/src/s_ilogbl.c new file mode 100644 index 0000000..3211f44 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_ilogbl.c @@ -0,0 +1,53 @@ +/* + * From: @(#)s_ilogb.c 5.1 93/09/24 + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <float.h> +#include <limits.h> +#include <math.h> + +#include "fpmath.h" + +int +ilogbl(long double x) +{ + union IEEEl2bits u; + unsigned long m; + int b; + + u.e = x; + if (u.bits.exp == 0) { + if ((u.bits.manl | u.bits.manh) == 0) + return (FP_ILOGB0); + /* denormalized */ + if (u.bits.manh == 0) { + m = 1lu << (LDBL_MANL_SIZE - 1); + for (b = LDBL_MANH_SIZE; !(u.bits.manl & m); m >>= 1) + b++; + } else { + m = 1lu << (LDBL_MANH_SIZE - 1); + for (b = 0; !(u.bits.manh & m); m >>= 1) + b++; + } +#ifdef LDBL_IMPLICIT_NBIT + b++; +#endif + return (LDBL_MIN_EXP - b - 1); + } else if (u.bits.exp < (LDBL_MAX_EXP << 1) - 1) + return (u.bits.exp - LDBL_MAX_EXP + 1); + else if (u.bits.manl != 0 || u.bits.manh != 0) + return (FP_ILOGBNAN); + else + return (INT_MAX); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_isfinite.c b/libm/upstream-freebsd/lib/msun/src/s_isfinite.c new file mode 100644 index 0000000..c9d1bd7 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_isfinite.c @@ -0,0 +1,58 @@ +/*- + * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <math.h> + +#include "fpmath.h" + +int +__isfinite(double d) +{ + union IEEEd2bits u; + + u.d = d; + return (u.bits.exp != 2047); +} + +int +__isfinitef(float f) +{ + union IEEEf2bits u; + + u.f = f; + return (u.bits.exp != 255); +} + +int +__isfinitel(long double e) +{ + union IEEEl2bits u; + + u.e = e; + return (u.bits.exp != 32767); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_isnan.c b/libm/upstream-freebsd/lib/msun/src/s_isnan.c new file mode 100644 index 0000000..a54ded3 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_isnan.c @@ -0,0 +1,65 @@ +/*- + * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <math.h> + +#include "fpmath.h" + +/* Provided by libc.so */ +#ifndef PIC +#undef isnan +int +isnan(double d) +{ + union IEEEd2bits u; + + u.d = d; + return (u.bits.exp == 2047 && (u.bits.manl != 0 || u.bits.manh != 0)); +} +#endif /* !PIC */ + +int +__isnanf(float f) +{ + union IEEEf2bits u; + + u.f = f; + return (u.bits.exp == 255 && u.bits.man != 0); +} + +int +__isnanl(long double e) +{ + union IEEEl2bits u; + + u.e = e; + mask_nbit_l(u); + return (u.bits.exp == 32767 && (u.bits.manl != 0 || u.bits.manh != 0)); +} + +__weak_reference(__isnanf, isnanf); diff --git a/libm/upstream-freebsd/lib/msun/src/s_isnormal.c b/libm/upstream-freebsd/lib/msun/src/s_isnormal.c new file mode 100644 index 0000000..49f2a74 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_isnormal.c @@ -0,0 +1,58 @@ +/*- + * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <math.h> + +#include "fpmath.h" + +int +__isnormal(double d) +{ + union IEEEd2bits u; + + u.d = d; + return (u.bits.exp != 0 && u.bits.exp != 2047); +} + +int +__isnormalf(float f) +{ + union IEEEf2bits u; + + u.f = f; + return (u.bits.exp != 0 && u.bits.exp != 255); +} + +int +__isnormall(long double e) +{ + union IEEEl2bits u; + + u.e = e; + return (u.bits.exp != 0 && u.bits.exp != 32767); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_llrint.c b/libm/upstream-freebsd/lib/msun/src/s_llrint.c new file mode 100644 index 0000000..7c959ec --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_llrint.c @@ -0,0 +1,9 @@ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#define type double +#define roundit rint +#define dtype long long +#define fn llrint + +#include "s_lrint.c" diff --git a/libm/upstream-freebsd/lib/msun/src/s_llrintf.c b/libm/upstream-freebsd/lib/msun/src/s_llrintf.c new file mode 100644 index 0000000..7ec6015 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_llrintf.c @@ -0,0 +1,9 @@ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#define type float +#define roundit rintf +#define dtype long long +#define fn llrintf + +#include "s_lrint.c" diff --git a/libm/upstream-freebsd/lib/msun/src/s_llrintl.c b/libm/upstream-freebsd/lib/msun/src/s_llrintl.c new file mode 100644 index 0000000..6ef8375 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_llrintl.c @@ -0,0 +1,9 @@ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#define type long double +#define roundit rintl +#define dtype long long +#define fn llrintl + +#include "s_lrint.c" diff --git a/libm/upstream-freebsd/lib/msun/src/s_llround.c b/libm/upstream-freebsd/lib/msun/src/s_llround.c new file mode 100644 index 0000000..827dfc1 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_llround.c @@ -0,0 +1,11 @@ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#define type double +#define roundit round +#define dtype long long +#define DTYPE_MIN LLONG_MIN +#define DTYPE_MAX LLONG_MAX +#define fn llround + +#include "s_lround.c" diff --git a/libm/upstream-freebsd/lib/msun/src/s_llroundf.c b/libm/upstream-freebsd/lib/msun/src/s_llroundf.c new file mode 100644 index 0000000..c037a18 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_llroundf.c @@ -0,0 +1,11 @@ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#define type float +#define roundit roundf +#define dtype long long +#define DTYPE_MIN LLONG_MIN +#define DTYPE_MAX LLONG_MAX +#define fn llroundf + +#include "s_lround.c" diff --git a/libm/upstream-freebsd/lib/msun/src/s_llroundl.c b/libm/upstream-freebsd/lib/msun/src/s_llroundl.c new file mode 100644 index 0000000..02c44eb --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_llroundl.c @@ -0,0 +1,11 @@ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#define type long double +#define roundit roundl +#define dtype long long +#define DTYPE_MIN LLONG_MIN +#define DTYPE_MAX LLONG_MAX +#define fn llroundl + +#include "s_lround.c" diff --git a/libm/upstream-freebsd/lib/msun/src/s_log1p.c b/libm/upstream-freebsd/lib/msun/src/s_log1p.c new file mode 100644 index 0000000..b062a8a --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_log1p.c @@ -0,0 +1,175 @@ +/* @(#)s_log1p.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* double log1p(double x) + * + * Method : + * 1. Argument Reduction: find k and f such that + * 1+x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * Note. If k=0, then f=x is exact. However, if k!=0, then f + * may not be representable exactly. In that case, a correction + * term is need. Let u=1+x rounded. Let c = (1+x)-u, then + * log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u), + * and add back the correction term c/u. + * (Note: when x > 2**53, one can simply return log(x)) + * + * 2. Approximation of log1p(f). + * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) + * = 2s + 2/3 s**3 + 2/5 s**5 + ....., + * = 2s + s*R + * We use a special Reme algorithm on [0,0.1716] to generate + * a polynomial of degree 14 to approximate R The maximum error + * of this polynomial approximation is bounded by 2**-58.45. In + * other words, + * 2 4 6 8 10 12 14 + * R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s +Lp6*s +Lp7*s + * (the values of Lp1 to Lp7 are listed in the program) + * and + * | 2 14 | -58.45 + * | Lp1*s +...+Lp7*s - R(z) | <= 2 + * | | + * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. + * In order to guarantee error in log below 1ulp, we compute log + * by + * log1p(f) = f - (hfsq - s*(hfsq+R)). + * + * 3. Finally, log1p(x) = k*ln2 + log1p(f). + * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) + * Here ln2 is split into two floating point number: + * ln2_hi + ln2_lo, + * where n*ln2_hi is always exact for |n| < 2000. + * + * Special cases: + * log1p(x) is NaN with signal if x < -1 (including -INF) ; + * log1p(+INF) is +INF; log1p(-1) is -INF with signal; + * log1p(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + * + * Note: Assuming log() return accurate answer, the following + * algorithm can be used to compute log1p(x) to within a few ULP: + * + * u = 1+x; + * if(u==1.0) return x ; else + * return log(u)*(x/(u-1.0)); + * + * See HP-15C Advanced Functions Handbook, p.193. + */ + +#include <float.h> + +#include "math.h" +#include "math_private.h" + +static const double +ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */ +ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */ +two54 = 1.80143985094819840000e+16, /* 43500000 00000000 */ +Lp1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ +Lp2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ +Lp3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ +Lp4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ +Lp5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ +Lp6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ +Lp7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +static const double zero = 0.0; + +double +log1p(double x) +{ + double hfsq,f,c,s,z,R,u; + int32_t k,hx,hu,ax; + + GET_HIGH_WORD(hx,x); + ax = hx&0x7fffffff; + + k = 1; + if (hx < 0x3FDA827A) { /* 1+x < sqrt(2)+ */ + if(ax>=0x3ff00000) { /* x <= -1.0 */ + if(x==-1.0) return -two54/zero; /* log1p(-1)=+inf */ + else return (x-x)/(x-x); /* log1p(x<-1)=NaN */ + } + if(ax<0x3e200000) { /* |x| < 2**-29 */ + if(two54+x>zero /* raise inexact */ + &&ax<0x3c900000) /* |x| < 2**-54 */ + return x; + else + return x - x*x*0.5; + } + if(hx>0||hx<=((int32_t)0xbfd2bec4)) { + k=0;f=x;hu=1;} /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + } + if (hx >= 0x7ff00000) return x+x; + if(k!=0) { + if(hx<0x43400000) { + STRICT_ASSIGN(double,u,1.0+x); + GET_HIGH_WORD(hu,u); + k = (hu>>20)-1023; + c = (k>0)? 1.0-(u-x):x-(u-1.0);/* correction term */ + c /= u; + } else { + u = x; + GET_HIGH_WORD(hu,u); + k = (hu>>20)-1023; + c = 0; + } + hu &= 0x000fffff; + /* + * The approximation to sqrt(2) used in thresholds is not + * critical. However, the ones used above must give less + * strict bounds than the one here so that the k==0 case is + * never reached from here, since here we have committed to + * using the correction term but don't use it if k==0. + */ + if(hu<0x6a09e) { /* u ~< sqrt(2) */ + SET_HIGH_WORD(u,hu|0x3ff00000); /* normalize u */ + } else { + k += 1; + SET_HIGH_WORD(u,hu|0x3fe00000); /* normalize u/2 */ + hu = (0x00100000-hu)>>2; + } + f = u-1.0; + } + hfsq=0.5*f*f; + if(hu==0) { /* |f| < 2**-20 */ + if(f==zero) { + if(k==0) { + return zero; + } else { + c += k*ln2_lo; + return k*ln2_hi+c; + } + } + R = hfsq*(1.0-0.66666666666666666*f); + if(k==0) return f-R; else + return k*ln2_hi-((R-(k*ln2_lo+c))-f); + } + s = f/(2.0+f); + z = s*s; + R = z*(Lp1+z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7)))))); + if(k==0) return f-(hfsq-s*(hfsq+R)); else + return k*ln2_hi-((hfsq-(s*(hfsq+R)+(k*ln2_lo+c)))-f); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_log1pf.c b/libm/upstream-freebsd/lib/msun/src/s_log1pf.c new file mode 100644 index 0000000..01d3457 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_log1pf.c @@ -0,0 +1,114 @@ +/* s_log1pf.c -- float version of s_log1p.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <float.h> + +#include "math.h" +#include "math_private.h" + +static const float +ln2_hi = 6.9313812256e-01, /* 0x3f317180 */ +ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */ +two25 = 3.355443200e+07, /* 0x4c000000 */ +Lp1 = 6.6666668653e-01, /* 3F2AAAAB */ +Lp2 = 4.0000000596e-01, /* 3ECCCCCD */ +Lp3 = 2.8571429849e-01, /* 3E924925 */ +Lp4 = 2.2222198546e-01, /* 3E638E29 */ +Lp5 = 1.8183572590e-01, /* 3E3A3325 */ +Lp6 = 1.5313838422e-01, /* 3E1CD04F */ +Lp7 = 1.4798198640e-01; /* 3E178897 */ + +static const float zero = 0.0; + +float +log1pf(float x) +{ + float hfsq,f,c,s,z,R,u; + int32_t k,hx,hu,ax; + + GET_FLOAT_WORD(hx,x); + ax = hx&0x7fffffff; + + k = 1; + if (hx < 0x3ed413d0) { /* 1+x < sqrt(2)+ */ + if(ax>=0x3f800000) { /* x <= -1.0 */ + if(x==(float)-1.0) return -two25/zero; /* log1p(-1)=+inf */ + else return (x-x)/(x-x); /* log1p(x<-1)=NaN */ + } + if(ax<0x38000000) { /* |x| < 2**-15 */ + if(two25+x>zero /* raise inexact */ + &&ax<0x33800000) /* |x| < 2**-24 */ + return x; + else + return x - x*x*(float)0.5; + } + if(hx>0||hx<=((int32_t)0xbe95f619)) { + k=0;f=x;hu=1;} /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + } + if (hx >= 0x7f800000) return x+x; + if(k!=0) { + if(hx<0x5a000000) { + STRICT_ASSIGN(float,u,(float)1.0+x); + GET_FLOAT_WORD(hu,u); + k = (hu>>23)-127; + /* correction term */ + c = (k>0)? (float)1.0-(u-x):x-(u-(float)1.0); + c /= u; + } else { + u = x; + GET_FLOAT_WORD(hu,u); + k = (hu>>23)-127; + c = 0; + } + hu &= 0x007fffff; + /* + * The approximation to sqrt(2) used in thresholds is not + * critical. However, the ones used above must give less + * strict bounds than the one here so that the k==0 case is + * never reached from here, since here we have committed to + * using the correction term but don't use it if k==0. + */ + if(hu<0x3504f4) { /* u < sqrt(2) */ + SET_FLOAT_WORD(u,hu|0x3f800000);/* normalize u */ + } else { + k += 1; + SET_FLOAT_WORD(u,hu|0x3f000000); /* normalize u/2 */ + hu = (0x00800000-hu)>>2; + } + f = u-(float)1.0; + } + hfsq=(float)0.5*f*f; + if(hu==0) { /* |f| < 2**-20 */ + if(f==zero) { + if(k==0) { + return zero; + } else { + c += k*ln2_lo; + return k*ln2_hi+c; + } + } + R = hfsq*((float)1.0-(float)0.66666666666666666*f); + if(k==0) return f-R; else + return k*ln2_hi-((R-(k*ln2_lo+c))-f); + } + s = f/((float)2.0+f); + z = s*s; + R = z*(Lp1+z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7)))))); + if(k==0) return f-(hfsq-s*(hfsq+R)); else + return k*ln2_hi-((hfsq-(s*(hfsq+R)+(k*ln2_lo+c)))-f); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_logb.c b/libm/upstream-freebsd/lib/msun/src/s_logb.c new file mode 100644 index 0000000..a47e354 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_logb.c @@ -0,0 +1,49 @@ +/* @(#)s_logb.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * double logb(x) + * IEEE 754 logb. Included to pass IEEE test suite. Not recommend. + * Use ilogb instead. + */ + +#include <float.h> + +#include "math.h" +#include "math_private.h" + +static const double +two54 = 1.80143985094819840000e+16; /* 43500000 00000000 */ + +double +logb(double x) +{ + int32_t lx,ix; + EXTRACT_WORDS(ix,lx,x); + ix &= 0x7fffffff; /* high |x| */ + if((ix|lx)==0) return -1.0/fabs(x); + if(ix>=0x7ff00000) return x*x; + if(ix<0x00100000) { + x *= two54; /* convert subnormal x to normal */ + GET_HIGH_WORD(ix,x); + ix &= 0x7fffffff; + return (double) ((ix>>20)-1023-54); + } else + return (double) ((ix>>20)-1023); +} + +#if (LDBL_MANT_DIG == 53) +__weak_reference(logb, logbl); +#endif diff --git a/libm/upstream-freebsd/lib/msun/src/s_logbf.c b/libm/upstream-freebsd/lib/msun/src/s_logbf.c new file mode 100644 index 0000000..3ab190d --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_logbf.c @@ -0,0 +1,40 @@ +/* s_logbf.c -- float version of s_logb.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +static const float +two25 = 3.355443200e+07; /* 0x4c000000 */ + +float +logbf(float x) +{ + int32_t ix; + GET_FLOAT_WORD(ix,x); + ix &= 0x7fffffff; /* high |x| */ + if(ix==0) return (float)-1.0/fabsf(x); + if(ix>=0x7f800000) return x*x; + if(ix<0x00800000) { + x *= two25; /* convert subnormal x to normal */ + GET_FLOAT_WORD(ix,x); + ix &= 0x7fffffff; + return (float) ((ix>>23)-127-25); + } else + return (float) ((ix>>23)-127); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_logbl.c b/libm/upstream-freebsd/lib/msun/src/s_logbl.c new file mode 100644 index 0000000..7e88e36 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_logbl.c @@ -0,0 +1,55 @@ +/* + * From: @(#)s_ilogb.c 5.1 93/09/24 + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef lint +static char rcsid[] = "$FreeBSD$"; +#endif + +#include <float.h> +#include <limits.h> +#include <math.h> + +#include "fpmath.h" + +long double +logbl(long double x) +{ + union IEEEl2bits u; + unsigned long m; + int b; + + u.e = x; + if (u.bits.exp == 0) { + if ((u.bits.manl | u.bits.manh) == 0) { /* x == 0 */ + u.bits.sign = 1; + return (1.0L / u.e); + } + /* denormalized */ + if (u.bits.manh == 0) { + m = 1lu << (LDBL_MANL_SIZE - 1); + for (b = LDBL_MANH_SIZE; !(u.bits.manl & m); m >>= 1) + b++; + } else { + m = 1lu << (LDBL_MANH_SIZE - 1); + for (b = 0; !(u.bits.manh & m); m >>= 1) + b++; + } +#ifdef LDBL_IMPLICIT_NBIT + b++; +#endif + return ((long double)(LDBL_MIN_EXP - b - 1)); + } + if (u.bits.exp < (LDBL_MAX_EXP << 1) - 1) /* normal */ + return ((long double)(u.bits.exp - LDBL_MAX_EXP + 1)); + else /* +/- inf or nan */ + return (x * x); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_lrint.c b/libm/upstream-freebsd/lib/msun/src/s_lrint.c new file mode 100644 index 0000000..27ff5ff --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_lrint.c @@ -0,0 +1,58 @@ +/*- + * Copyright (c) 2005 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <fenv.h> +#include <math.h> + +#ifndef type +__FBSDID("$FreeBSD$"); +#define type double +#define roundit rint +#define dtype long +#define fn lrint +#endif + +/* + * C99 says we should not raise a spurious inexact exception when an + * invalid exception is raised. Unfortunately, the set of inputs + * that overflows depends on the rounding mode when 'dtype' has more + * significant bits than 'type'. Hence, we bend over backwards for the + * sake of correctness; an MD implementation could be more efficient. + */ +dtype +fn(type x) +{ + fenv_t env; + dtype d; + + feholdexcept(&env); + d = (dtype)roundit(x); + if (fetestexcept(FE_INVALID)) + feclearexcept(FE_INEXACT); + feupdateenv(&env); + return (d); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_lrintf.c b/libm/upstream-freebsd/lib/msun/src/s_lrintf.c new file mode 100644 index 0000000..a757ded --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_lrintf.c @@ -0,0 +1,9 @@ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#define type float +#define roundit rintf +#define dtype long +#define fn lrintf + +#include "s_lrint.c" diff --git a/libm/upstream-freebsd/lib/msun/src/s_lrintl.c b/libm/upstream-freebsd/lib/msun/src/s_lrintl.c new file mode 100644 index 0000000..497b442 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_lrintl.c @@ -0,0 +1,9 @@ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#define type long double +#define roundit rintl +#define dtype long +#define fn lrintl + +#include "s_lrint.c" diff --git a/libm/upstream-freebsd/lib/msun/src/s_lround.c b/libm/upstream-freebsd/lib/msun/src/s_lround.c new file mode 100644 index 0000000..3cff489 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_lround.c @@ -0,0 +1,66 @@ +/*- + * Copyright (c) 2005 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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/limits.h> +#include <fenv.h> +#include <math.h> + +#ifndef type +__FBSDID("$FreeBSD$"); +#define type double +#define roundit round +#define dtype long +#define DTYPE_MIN LONG_MIN +#define DTYPE_MAX LONG_MAX +#define fn lround +#endif + +/* + * If type has more precision than dtype, the endpoints dtype_(min|max) are + * of the form xxx.5; they are "out of range" because lround() rounds away + * from 0. On the other hand, if type has less precision than dtype, then + * all values that are out of range are integral, so we might as well assume + * that everything is in range. At compile time, INRANGE(x) should reduce to + * two floating-point comparisons in the former case, or TRUE otherwise. + */ +static const type dtype_min = DTYPE_MIN - 0.5; +static const type dtype_max = DTYPE_MAX + 0.5; +#define INRANGE(x) (dtype_max - DTYPE_MAX != 0.5 || \ + ((x) > dtype_min && (x) < dtype_max)) + +dtype +fn(type x) +{ + + if (INRANGE(x)) { + x = roundit(x); + return ((dtype)x); + } else { + feraiseexcept(FE_INVALID); + return (DTYPE_MAX); + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_lroundf.c b/libm/upstream-freebsd/lib/msun/src/s_lroundf.c new file mode 100644 index 0000000..e24fe7f --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_lroundf.c @@ -0,0 +1,11 @@ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#define type float +#define roundit roundf +#define dtype long +#define DTYPE_MIN LONG_MIN +#define DTYPE_MAX LONG_MAX +#define fn lroundf + +#include "s_lround.c" diff --git a/libm/upstream-freebsd/lib/msun/src/s_lroundl.c b/libm/upstream-freebsd/lib/msun/src/s_lroundl.c new file mode 100644 index 0000000..e410827 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_lroundl.c @@ -0,0 +1,11 @@ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#define type long double +#define roundit roundl +#define dtype long +#define DTYPE_MIN LONG_MIN +#define DTYPE_MAX LONG_MAX +#define fn lroundl + +#include "s_lround.c" diff --git a/libm/upstream-freebsd/lib/msun/src/s_modf.c b/libm/upstream-freebsd/lib/msun/src/s_modf.c new file mode 100644 index 0000000..ab13191 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_modf.c @@ -0,0 +1,79 @@ +/* @(#)s_modf.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef lint +static char rcsid[] = "$FreeBSD$"; +#endif + +/* + * modf(double x, double *iptr) + * return fraction part of x, and return x's integral part in *iptr. + * Method: + * Bit twiddling. + * + * Exception: + * No exception. + */ + +#include "math.h" +#include "math_private.h" + +static const double one = 1.0; + +double +modf(double x, double *iptr) +{ + int32_t i0,i1,j0; + u_int32_t i; + EXTRACT_WORDS(i0,i1,x); + j0 = ((i0>>20)&0x7ff)-0x3ff; /* exponent of x */ + if(j0<20) { /* integer part in high x */ + if(j0<0) { /* |x|<1 */ + INSERT_WORDS(*iptr,i0&0x80000000,0); /* *iptr = +-0 */ + return x; + } else { + i = (0x000fffff)>>j0; + if(((i0&i)|i1)==0) { /* x is integral */ + u_int32_t high; + *iptr = x; + GET_HIGH_WORD(high,x); + INSERT_WORDS(x,high&0x80000000,0); /* return +-0 */ + return x; + } else { + INSERT_WORDS(*iptr,i0&(~i),0); + return x - *iptr; + } + } + } else if (j0>51) { /* no fraction part */ + u_int32_t high; + if (j0 == 0x400) { /* inf/NaN */ + *iptr = x; + return 0.0 / x; + } + *iptr = x*one; + GET_HIGH_WORD(high,x); + INSERT_WORDS(x,high&0x80000000,0); /* return +-0 */ + return x; + } else { /* fraction part in low x */ + i = ((u_int32_t)(0xffffffff))>>(j0-20); + if((i1&i)==0) { /* x is integral */ + u_int32_t high; + *iptr = x; + GET_HIGH_WORD(high,x); + INSERT_WORDS(x,high&0x80000000,0); /* return +-0 */ + return x; + } else { + INSERT_WORDS(*iptr,i0,i1&(~i)); + return x - *iptr; + } + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_modff.c b/libm/upstream-freebsd/lib/msun/src/s_modff.c new file mode 100644 index 0000000..062259c --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_modff.c @@ -0,0 +1,57 @@ +/* s_modff.c -- float version of s_modf.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +static const float one = 1.0; + +float +modff(float x, float *iptr) +{ + int32_t i0,j0; + u_int32_t i; + GET_FLOAT_WORD(i0,x); + j0 = ((i0>>23)&0xff)-0x7f; /* exponent of x */ + if(j0<23) { /* integer part in x */ + if(j0<0) { /* |x|<1 */ + SET_FLOAT_WORD(*iptr,i0&0x80000000); /* *iptr = +-0 */ + return x; + } else { + i = (0x007fffff)>>j0; + if((i0&i)==0) { /* x is integral */ + u_int32_t ix; + *iptr = x; + GET_FLOAT_WORD(ix,x); + SET_FLOAT_WORD(x,ix&0x80000000); /* return +-0 */ + return x; + } else { + SET_FLOAT_WORD(*iptr,i0&(~i)); + return x - *iptr; + } + } + } else { /* no fraction part */ + u_int32_t ix; + *iptr = x*one; + if (x != x) /* NaN */ + return x; + GET_FLOAT_WORD(ix,x); + SET_FLOAT_WORD(x,ix&0x80000000); /* return +-0 */ + return x; + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_modfl.c b/libm/upstream-freebsd/lib/msun/src/s_modfl.c new file mode 100644 index 0000000..3dcdf86 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_modfl.c @@ -0,0 +1,101 @@ +/*- + * Copyright (c) 2007 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * Derived from s_modf.c, which has the following Copyright: + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * $FreeBSD$ + */ + +#include <float.h> +#include <math.h> +#include <sys/types.h> + +#include "fpmath.h" + +#if LDBL_MANL_SIZE > 32 +#define MASK ((uint64_t)-1) +#else +#define MASK ((uint32_t)-1) +#endif +/* Return the last n bits of a word, representing the fractional part. */ +#define GETFRAC(bits, n) ((bits) & ~(MASK << (n))) +/* The number of fraction bits in manh, not counting the integer bit */ +#define HIBITS (LDBL_MANT_DIG - LDBL_MANL_SIZE) + +static const long double zero[] = { 0.0L, -0.0L }; + +long double +modfl(long double x, long double *iptr) +{ + union IEEEl2bits ux; + int e; + + ux.e = x; + e = ux.bits.exp - LDBL_MAX_EXP + 1; + if (e < HIBITS) { /* Integer part is in manh. */ + if (e < 0) { /* |x|<1 */ + *iptr = zero[ux.bits.sign]; + return (x); + } else { + if ((GETFRAC(ux.bits.manh, HIBITS - 1 - e) | + ux.bits.manl) == 0) { /* X is an integer. */ + *iptr = x; + return (zero[ux.bits.sign]); + } else { + /* Clear all but the top e+1 bits. */ + ux.bits.manh >>= HIBITS - 1 - e; + ux.bits.manh <<= HIBITS - 1 - e; + ux.bits.manl = 0; + *iptr = ux.e; + return (x - ux.e); + } + } + } else if (e >= LDBL_MANT_DIG - 1) { /* x has no fraction part. */ + *iptr = x; + if (x != x) /* Handle NaNs. */ + return (x); + return (zero[ux.bits.sign]); + } else { /* Fraction part is in manl. */ + if (GETFRAC(ux.bits.manl, LDBL_MANT_DIG - 1 - e) == 0) { + /* x is integral. */ + *iptr = x; + return (zero[ux.bits.sign]); + } else { + /* Clear all but the top e+1 bits. */ + ux.bits.manl >>= LDBL_MANT_DIG - 1 - e; + ux.bits.manl <<= LDBL_MANT_DIG - 1 - e; + *iptr = ux.e; + return (x - ux.e); + } + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_nan.c b/libm/upstream-freebsd/lib/msun/src/s_nan.c new file mode 100644 index 0000000..890f471 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_nan.c @@ -0,0 +1,110 @@ +/*- + * Copyright (c) 2007 David Schultz + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <sys/endian.h> +#include <ctype.h> +#include <float.h> +#include <math.h> +#include <stdint.h> +#include <strings.h> + +#include "math_private.h" + +/* + * Scan a string of hexadecimal digits (the format nan(3) expects) and + * make a bit array (using the local endianness). We stop when we + * encounter an invalid character, NUL, etc. If we overflow, we do + * the same as gcc's __builtin_nan(), namely, discard the high order bits. + * + * The format this routine accepts needs to be compatible with what is used + * in contrib/gdtoa/hexnan.c (for strtod/scanf) and what is used in + * __builtin_nan(). In fact, we're only 100% compatible for strings we + * consider valid, so we might be violating the C standard. But it's + * impossible to use nan(3) portably anyway, so this seems good enough. + */ +void +_scan_nan(uint32_t *words, int num_words, const char *s) +{ + int si; /* index into s */ + int bitpos; /* index into words (in bits) */ + + bzero(words, num_words * sizeof(uint32_t)); + + /* Allow a leading '0x'. (It's expected, but redundant.) */ + if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) + s += 2; + + /* Scan forwards in the string, looking for the end of the sequence. */ + for (si = 0; isxdigit(s[si]); si++) + ; + + /* Scan backwards, filling in the bits in words[] as we go. */ +#if _BYTE_ORDER == _LITTLE_ENDIAN + for (bitpos = 0; bitpos < 32 * num_words; bitpos += 4) { +#else + for (bitpos = 32 * num_words - 4; bitpos >= 0; bitpos -= 4) { +#endif + if (--si < 0) + break; + words[bitpos / 32] |= digittoint(s[si]) << (bitpos % 32); + } +} + +double +nan(const char *s) +{ + union { + double d; + uint32_t bits[2]; + } u; + + _scan_nan(u.bits, 2, s); +#if _BYTE_ORDER == _LITTLE_ENDIAN + u.bits[1] |= 0x7ff80000; +#else + u.bits[0] |= 0x7ff80000; +#endif + return (u.d); +} + +float +nanf(const char *s) +{ + union { + float f; + uint32_t bits[1]; + } u; + + _scan_nan(u.bits, 1, s); + u.bits[0] |= 0x7fc00000; + return (u.f); +} + +#if (LDBL_MANT_DIG == 53) +__weak_reference(nan, nanl); +#endif diff --git a/libm/upstream-freebsd/lib/msun/src/s_nearbyint.c b/libm/upstream-freebsd/lib/msun/src/s_nearbyint.c new file mode 100644 index 0000000..12493d2 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_nearbyint.c @@ -0,0 +1,55 @@ +/*- + * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <fenv.h> +#include <math.h> + +/* + * We save and restore the floating-point environment to avoid raising + * an inexact exception. We can get away with using fesetenv() + * instead of feclearexcept()/feupdateenv() to restore the environment + * because the only exception defined for rint() is overflow, and + * rounding can't overflow as long as emax >= p. + */ +#define DECL(type, fn, rint) \ +type \ +fn(type x) \ +{ \ + type ret; \ + fenv_t env; \ + \ + fegetenv(&env); \ + ret = rint(x); \ + fesetenv(&env); \ + return (ret); \ +} + +DECL(double, nearbyint, rint) +DECL(float, nearbyintf, rintf) +DECL(long double, nearbyintl, rintl) diff --git a/libm/upstream-freebsd/lib/msun/src/s_nextafter.c b/libm/upstream-freebsd/lib/msun/src/s_nextafter.c new file mode 100644 index 0000000..52dd21c --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_nextafter.c @@ -0,0 +1,83 @@ +/* @(#)s_nextafter.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* IEEE functions + * nextafter(x,y) + * return the next machine floating-point number of x in the + * direction toward y. + * Special cases: + */ + +#include <float.h> + +#include "math.h" +#include "math_private.h" + +double +nextafter(double x, double y) +{ + volatile double t; + int32_t hx,hy,ix,iy; + u_int32_t lx,ly; + + EXTRACT_WORDS(hx,lx,x); + EXTRACT_WORDS(hy,ly,y); + ix = hx&0x7fffffff; /* |x| */ + iy = hy&0x7fffffff; /* |y| */ + + if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) || /* x is nan */ + ((iy>=0x7ff00000)&&((iy-0x7ff00000)|ly)!=0)) /* y is nan */ + return x+y; + if(x==y) return y; /* x=y, return y */ + if((ix|lx)==0) { /* x == 0 */ + INSERT_WORDS(x,hy&0x80000000,1); /* return +-minsubnormal */ + t = x*x; + if(t==x) return t; else return x; /* raise underflow flag */ + } + if(hx>=0) { /* x > 0 */ + if(hx>hy||((hx==hy)&&(lx>ly))) { /* x > y, x -= ulp */ + if(lx==0) hx -= 1; + lx -= 1; + } else { /* x < y, x += ulp */ + lx += 1; + if(lx==0) hx += 1; + } + } else { /* x < 0 */ + if(hy>=0||hx>hy||((hx==hy)&&(lx>ly))){/* x < y, x -= ulp */ + if(lx==0) hx -= 1; + lx -= 1; + } else { /* x > y, x += ulp */ + lx += 1; + if(lx==0) hx += 1; + } + } + hy = hx&0x7ff00000; + if(hy>=0x7ff00000) return x+x; /* overflow */ + if(hy<0x00100000) { /* underflow */ + t = x*x; + if(t!=x) { /* raise underflow flag */ + INSERT_WORDS(y,hx,lx); + return y; + } + } + INSERT_WORDS(x,hx,lx); + return x; +} + +#if (LDBL_MANT_DIG == 53) +__weak_reference(nextafter, nexttoward); +__weak_reference(nextafter, nexttowardl); +__weak_reference(nextafter, nextafterl); +#endif diff --git a/libm/upstream-freebsd/lib/msun/src/s_nextafterf.c b/libm/upstream-freebsd/lib/msun/src/s_nextafterf.c new file mode 100644 index 0000000..96e21ef --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_nextafterf.c @@ -0,0 +1,66 @@ +/* s_nextafterf.c -- float version of s_nextafter.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +float +nextafterf(float x, float y) +{ + volatile float t; + int32_t hx,hy,ix,iy; + + GET_FLOAT_WORD(hx,x); + GET_FLOAT_WORD(hy,y); + ix = hx&0x7fffffff; /* |x| */ + iy = hy&0x7fffffff; /* |y| */ + + if((ix>0x7f800000) || /* x is nan */ + (iy>0x7f800000)) /* y is nan */ + return x+y; + if(x==y) return y; /* x=y, return y */ + if(ix==0) { /* x == 0 */ + SET_FLOAT_WORD(x,(hy&0x80000000)|1);/* return +-minsubnormal */ + t = x*x; + if(t==x) return t; else return x; /* raise underflow flag */ + } + if(hx>=0) { /* x > 0 */ + if(hx>hy) { /* x > y, x -= ulp */ + hx -= 1; + } else { /* x < y, x += ulp */ + hx += 1; + } + } else { /* x < 0 */ + if(hy>=0||hx>hy){ /* x < y, x -= ulp */ + hx -= 1; + } else { /* x > y, x += ulp */ + hx += 1; + } + } + hy = hx&0x7f800000; + if(hy>=0x7f800000) return x+x; /* overflow */ + if(hy<0x00800000) { /* underflow */ + t = x*x; + if(t!=x) { /* raise underflow flag */ + SET_FLOAT_WORD(y,hx); + return y; + } + } + SET_FLOAT_WORD(x,hx); + return x; +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_nextafterl.c b/libm/upstream-freebsd/lib/msun/src/s_nextafterl.c new file mode 100644 index 0000000..9c61a43 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_nextafterl.c @@ -0,0 +1,80 @@ +/* @(#)s_nextafter.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* IEEE functions + * nextafter(x,y) + * return the next machine floating-point number of x in the + * direction toward y. + * Special cases: + */ + +#include <float.h> + +#include "fpmath.h" +#include "math.h" +#include "math_private.h" + +#if LDBL_MAX_EXP != 0x4000 +#error "Unsupported long double format" +#endif + +long double +nextafterl(long double x, long double y) +{ + volatile long double t; + union IEEEl2bits ux, uy; + + ux.e = x; + uy.e = y; + + if ((ux.bits.exp == 0x7fff && + ((ux.bits.manh&~LDBL_NBIT)|ux.bits.manl) != 0) || + (uy.bits.exp == 0x7fff && + ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl) != 0)) + return x+y; /* x or y is nan */ + if(x==y) return y; /* x=y, return y */ + if(x==0.0) { + ux.bits.manh = 0; /* return +-minsubnormal */ + ux.bits.manl = 1; + ux.bits.sign = uy.bits.sign; + t = ux.e*ux.e; + if(t==ux.e) return t; else return ux.e; /* raise underflow flag */ + } + if(x>0.0 ^ x<y) { /* x -= ulp */ + if(ux.bits.manl==0) { + if ((ux.bits.manh&~LDBL_NBIT)==0) + ux.bits.exp -= 1; + ux.bits.manh = (ux.bits.manh - 1) | (ux.bits.manh & LDBL_NBIT); + } + ux.bits.manl -= 1; + } else { /* x += ulp */ + ux.bits.manl += 1; + if(ux.bits.manl==0) { + ux.bits.manh = (ux.bits.manh + 1) | (ux.bits.manh & LDBL_NBIT); + if ((ux.bits.manh&~LDBL_NBIT)==0) + ux.bits.exp += 1; + } + } + if(ux.bits.exp==0x7fff) return x+x; /* overflow */ + if(ux.bits.exp==0) { /* underflow */ + mask_nbit_l(ux); + t = ux.e * ux.e; + if(t!=ux.e) /* raise underflow flag */ + return ux.e; + } + return ux.e; +} + +__strong_reference(nextafterl, nexttowardl); diff --git a/libm/upstream-freebsd/lib/msun/src/s_nexttoward.c b/libm/upstream-freebsd/lib/msun/src/s_nexttoward.c new file mode 100644 index 0000000..b2a50d3 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_nexttoward.c @@ -0,0 +1,72 @@ +/* @(#)s_nextafter.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * We assume that a long double has a 15-bit exponent. On systems + * where long double is the same as double, nexttoward() is an alias + * for nextafter(), so we don't use this routine. + */ + +#include <float.h> + +#include "fpmath.h" +#include "math.h" +#include "math_private.h" + +#if LDBL_MAX_EXP != 0x4000 +#error "Unsupported long double format" +#endif + +double +nexttoward(double x, long double y) +{ + union IEEEl2bits uy; + volatile double t; + int32_t hx,ix; + u_int32_t lx; + + EXTRACT_WORDS(hx,lx,x); + ix = hx&0x7fffffff; /* |x| */ + uy.e = y; + + if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) || + (uy.bits.exp == 0x7fff && + ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl) != 0)) + return x+y; /* x or y is nan */ + if(x==y) return (double)y; /* x=y, return y */ + if(x==0.0) { + INSERT_WORDS(x,uy.bits.sign<<31,1); /* return +-minsubnormal */ + t = x*x; + if(t==x) return t; else return x; /* raise underflow flag */ + } + if(hx>0.0 ^ x < y) { /* x -= ulp */ + if(lx==0) hx -= 1; + lx -= 1; + } else { /* x += ulp */ + lx += 1; + if(lx==0) hx += 1; + } + ix = hx&0x7ff00000; + if(ix>=0x7ff00000) return x+x; /* overflow */ + if(ix<0x00100000) { /* underflow */ + t = x*x; + if(t!=x) { /* raise underflow flag */ + INSERT_WORDS(x,hx,lx); + return x; + } + } + INSERT_WORDS(x,hx,lx); + return x; +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_nexttowardf.c b/libm/upstream-freebsd/lib/msun/src/s_nexttowardf.c new file mode 100644 index 0000000..9ddfff9 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_nexttowardf.c @@ -0,0 +1,59 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <float.h> + +#include "fpmath.h" +#include "math.h" +#include "math_private.h" + +#define LDBL_INFNAN_EXP (LDBL_MAX_EXP * 2 - 1) + +float +nexttowardf(float x, long double y) +{ + union IEEEl2bits uy; + volatile float t; + int32_t hx,ix; + + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; /* |x| */ + uy.e = y; + + if((ix>0x7f800000) || + (uy.bits.exp == LDBL_INFNAN_EXP && + ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl) != 0)) + return x+y; /* x or y is nan */ + if(x==y) return (float)y; /* x=y, return y */ + if(ix==0) { /* x == 0 */ + SET_FLOAT_WORD(x,(uy.bits.sign<<31)|1);/* return +-minsubnormal */ + t = x*x; + if(t==x) return t; else return x; /* raise underflow flag */ + } + if(hx>=0 ^ x < y) /* x -= ulp */ + hx -= 1; + else /* x += ulp */ + hx += 1; + ix = hx&0x7f800000; + if(ix>=0x7f800000) return x+x; /* overflow */ + if(ix<0x00800000) { /* underflow */ + t = x*x; + if(t!=x) { /* raise underflow flag */ + SET_FLOAT_WORD(x,hx); + return x; + } + } + SET_FLOAT_WORD(x,hx); + return x; +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_remquo.c b/libm/upstream-freebsd/lib/msun/src/s_remquo.c new file mode 100644 index 0000000..d811c69 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_remquo.c @@ -0,0 +1,159 @@ +/* @(#)e_fmod.c 1.3 95/01/18 */ +/*- + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <float.h> + +#include "math.h" +#include "math_private.h" + +static const double Zero[] = {0.0, -0.0,}; + +/* + * Return the IEEE remainder and set *quo to the last n bits of the + * quotient, rounded to the nearest integer. We choose n=31 because + * we wind up computing all the integer bits of the quotient anyway as + * a side-effect of computing the remainder by the shift and subtract + * method. In practice, this is far more bits than are needed to use + * remquo in reduction algorithms. + */ +double +remquo(double x, double y, int *quo) +{ + int32_t n,hx,hy,hz,ix,iy,sx,i; + u_int32_t lx,ly,lz,q,sxy; + + EXTRACT_WORDS(hx,lx,x); + EXTRACT_WORDS(hy,ly,y); + sxy = (hx ^ hy) & 0x80000000; + sx = hx&0x80000000; /* sign of x */ + hx ^=sx; /* |x| */ + hy &= 0x7fffffff; /* |y| */ + + /* purge off exception values */ + if((hy|ly)==0||(hx>=0x7ff00000)|| /* y=0,or x not finite */ + ((hy|((ly|-ly)>>31))>0x7ff00000)) /* or y is NaN */ + return (x*y)/(x*y); + if(hx<=hy) { + if((hx<hy)||(lx<ly)) { + q = 0; + goto fixup; /* |x|<|y| return x or x-y */ + } + if(lx==ly) { + *quo = (sxy ? -1 : 1); + return Zero[(u_int32_t)sx>>31]; /* |x|=|y| return x*0*/ + } + } + + /* determine ix = ilogb(x) */ + if(hx<0x00100000) { /* subnormal x */ + if(hx==0) { + for (ix = -1043, i=lx; i>0; i<<=1) ix -=1; + } else { + for (ix = -1022,i=(hx<<11); i>0; i<<=1) ix -=1; + } + } else ix = (hx>>20)-1023; + + /* determine iy = ilogb(y) */ + if(hy<0x00100000) { /* subnormal y */ + if(hy==0) { + for (iy = -1043, i=ly; i>0; i<<=1) iy -=1; + } else { + for (iy = -1022,i=(hy<<11); i>0; i<<=1) iy -=1; + } + } else iy = (hy>>20)-1023; + + /* set up {hx,lx}, {hy,ly} and align y to x */ + if(ix >= -1022) + hx = 0x00100000|(0x000fffff&hx); + else { /* subnormal x, shift x to normal */ + n = -1022-ix; + if(n<=31) { + hx = (hx<<n)|(lx>>(32-n)); + lx <<= n; + } else { + hx = lx<<(n-32); + lx = 0; + } + } + if(iy >= -1022) + hy = 0x00100000|(0x000fffff&hy); + else { /* subnormal y, shift y to normal */ + n = -1022-iy; + if(n<=31) { + hy = (hy<<n)|(ly>>(32-n)); + ly <<= n; + } else { + hy = ly<<(n-32); + ly = 0; + } + } + + /* fix point fmod */ + n = ix - iy; + q = 0; + while(n--) { + hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1; + if(hz<0){hx = hx+hx+(lx>>31); lx = lx+lx;} + else {hx = hz+hz+(lz>>31); lx = lz+lz; q++;} + q <<= 1; + } + hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1; + if(hz>=0) {hx=hz;lx=lz;q++;} + + /* convert back to floating value and restore the sign */ + if((hx|lx)==0) { /* return sign(x)*0 */ + q &= 0x7fffffff; + *quo = (sxy ? -q : q); + return Zero[(u_int32_t)sx>>31]; + } + while(hx<0x00100000) { /* normalize x */ + hx = hx+hx+(lx>>31); lx = lx+lx; + iy -= 1; + } + if(iy>= -1022) { /* normalize output */ + hx = ((hx-0x00100000)|((iy+1023)<<20)); + } else { /* subnormal output */ + n = -1022 - iy; + if(n<=20) { + lx = (lx>>n)|((u_int32_t)hx<<(32-n)); + hx >>= n; + } else if (n<=31) { + lx = (hx<<(32-n))|(lx>>n); hx = 0; + } else { + lx = hx>>(n-32); hx = 0; + } + } +fixup: + INSERT_WORDS(x,hx,lx); + y = fabs(y); + if (y < 0x1p-1021) { + if (x+x>y || (x+x==y && (q & 1))) { + q++; + x-=y; + } + } else if (x>0.5*y || (x==0.5*y && (q & 1))) { + q++; + x-=y; + } + GET_HIGH_WORD(hx,x); + SET_HIGH_WORD(x,hx^sx); + q &= 0x7fffffff; + *quo = (sxy ? -q : q); + return x; +} + +#if LDBL_MANT_DIG == 53 +__weak_reference(remquo, remquol); +#endif diff --git a/libm/upstream-freebsd/lib/msun/src/s_remquof.c b/libm/upstream-freebsd/lib/msun/src/s_remquof.c new file mode 100644 index 0000000..f7b4c00 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_remquof.c @@ -0,0 +1,122 @@ +/* @(#)e_fmod.c 1.3 95/01/18 */ +/*- + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +static const float Zero[] = {0.0, -0.0,}; + +/* + * Return the IEEE remainder and set *quo to the last n bits of the + * quotient, rounded to the nearest integer. We choose n=31 because + * we wind up computing all the integer bits of the quotient anyway as + * a side-effect of computing the remainder by the shift and subtract + * method. In practice, this is far more bits than are needed to use + * remquo in reduction algorithms. + */ +float +remquof(float x, float y, int *quo) +{ + int32_t n,hx,hy,hz,ix,iy,sx,i; + u_int32_t q,sxy; + + GET_FLOAT_WORD(hx,x); + GET_FLOAT_WORD(hy,y); + sxy = (hx ^ hy) & 0x80000000; + sx = hx&0x80000000; /* sign of x */ + hx ^=sx; /* |x| */ + hy &= 0x7fffffff; /* |y| */ + + /* purge off exception values */ + if(hy==0||hx>=0x7f800000||hy>0x7f800000) /* y=0,NaN;or x not finite */ + return (x*y)/(x*y); + if(hx<hy) { + q = 0; + goto fixup; /* |x|<|y| return x or x-y */ + } else if(hx==hy) { + *quo = (sxy ? -1 : 1); + return Zero[(u_int32_t)sx>>31]; /* |x|=|y| return x*0*/ + } + + /* determine ix = ilogb(x) */ + if(hx<0x00800000) { /* subnormal x */ + for (ix = -126,i=(hx<<8); i>0; i<<=1) ix -=1; + } else ix = (hx>>23)-127; + + /* determine iy = ilogb(y) */ + if(hy<0x00800000) { /* subnormal y */ + for (iy = -126,i=(hy<<8); i>0; i<<=1) iy -=1; + } else iy = (hy>>23)-127; + + /* set up {hx,lx}, {hy,ly} and align y to x */ + if(ix >= -126) + hx = 0x00800000|(0x007fffff&hx); + else { /* subnormal x, shift x to normal */ + n = -126-ix; + hx <<= n; + } + if(iy >= -126) + hy = 0x00800000|(0x007fffff&hy); + else { /* subnormal y, shift y to normal */ + n = -126-iy; + hy <<= n; + } + + /* fix point fmod */ + n = ix - iy; + q = 0; + while(n--) { + hz=hx-hy; + if(hz<0) hx = hx << 1; + else {hx = hz << 1; q++;} + q <<= 1; + } + hz=hx-hy; + if(hz>=0) {hx=hz;q++;} + + /* convert back to floating value and restore the sign */ + if(hx==0) { /* return sign(x)*0 */ + q &= 0x7fffffff; + *quo = (sxy ? -q : q); + return Zero[(u_int32_t)sx>>31]; + } + while(hx<0x00800000) { /* normalize x */ + hx <<= 1; + iy -= 1; + } + if(iy>= -126) { /* normalize output */ + hx = ((hx-0x00800000)|((iy+127)<<23)); + } else { /* subnormal output */ + n = -126 - iy; + hx >>= n; + } +fixup: + SET_FLOAT_WORD(x,hx); + y = fabsf(y); + if (y < 0x1p-125f) { + if (x+x>y || (x+x==y && (q & 1))) { + q++; + x-=y; + } + } else if (x>0.5f*y || (x==0.5f*y && (q & 1))) { + q++; + x-=y; + } + GET_FLOAT_WORD(hx,x); + SET_FLOAT_WORD(x,hx^sx); + q &= 0x7fffffff; + *quo = (sxy ? -q : q); + return x; +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_remquol.c b/libm/upstream-freebsd/lib/msun/src/s_remquol.c new file mode 100644 index 0000000..712651c --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_remquol.c @@ -0,0 +1,178 @@ +/* @(#)e_fmod.c 1.3 95/01/18 */ +/*- + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <float.h> +#include <stdint.h> + +#include "fpmath.h" +#include "math.h" +#include "math_private.h" + +#define BIAS (LDBL_MAX_EXP - 1) + +#if LDBL_MANL_SIZE > 32 +typedef uint64_t manl_t; +#else +typedef uint32_t manl_t; +#endif + +#if LDBL_MANH_SIZE > 32 +typedef uint64_t manh_t; +#else +typedef uint32_t manh_t; +#endif + +/* + * These macros add and remove an explicit integer bit in front of the + * fractional mantissa, if the architecture doesn't have such a bit by + * default already. + */ +#ifdef LDBL_IMPLICIT_NBIT +#define SET_NBIT(hx) ((hx) | (1ULL << LDBL_MANH_SIZE)) +#define HFRAC_BITS LDBL_MANH_SIZE +#else +#define SET_NBIT(hx) (hx) +#define HFRAC_BITS (LDBL_MANH_SIZE - 1) +#endif + +#define MANL_SHIFT (LDBL_MANL_SIZE - 1) + +static const long double Zero[] = {0.0L, -0.0L}; + +/* + * Return the IEEE remainder and set *quo to the last n bits of the + * quotient, rounded to the nearest integer. We choose n=31 because + * we wind up computing all the integer bits of the quotient anyway as + * a side-effect of computing the remainder by the shift and subtract + * method. In practice, this is far more bits than are needed to use + * remquo in reduction algorithms. + * + * Assumptions: + * - The low part of the mantissa fits in a manl_t exactly. + * - The high part of the mantissa fits in an int64_t with enough room + * for an explicit integer bit in front of the fractional bits. + */ +long double +remquol(long double x, long double y, int *quo) +{ + union IEEEl2bits ux, uy; + int64_t hx,hz; /* We need a carry bit even if LDBL_MANH_SIZE is 32. */ + manh_t hy; + manl_t lx,ly,lz; + int ix,iy,n,q,sx,sxy; + + ux.e = x; + uy.e = y; + sx = ux.bits.sign; + sxy = sx ^ uy.bits.sign; + ux.bits.sign = 0; /* |x| */ + uy.bits.sign = 0; /* |y| */ + x = ux.e; + + /* purge off exception values */ + if((uy.bits.exp|uy.bits.manh|uy.bits.manl)==0 || /* y=0 */ + (ux.bits.exp == BIAS + LDBL_MAX_EXP) || /* or x not finite */ + (uy.bits.exp == BIAS + LDBL_MAX_EXP && + ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl)!=0)) /* or y is NaN */ + return (x*y)/(x*y); + if(ux.bits.exp<=uy.bits.exp) { + if((ux.bits.exp<uy.bits.exp) || + (ux.bits.manh<=uy.bits.manh && + (ux.bits.manh<uy.bits.manh || + ux.bits.manl<uy.bits.manl))) { + q = 0; + goto fixup; /* |x|<|y| return x or x-y */ + } + if(ux.bits.manh==uy.bits.manh && ux.bits.manl==uy.bits.manl) { + *quo = (sxy ? -1 : 1); + return Zero[sx]; /* |x|=|y| return x*0*/ + } + } + + /* determine ix = ilogb(x) */ + if(ux.bits.exp == 0) { /* subnormal x */ + ux.e *= 0x1.0p512; + ix = ux.bits.exp - (BIAS + 512); + } else { + ix = ux.bits.exp - BIAS; + } + + /* determine iy = ilogb(y) */ + if(uy.bits.exp == 0) { /* subnormal y */ + uy.e *= 0x1.0p512; + iy = uy.bits.exp - (BIAS + 512); + } else { + iy = uy.bits.exp - BIAS; + } + + /* set up {hx,lx}, {hy,ly} and align y to x */ + hx = SET_NBIT(ux.bits.manh); + hy = SET_NBIT(uy.bits.manh); + lx = ux.bits.manl; + ly = uy.bits.manl; + + /* fix point fmod */ + n = ix - iy; + q = 0; + + while(n--) { + hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1; + if(hz<0){hx = hx+hx+(lx>>MANL_SHIFT); lx = lx+lx;} + else {hx = hz+hz+(lz>>MANL_SHIFT); lx = lz+lz; q++;} + q <<= 1; + } + hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1; + if(hz>=0) {hx=hz;lx=lz;q++;} + + /* convert back to floating value and restore the sign */ + if((hx|lx)==0) { /* return sign(x)*0 */ + q &= 0x7fffffff; + *quo = (sxy ? -q : q); + return Zero[sx]; + } + while(hx<(1ULL<<HFRAC_BITS)) { /* normalize x */ + hx = hx+hx+(lx>>MANL_SHIFT); lx = lx+lx; + iy -= 1; + } + ux.bits.manh = hx; /* The integer bit is truncated here if needed. */ + ux.bits.manl = lx; + if (iy < LDBL_MIN_EXP) { + ux.bits.exp = iy + (BIAS + 512); + ux.e *= 0x1p-512; + } else { + ux.bits.exp = iy + BIAS; + } + ux.bits.sign = 0; + x = ux.e; +fixup: + y = fabsl(y); + if (y < LDBL_MIN * 2) { + if (x+x>y || (x+x==y && (q & 1))) { + q++; + x-=y; + } + } else if (x>0.5*y || (x==0.5*y && (q & 1))) { + q++; + x-=y; + } + + ux.e = x; + ux.bits.sign ^= sx; + x = ux.e; + + q &= 0x7fffffff; + *quo = (sxy ? -q : q); + return x; +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_rint.c b/libm/upstream-freebsd/lib/msun/src/s_rint.c new file mode 100644 index 0000000..c56f8fb --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_rint.c @@ -0,0 +1,92 @@ +/* @(#)s_rint.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * rint(x) + * Return x rounded to integral value according to the prevailing + * rounding mode. + * Method: + * Using floating addition. + * Exception: + * Inexact flag raised if x not equal to rint(x). + */ + +#include <float.h> + +#include "math.h" +#include "math_private.h" + +static const double +TWO52[2]={ + 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */ + -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */ +}; + +double +rint(double x) +{ + int32_t i0,j0,sx; + u_int32_t i,i1; + double w,t; + EXTRACT_WORDS(i0,i1,x); + sx = (i0>>31)&1; + j0 = ((i0>>20)&0x7ff)-0x3ff; + if(j0<20) { + if(j0<0) { + if(((i0&0x7fffffff)|i1)==0) return x; + i1 |= (i0&0x0fffff); + i0 &= 0xfffe0000; + i0 |= ((i1|-i1)>>12)&0x80000; + SET_HIGH_WORD(x,i0); + STRICT_ASSIGN(double,w,TWO52[sx]+x); + t = w-TWO52[sx]; + GET_HIGH_WORD(i0,t); + SET_HIGH_WORD(t,(i0&0x7fffffff)|(sx<<31)); + return t; + } else { + i = (0x000fffff)>>j0; + if(((i0&i)|i1)==0) return x; /* x is integral */ + i>>=1; + if(((i0&i)|i1)!=0) { + /* + * Some bit is set after the 0.5 bit. To avoid the + * possibility of errors from double rounding in + * w = TWO52[sx]+x, adjust the 0.25 bit to a lower + * guard bit. We do this for all j0<=51. The + * adjustment is trickiest for j0==18 and j0==19 + * since then it spans the word boundary. + */ + if(j0==19) i1 = 0x40000000; else + if(j0==18) i1 = 0x80000000; else + i0 = (i0&(~i))|((0x20000)>>j0); + } + } + } else if (j0>51) { + if(j0==0x400) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } else { + i = ((u_int32_t)(0xffffffff))>>(j0-20); + if((i1&i)==0) return x; /* x is integral */ + i>>=1; + if((i1&i)!=0) i1 = (i1&(~i))|((0x40000000)>>(j0-20)); + } + INSERT_WORDS(x,i0,i1); + STRICT_ASSIGN(double,w,TWO52[sx]+x); + return w-TWO52[sx]; +} + +#if (LDBL_MANT_DIG == 53) +__weak_reference(rint, rintl); +#endif diff --git a/libm/upstream-freebsd/lib/msun/src/s_rintf.c b/libm/upstream-freebsd/lib/msun/src/s_rintf.c new file mode 100644 index 0000000..f8743a4 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_rintf.c @@ -0,0 +1,53 @@ +/* s_rintf.c -- float version of s_rint.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <float.h> +#include <stdint.h> + +#include "math.h" +#include "math_private.h" + +static const float +TWO23[2]={ + 8.3886080000e+06, /* 0x4b000000 */ + -8.3886080000e+06, /* 0xcb000000 */ +}; + +float +rintf(float x) +{ + int32_t i0,j0,sx; + float w,t; + GET_FLOAT_WORD(i0,x); + sx = (i0>>31)&1; + j0 = ((i0>>23)&0xff)-0x7f; + if(j0<23) { + if(j0<0) { + if((i0&0x7fffffff)==0) return x; + STRICT_ASSIGN(float,w,TWO23[sx]+x); + t = w-TWO23[sx]; + GET_FLOAT_WORD(i0,t); + SET_FLOAT_WORD(t,(i0&0x7fffffff)|(sx<<31)); + return t; + } + STRICT_ASSIGN(float,w,TWO23[sx]+x); + return w-TWO23[sx]; + } + if(j0==0x80) return x+x; /* inf or NaN */ + else return x; /* x is integral */ +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_rintl.c b/libm/upstream-freebsd/lib/msun/src/s_rintl.c new file mode 100644 index 0000000..b43df89 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_rintl.c @@ -0,0 +1,90 @@ +/*- + * Copyright (c) 2008 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <float.h> +#include <math.h> + +#include "fpmath.h" + +#if LDBL_MAX_EXP != 0x4000 +/* We also require the usual bias, min exp and expsign packing. */ +#error "Unsupported long double format" +#endif + +#define BIAS (LDBL_MAX_EXP - 1) + +static const float +shift[2] = { +#if LDBL_MANT_DIG == 64 + 0x1.0p63, -0x1.0p63 +#elif LDBL_MANT_DIG == 113 + 0x1.0p112, -0x1.0p112 +#else +#error "Unsupported long double format" +#endif +}; +static const float zero[2] = { 0.0, -0.0 }; + +long double +rintl(long double x) +{ + union IEEEl2bits u; + uint32_t expsign; + int ex, sign; + + u.e = x; + expsign = u.xbits.expsign; + ex = expsign & 0x7fff; + + if (ex >= BIAS + LDBL_MANT_DIG - 1) { + if (ex == BIAS + LDBL_MAX_EXP) + return (x + x); /* Inf, NaN, or unsupported format */ + return (x); /* finite and already an integer */ + } + sign = expsign >> 15; + + /* + * The following code assumes that intermediate results are + * evaluated in long double precision. If they are evaluated in + * greater precision, double rounding may occur, and if they are + * evaluated in less precision (as on i386), results will be + * wildly incorrect. + */ + x += shift[sign]; + x -= shift[sign]; + + /* + * If the result is +-0, then it must have the same sign as x, but + * the above calculation doesn't always give this. Fix up the sign. + */ + if (ex < BIAS && x == 0.0L) + return (zero[sign]); + + return (x); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_round.c b/libm/upstream-freebsd/lib/msun/src/s_round.c new file mode 100644 index 0000000..65de31b --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_round.c @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2003, Steven G. Kargl + * All rights reserved. + * + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <math.h> + +double +round(double x) +{ + double t; + + if (!isfinite(x)) + return (x); + + if (x >= 0.0) { + t = floor(x); + if (t - x <= -0.5) + t += 1.0; + return (t); + } else { + t = floor(-x); + if (t + x <= -0.5) + t += 1.0; + return (-t); + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_roundf.c b/libm/upstream-freebsd/lib/msun/src/s_roundf.c new file mode 100644 index 0000000..952e8e7 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_roundf.c @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2003, Steven G. Kargl + * All rights reserved. + * + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <math.h> + +float +roundf(float x) +{ + float t; + + if (!isfinite(x)) + return (x); + + if (x >= 0.0) { + t = floorf(x); + if (t - x <= -0.5) + t += 1.0; + return (t); + } else { + t = floorf(-x); + if (t + x <= -0.5) + t += 1.0; + return (-t); + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_roundl.c b/libm/upstream-freebsd/lib/msun/src/s_roundl.c new file mode 100644 index 0000000..a70b617 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_roundl.c @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2003, Steven G. Kargl + * All rights reserved. + * + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <math.h> + +long double +roundl(long double x) +{ + long double t; + + if (!isfinite(x)) + return (x); + + if (x >= 0.0) { + t = floorl(x); + if (t - x <= -0.5) + t += 1.0; + return (t); + } else { + t = floorl(-x); + if (t + x <= -0.5) + t += 1.0; + return (-t); + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_scalbln.c b/libm/upstream-freebsd/lib/msun/src/s_scalbln.c new file mode 100644 index 0000000..d609d4e --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_scalbln.c @@ -0,0 +1,76 @@ +/*- + * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <limits.h> +#include <math.h> + +double +scalbln (double x, long n) +{ + int in; + + in = (int)n; + if (in != n) { + if (n > 0) + in = INT_MAX; + else + in = INT_MIN; + } + return (scalbn(x, in)); +} + +float +scalblnf (float x, long n) +{ + int in; + + in = (int)n; + if (in != n) { + if (n > 0) + in = INT_MAX; + else + in = INT_MIN; + } + return (scalbnf(x, in)); +} + +long double +scalblnl (long double x, long n) +{ + int in; + + in = (int)n; + if (in != n) { + if (n > 0) + in = INT_MAX; + else + in = INT_MIN; + } + return (scalbnl(x, (int)n)); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_scalbn.c b/libm/upstream-freebsd/lib/msun/src/s_scalbn.c new file mode 100644 index 0000000..e7efaab --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_scalbn.c @@ -0,0 +1,66 @@ +/* @(#)s_scalbn.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef lint +static char rcsid[] = "$FreeBSD$"; +#endif + +/* + * scalbn (double x, int n) + * scalbn(x,n) returns x* 2**n computed by exponent + * manipulation rather than by actually performing an + * exponentiation or a multiplication. + */ + +#include <sys/cdefs.h> +#include <float.h> + +#include "math.h" +#include "math_private.h" + +static const double +two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */ +twom54 = 5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */ +huge = 1.0e+300, +tiny = 1.0e-300; + +double +scalbn (double x, int n) +{ + int32_t k,hx,lx; + EXTRACT_WORDS(hx,lx,x); + k = (hx&0x7ff00000)>>20; /* extract exponent */ + if (k==0) { /* 0 or subnormal x */ + if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */ + x *= two54; + GET_HIGH_WORD(hx,x); + k = ((hx&0x7ff00000)>>20) - 54; + if (n< -50000) return tiny*x; /*underflow*/ + } + if (k==0x7ff) return x+x; /* NaN or Inf */ + k = k+n; + if (k > 0x7fe) return huge*copysign(huge,x); /* overflow */ + if (k > 0) /* normal result */ + {SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20)); return x;} + if (k <= -54) + if (n > 50000) /* in case integer overflow in n+k */ + return huge*copysign(huge,x); /*overflow*/ + else return tiny*copysign(tiny,x); /*underflow*/ + k += 54; /* subnormal result */ + SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20)); + return x*twom54; +} + +#if (LDBL_MANT_DIG == 53) +__weak_reference(scalbn, ldexpl); +__weak_reference(scalbn, scalbnl); +#endif diff --git a/libm/upstream-freebsd/lib/msun/src/s_scalbnf.c b/libm/upstream-freebsd/lib/msun/src/s_scalbnf.c new file mode 100644 index 0000000..7666c74 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_scalbnf.c @@ -0,0 +1,58 @@ +/* s_scalbnf.c -- float version of s_scalbn.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef lint +static char rcsid[] = "$FreeBSD$"; +#endif + +#include <sys/cdefs.h> + +#include "math.h" +#include "math_private.h" + +static const float +two25 = 3.355443200e+07, /* 0x4c000000 */ +twom25 = 2.9802322388e-08, /* 0x33000000 */ +huge = 1.0e+30, +tiny = 1.0e-30; + +float +scalbnf (float x, int n) +{ + int32_t k,ix; + GET_FLOAT_WORD(ix,x); + k = (ix&0x7f800000)>>23; /* extract exponent */ + if (k==0) { /* 0 or subnormal x */ + if ((ix&0x7fffffff)==0) return x; /* +-0 */ + x *= two25; + GET_FLOAT_WORD(ix,x); + k = ((ix&0x7f800000)>>23) - 25; + if (n< -50000) return tiny*x; /*underflow*/ + } + if (k==0xff) return x+x; /* NaN or Inf */ + k = k+n; + if (k > 0xfe) return huge*copysignf(huge,x); /* overflow */ + if (k > 0) /* normal result */ + {SET_FLOAT_WORD(x,(ix&0x807fffff)|(k<<23)); return x;} + if (k <= -25) + if (n > 50000) /* in case integer overflow in n+k */ + return huge*copysignf(huge,x); /*overflow*/ + else return tiny*copysignf(tiny,x); /*underflow*/ + k += 25; /* subnormal result */ + SET_FLOAT_WORD(x,(ix&0x807fffff)|(k<<23)); + return x*twom25; +} + +__strong_reference(scalbnf, ldexpf); diff --git a/libm/upstream-freebsd/lib/msun/src/s_scalbnl.c b/libm/upstream-freebsd/lib/msun/src/s_scalbnl.c new file mode 100644 index 0000000..fc89f8d --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_scalbnl.c @@ -0,0 +1,71 @@ +/* @(#)s_scalbn.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef lint +static char rcsid[] = "$FreeBSD$"; +#endif + +/* + * scalbnl (long double x, int n) + * scalbnl(x,n) returns x* 2**n computed by exponent + * manipulation rather than by actually performing an + * exponentiation or a multiplication. + */ + +/* + * We assume that a long double has a 15-bit exponent. On systems + * where long double is the same as double, scalbnl() is an alias + * for scalbn(), so we don't use this routine. + */ + +#include <sys/cdefs.h> +#include <float.h> +#include <math.h> + +#include "fpmath.h" + +#if LDBL_MAX_EXP != 0x4000 +#error "Unsupported long double format" +#endif + +static const long double +huge = 0x1p16000L, +tiny = 0x1p-16000L; + +long double +scalbnl (long double x, int n) +{ + union IEEEl2bits u; + int k; + u.e = x; + k = u.bits.exp; /* extract exponent */ + if (k==0) { /* 0 or subnormal x */ + if ((u.bits.manh|u.bits.manl)==0) return x; /* +-0 */ + u.e *= 0x1p+128; + k = u.bits.exp - 128; + if (n< -50000) return tiny*x; /*underflow*/ + } + if (k==0x7fff) return x+x; /* NaN or Inf */ + k = k+n; + if (k >= 0x7fff) return huge*copysignl(huge,x); /* overflow */ + if (k > 0) /* normal result */ + {u.bits.exp = k; return u.e;} + if (k <= -128) + if (n > 50000) /* in case integer overflow in n+k */ + return huge*copysign(huge,x); /*overflow*/ + else return tiny*copysign(tiny,x); /*underflow*/ + k += 128; /* subnormal result */ + u.bits.exp = k; + return u.e*0x1p-128; +} + +__strong_reference(scalbnl, ldexpl); diff --git a/libm/upstream-freebsd/lib/msun/src/s_signbit.c b/libm/upstream-freebsd/lib/msun/src/s_signbit.c new file mode 100644 index 0000000..01eb3ab --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_signbit.c @@ -0,0 +1,58 @@ +/*- + * Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <math.h> + +#include "fpmath.h" + +int +__signbit(double d) +{ + union IEEEd2bits u; + + u.d = d; + return (u.bits.sign); +} + +int +__signbitf(float f) +{ + union IEEEf2bits u; + + u.f = f; + return (u.bits.sign); +} + +int +__signbitl(long double e) +{ + union IEEEl2bits u; + + u.e = e; + return (u.bits.sign); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_signgam.c b/libm/upstream-freebsd/lib/msun/src/s_signgam.c new file mode 100644 index 0000000..d67d591 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_signgam.c @@ -0,0 +1,3 @@ +#include "math.h" +#include "math_private.h" +int signgam = 0; diff --git a/libm/upstream-freebsd/lib/msun/src/s_significand.c b/libm/upstream-freebsd/lib/msun/src/s_significand.c new file mode 100644 index 0000000..356e300 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_significand.c @@ -0,0 +1,29 @@ +/* @(#)s_signif.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * significand(x) computes just + * scalb(x, (double) -ilogb(x)), + * for exercising the fraction-part(F) IEEE 754-1985 test vector. + */ + +#include "math.h" +#include "math_private.h" + +double +significand(double x) +{ + return __ieee754_scalb(x,(double) -ilogb(x)); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_significandf.c b/libm/upstream-freebsd/lib/msun/src/s_significandf.c new file mode 100644 index 0000000..ad030e2 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_significandf.c @@ -0,0 +1,26 @@ +/* s_significandf.c -- float version of s_significand.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +float +significandf(float x) +{ + return __ieee754_scalbf(x,(float) -ilogbf(x)); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_sin.c b/libm/upstream-freebsd/lib/msun/src/s_sin.c new file mode 100644 index 0000000..17ea846 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_sin.c @@ -0,0 +1,89 @@ +/* @(#)s_sin.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* sin(x) + * Return sine function of x. + * + * kernel function: + * __kernel_sin ... sine function on [-pi/4,pi/4] + * __kernel_cos ... cose function on [-pi/4,pi/4] + * __ieee754_rem_pio2 ... argument reduction routine + * + * Method. + * Let S,C and T denote the sin, cos and tan respectively on + * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + * in [-pi/4 , +pi/4], and let n = k mod 4. + * We have + * + * n sin(x) cos(x) tan(x) + * ---------------------------------------------------------- + * 0 S C T + * 1 C -S -1/T + * 2 -S -C T + * 3 -C S -1/T + * ---------------------------------------------------------- + * + * Special cases: + * Let trig be any of sin, cos, or tan. + * trig(+-INF) is NaN, with signals; + * trig(NaN) is that NaN; + * + * Accuracy: + * TRIG(x) returns trig(x) nearly rounded + */ + +#include <float.h> + +#include "math.h" +#define INLINE_REM_PIO2 +#include "math_private.h" +#include "e_rem_pio2.c" + +double +sin(double x) +{ + double y[2],z=0.0; + int32_t n, ix; + + /* High word of x. */ + GET_HIGH_WORD(ix,x); + + /* |x| ~< pi/4 */ + ix &= 0x7fffffff; + if(ix <= 0x3fe921fb) { + if(ix<0x3e500000) /* |x| < 2**-26 */ + {if((int)x==0) return x;} /* generate inexact */ + return __kernel_sin(x,z,0); + } + + /* sin(Inf or NaN) is NaN */ + else if (ix>=0x7ff00000) return x-x; + + /* argument reduction needed */ + else { + n = __ieee754_rem_pio2(x,y); + switch(n&3) { + case 0: return __kernel_sin(y[0],y[1],1); + case 1: return __kernel_cos(y[0],y[1]); + case 2: return -__kernel_sin(y[0],y[1],1); + default: + return -__kernel_cos(y[0],y[1]); + } + } +} + +#if (LDBL_MANT_DIG == 53) +__weak_reference(sin, sinl); +#endif diff --git a/libm/upstream-freebsd/lib/msun/src/s_sinf.c b/libm/upstream-freebsd/lib/msun/src/s_sinf.c new file mode 100644 index 0000000..41b5dc1 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_sinf.c @@ -0,0 +1,85 @@ +/* s_sinf.c -- float version of s_sin.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <float.h> + +#include "math.h" +#define INLINE_KERNEL_COSDF +#define INLINE_KERNEL_SINDF +#define INLINE_REM_PIO2F +#include "math_private.h" +#include "e_rem_pio2f.c" +#include "k_cosf.c" +#include "k_sinf.c" + +/* Small multiples of pi/2 rounded to double precision. */ +static const double +s1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ +s2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ +s3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ +s4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + +float +sinf(float x) +{ + double y; + int32_t n, hx, ix; + + GET_FLOAT_WORD(hx,x); + ix = hx & 0x7fffffff; + + if(ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if(ix<0x39800000) /* |x| < 2**-12 */ + if(((int)x)==0) return x; /* x with inexact if x != 0 */ + return __kernel_sindf(x); + } + if(ix<=0x407b53d1) { /* |x| ~<= 5*pi/4 */ + if(ix<=0x4016cbe3) { /* |x| ~<= 3pi/4 */ + if(hx>0) + return __kernel_cosdf(x - s1pio2); + else + return -__kernel_cosdf(x + s1pio2); + } else + return __kernel_sindf((hx > 0 ? s2pio2 : -s2pio2) - x); + } + if(ix<=0x40e231d5) { /* |x| ~<= 9*pi/4 */ + if(ix<=0x40afeddf) { /* |x| ~<= 7*pi/4 */ + if(hx>0) + return -__kernel_cosdf(x - s3pio2); + else + return __kernel_cosdf(x + s3pio2); + } else + return __kernel_sindf(x + (hx > 0 ? -s4pio2 : s4pio2)); + } + + /* sin(Inf or NaN) is NaN */ + else if (ix>=0x7f800000) return x-x; + + /* general argument reduction needed */ + else { + n = __ieee754_rem_pio2f(x,&y); + switch(n&3) { + case 0: return __kernel_sindf(y); + case 1: return __kernel_cosdf(y); + case 2: return __kernel_sindf(-y); + default: + return -__kernel_cosdf(y); + } + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_sinl.c b/libm/upstream-freebsd/lib/msun/src/s_sinl.c new file mode 100644 index 0000000..f454f8f --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_sinl.c @@ -0,0 +1,93 @@ +/*- + * Copyright (c) 2007 Steven G. Kargl + * All rights reserved. + * + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <float.h> +#ifdef __i386__ +#include <ieeefp.h> +#endif + +#include "math.h" +#include "math_private.h" +#if LDBL_MANT_DIG == 64 +#include "../ld80/e_rem_pio2l.h" +#elif LDBL_MANT_DIG == 113 +#include "../ld128/e_rem_pio2l.h" +#else +#error "Unsupported long double format" +#endif + +long double +sinl(long double x) +{ + union IEEEl2bits z; + int e0, s; + long double y[2]; + long double hi, lo; + + z.e = x; + s = z.bits.sign; + z.bits.sign = 0; + + /* If x = +-0 or x is a subnormal number, then sin(x) = x */ + if (z.bits.exp == 0) + return (x); + + /* If x = NaN or Inf, then sin(x) = NaN. */ + if (z.bits.exp == 32767) + return ((x - x) / (x - x)); + + ENTERI(); + + /* Optimize the case where x is already within range. */ + if (z.e < M_PI_4) { + hi = __kernel_sinl(z.e, 0, 0); + RETURNI(s ? -hi : hi); + } + + e0 = __ieee754_rem_pio2l(x, y); + hi = y[0]; + lo = y[1]; + + switch (e0 & 3) { + case 0: + hi = __kernel_sinl(hi, lo, 1); + break; + case 1: + hi = __kernel_cosl(hi, lo); + break; + case 2: + hi = - __kernel_sinl(hi, lo, 1); + break; + case 3: + hi = - __kernel_cosl(hi, lo); + break; + } + + RETURNI(hi); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_tan.c b/libm/upstream-freebsd/lib/msun/src/s_tan.c new file mode 100644 index 0000000..196c27e --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_tan.c @@ -0,0 +1,83 @@ +/* @(#)s_tan.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* tan(x) + * Return tangent function of x. + * + * kernel function: + * __kernel_tan ... tangent function on [-pi/4,pi/4] + * __ieee754_rem_pio2 ... argument reduction routine + * + * Method. + * Let S,C and T denote the sin, cos and tan respectively on + * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + * in [-pi/4 , +pi/4], and let n = k mod 4. + * We have + * + * n sin(x) cos(x) tan(x) + * ---------------------------------------------------------- + * 0 S C T + * 1 C -S -1/T + * 2 -S -C T + * 3 -C S -1/T + * ---------------------------------------------------------- + * + * Special cases: + * Let trig be any of sin, cos, or tan. + * trig(+-INF) is NaN, with signals; + * trig(NaN) is that NaN; + * + * Accuracy: + * TRIG(x) returns trig(x) nearly rounded + */ + +#include <float.h> + +#include "math.h" +#define INLINE_REM_PIO2 +#include "math_private.h" +#include "e_rem_pio2.c" + +double +tan(double x) +{ + double y[2],z=0.0; + int32_t n, ix; + + /* High word of x. */ + GET_HIGH_WORD(ix,x); + + /* |x| ~< pi/4 */ + ix &= 0x7fffffff; + if(ix <= 0x3fe921fb) { + if(ix<0x3e400000) /* x < 2**-27 */ + if((int)x==0) return x; /* generate inexact */ + return __kernel_tan(x,z,1); + } + + /* tan(Inf or NaN) is NaN */ + else if (ix>=0x7ff00000) return x-x; /* NaN */ + + /* argument reduction needed */ + else { + n = __ieee754_rem_pio2(x,y); + return __kernel_tan(y[0],y[1],1-((n&1)<<1)); /* 1 -- n even + -1 -- n odd */ + } +} + +#if (LDBL_MANT_DIG == 53) +__weak_reference(tan, tanl); +#endif diff --git a/libm/upstream-freebsd/lib/msun/src/s_tanf.c b/libm/upstream-freebsd/lib/msun/src/s_tanf.c new file mode 100644 index 0000000..4fe8c17 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_tanf.c @@ -0,0 +1,72 @@ +/* s_tanf.c -- float version of s_tan.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <float.h> + +#include "math.h" +#define INLINE_KERNEL_TANDF +#define INLINE_REM_PIO2F +#include "math_private.h" +#include "e_rem_pio2f.c" +#include "k_tanf.c" + +/* Small multiples of pi/2 rounded to double precision. */ +static const double +t1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ +t2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ +t3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ +t4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + +float +tanf(float x) +{ + double y; + int32_t n, hx, ix; + + GET_FLOAT_WORD(hx,x); + ix = hx & 0x7fffffff; + + if(ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if(ix<0x39800000) /* |x| < 2**-12 */ + if(((int)x)==0) return x; /* x with inexact if x != 0 */ + return __kernel_tandf(x,1); + } + if(ix<=0x407b53d1) { /* |x| ~<= 5*pi/4 */ + if(ix<=0x4016cbe3) /* |x| ~<= 3pi/4 */ + return __kernel_tandf(x + (hx>0 ? -t1pio2 : t1pio2), -1); + else + return __kernel_tandf(x + (hx>0 ? -t2pio2 : t2pio2), 1); + } + if(ix<=0x40e231d5) { /* |x| ~<= 9*pi/4 */ + if(ix<=0x40afeddf) /* |x| ~<= 7*pi/4 */ + return __kernel_tandf(x + (hx>0 ? -t3pio2 : t3pio2), -1); + else + return __kernel_tandf(x + (hx>0 ? -t4pio2 : t4pio2), 1); + } + + /* tan(Inf or NaN) is NaN */ + else if (ix>=0x7f800000) return x-x; + + /* general argument reduction needed */ + else { + n = __ieee754_rem_pio2f(x,&y); + /* integer parameter: 1 -- n even; -1 -- n odd */ + return __kernel_tandf(y,1-((n&1)<<1)); + } +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_tanh.c b/libm/upstream-freebsd/lib/msun/src/s_tanh.c new file mode 100644 index 0000000..96e3565 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_tanh.c @@ -0,0 +1,77 @@ +/* @(#)s_tanh.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* Tanh(x) + * Return the Hyperbolic Tangent of x + * + * Method : + * x -x + * e - e + * 0. tanh(x) is defined to be ----------- + * x -x + * e + e + * 1. reduce x to non-negative by tanh(-x) = -tanh(x). + * 2. 0 <= x < 2**-28 : tanh(x) := x with inexact if x != 0 + * -t + * 2**-28 <= x < 1 : tanh(x) := -----; t = expm1(-2x) + * t + 2 + * 2 + * 1 <= x < 22 : tanh(x) := 1 - -----; t = expm1(2x) + * t + 2 + * 22 <= x <= INF : tanh(x) := 1. + * + * Special cases: + * tanh(NaN) is NaN; + * only tanh(0)=0 is exact for finite argument. + */ + +#include "math.h" +#include "math_private.h" + +static const double one = 1.0, two = 2.0, tiny = 1.0e-300, huge = 1.0e300; + +double +tanh(double x) +{ + double t,z; + int32_t jx,ix; + + GET_HIGH_WORD(jx,x); + ix = jx&0x7fffffff; + + /* x is INF or NaN */ + if(ix>=0x7ff00000) { + if (jx>=0) return one/x+one; /* tanh(+-inf)=+-1 */ + else return one/x-one; /* tanh(NaN) = NaN */ + } + + /* |x| < 22 */ + if (ix < 0x40360000) { /* |x|<22 */ + if (ix<0x3e300000) { /* |x|<2**-28 */ + if(huge+x>one) return x; /* tanh(tiny) = tiny with inexact */ + } + if (ix>=0x3ff00000) { /* |x|>=1 */ + t = expm1(two*fabs(x)); + z = one - two/(t+two); + } else { + t = expm1(-two*fabs(x)); + z= -t/(t+two); + } + /* |x| >= 22, return +-1 */ + } else { + z = one - tiny; /* raise inexact flag */ + } + return (jx>=0)? z: -z; +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_tanhf.c b/libm/upstream-freebsd/lib/msun/src/s_tanhf.c new file mode 100644 index 0000000..04f09c6 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_tanhf.c @@ -0,0 +1,55 @@ +/* s_tanhf.c -- float version of s_tanh.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +static const float one=1.0, two=2.0, tiny = 1.0e-30, huge = 1.0e30; +float +tanhf(float x) +{ + float t,z; + int32_t jx,ix; + + GET_FLOAT_WORD(jx,x); + ix = jx&0x7fffffff; + + /* x is INF or NaN */ + if(ix>=0x7f800000) { + if (jx>=0) return one/x+one; /* tanh(+-inf)=+-1 */ + else return one/x-one; /* tanh(NaN) = NaN */ + } + + /* |x| < 9 */ + if (ix < 0x41100000) { /* |x|<9 */ + if (ix<0x39800000) { /* |x|<2**-12 */ + if(huge+x>one) return x; /* tanh(tiny) = tiny with inexact */ + } + if (ix>=0x3f800000) { /* |x|>=1 */ + t = expm1f(two*fabsf(x)); + z = one - two/(t+two); + } else { + t = expm1f(-two*fabsf(x)); + z= -t/(t+two); + } + /* |x| >= 9, return +-1 */ + } else { + z = one - tiny; /* raise inexact flag */ + } + return (jx>=0)? z: -z; +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_tanl.c b/libm/upstream-freebsd/lib/msun/src/s_tanl.c new file mode 100644 index 0000000..eadc837 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_tanl.c @@ -0,0 +1,95 @@ +/*- + * Copyright (c) 2007 Steven G. Kargl + * All rights reserved. + * + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +/* + * Limited testing on pseudorandom numbers drawn within [0:4e8] shows + * an accuracy of <= 1.5 ULP where 247024 values of x out of 40 million + * possibles resulted in tan(x) that exceeded 0.5 ULP (ie., 0.6%). + */ + +#include <float.h> +#ifdef __i386__ +#include <ieeefp.h> +#endif + +#include "math.h" +#include "math_private.h" +#if LDBL_MANT_DIG == 64 +#include "../ld80/e_rem_pio2l.h" +#elif LDBL_MANT_DIG == 113 +#include "../ld128/e_rem_pio2l.h" +#else +#error "Unsupported long double format" +#endif + +long double +tanl(long double x) +{ + union IEEEl2bits z; + int e0, s; + long double y[2]; + long double hi, lo; + + z.e = x; + s = z.bits.sign; + z.bits.sign = 0; + + /* If x = +-0 or x is subnormal, then tan(x) = x. */ + if (z.bits.exp == 0) + return (x); + + /* If x = NaN or Inf, then tan(x) = NaN. */ + if (z.bits.exp == 32767) + return ((x - x) / (x - x)); + + ENTERI(); + + /* Optimize the case where x is already within range. */ + if (z.e < M_PI_4) { + hi = __kernel_tanl(z.e, 0, 0); + RETURNI(s ? -hi : hi); + } + + e0 = __ieee754_rem_pio2l(x, y); + hi = y[0]; + lo = y[1]; + + switch (e0 & 3) { + case 0: + case 2: + hi = __kernel_tanl(hi, lo, 0); + break; + case 1: + case 3: + hi = __kernel_tanl(hi, lo, 1); + break; + } + + RETURNI(hi); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_tgammaf.c b/libm/upstream-freebsd/lib/msun/src/s_tgammaf.c new file mode 100644 index 0000000..9993d91 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_tgammaf.c @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2008 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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> +__FBSDID("$FreeBSD$"); + +#include <math.h> + +/* + * We simply call tgamma() rather than bloating the math library with + * a float-optimized version of it. The reason is that tgammaf() is + * essentially useless, since the function is superexponential and + * floats have very limited range. + */ +float +tgammaf(float x) +{ + + return (tgamma(x)); +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_trunc.c b/libm/upstream-freebsd/lib/msun/src/s_trunc.c new file mode 100644 index 0000000..63a6753 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_trunc.c @@ -0,0 +1,67 @@ +/* @(#)s_floor.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * trunc(x) + * Return x rounded toward 0 to integral value + * Method: + * Bit twiddling. + * Exception: + * Inexact flag raised if x not equal to trunc(x). + */ + +#include <float.h> + +#include "math.h" +#include "math_private.h" + +static const double huge = 1.0e300; + +double +trunc(double x) +{ + int32_t i0,i1,j0; + u_int32_t i; + EXTRACT_WORDS(i0,i1,x); + j0 = ((i0>>20)&0x7ff)-0x3ff; + if(j0<20) { + if(j0<0) { /* raise inexact if x != 0 */ + if(huge+x>0.0) {/* |x|<1, so return 0*sign(x) */ + i0 &= 0x80000000U; + i1 = 0; + } + } else { + i = (0x000fffff)>>j0; + if(((i0&i)|i1)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + i0 &= (~i); i1=0; + } + } + } else if (j0>51) { + if(j0==0x400) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } else { + i = ((u_int32_t)(0xffffffff))>>(j0-20); + if((i1&i)==0) return x; /* x is integral */ + if(huge+x>0.0) /* raise inexact flag */ + i1 &= (~i); + } + INSERT_WORDS(x,i0,i1); + return x; +} + +#if LDBL_MANT_DIG == 53 +__weak_reference(trunc, truncl); +#endif diff --git a/libm/upstream-freebsd/lib/msun/src/s_truncf.c b/libm/upstream-freebsd/lib/msun/src/s_truncf.c new file mode 100644 index 0000000..384eaee --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_truncf.c @@ -0,0 +1,53 @@ +/* @(#)s_floor.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * truncf(x) + * Return x rounded toward 0 to integral value + * Method: + * Bit twiddling. + * Exception: + * Inexact flag raised if x not equal to truncf(x). + */ + +#include "math.h" +#include "math_private.h" + +static const float huge = 1.0e30F; + +float +truncf(float x) +{ + int32_t i0,j0; + u_int32_t i; + GET_FLOAT_WORD(i0,x); + j0 = ((i0>>23)&0xff)-0x7f; + if(j0<23) { + if(j0<0) { /* raise inexact if x != 0 */ + if(huge+x>0.0F) /* |x|<1, so return 0*sign(x) */ + i0 &= 0x80000000; + } else { + i = (0x007fffff)>>j0; + if((i0&i)==0) return x; /* x is integral */ + if(huge+x>0.0F) /* raise inexact flag */ + i0 &= (~i); + } + } else { + if(j0==0x80) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } + SET_FLOAT_WORD(x,i0); + return x; +} diff --git a/libm/upstream-freebsd/lib/msun/src/s_truncl.c b/libm/upstream-freebsd/lib/msun/src/s_truncl.c new file mode 100644 index 0000000..9e2b511 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/s_truncl.c @@ -0,0 +1,68 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * From: @(#)s_floor.c 5.1 93/09/24 + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * truncl(x) + * Return x rounded toward 0 to integral value + * Method: + * Bit twiddling. + * Exception: + * Inexact flag raised if x not equal to truncl(x). + */ + +#include <float.h> +#include <math.h> +#include <stdint.h> + +#include "fpmath.h" + +#ifdef LDBL_IMPLICIT_NBIT +#define MANH_SIZE (LDBL_MANH_SIZE + 1) +#else +#define MANH_SIZE LDBL_MANH_SIZE +#endif + +static const long double huge = 1.0e300; +static const float zero[] = { 0.0, -0.0 }; + +long double +truncl(long double x) +{ + union IEEEl2bits u = { .e = x }; + int e = u.bits.exp - LDBL_MAX_EXP + 1; + + if (e < MANH_SIZE - 1) { + if (e < 0) { /* raise inexact if x != 0 */ + if (huge + x > 0.0) + u.e = zero[u.bits.sign]; + } else { + uint64_t m = ((1llu << MANH_SIZE) - 1) >> (e + 1); + if (((u.bits.manh & m) | u.bits.manl) == 0) + return (x); /* x is integral */ + if (huge + x > 0.0) { /* raise inexact flag */ + u.bits.manh &= ~m; + u.bits.manl = 0; + } + } + } else if (e < LDBL_MANT_DIG - 1) { + uint64_t m = (uint64_t)-1 >> (64 - LDBL_MANT_DIG + e + 1); + if ((u.bits.manl & m) == 0) + return (x); /* x is integral */ + if (huge + x > 0.0) /* raise inexact flag */ + u.bits.manl &= ~m; + } + return (u.e); +} diff --git a/libm/upstream-freebsd/lib/msun/src/w_cabs.c b/libm/upstream-freebsd/lib/msun/src/w_cabs.c new file mode 100644 index 0000000..543b858 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/w_cabs.c @@ -0,0 +1,23 @@ +/* + * cabs() wrapper for hypot(). + * + * Written by J.T. Conklin, <jtc@wimsey.com> + * Placed into the Public Domain, 1994. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <complex.h> +#include <float.h> +#include <math.h> + +double +cabs(double complex z) +{ + return hypot(creal(z), cimag(z)); +} + +#if LDBL_MANT_DIG == 53 +__weak_reference(cabs, cabsl); +#endif diff --git a/libm/upstream-freebsd/lib/msun/src/w_cabsf.c b/libm/upstream-freebsd/lib/msun/src/w_cabsf.c new file mode 100644 index 0000000..e7bfe22 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/w_cabsf.c @@ -0,0 +1,23 @@ +/* + * cabsf() wrapper for hypotf(). + * + * Written by J.T. Conklin, <jtc@wimsey.com> + * Placed into the Public Domain, 1994. + */ + +#ifndef lint +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +#include <complex.h> +#include <math.h> +#include "math_private.h" + +float +cabsf(z) + float complex z; +{ + + return hypotf(crealf(z), cimagf(z)); +} diff --git a/libm/upstream-freebsd/lib/msun/src/w_cabsl.c b/libm/upstream-freebsd/lib/msun/src/w_cabsl.c new file mode 100644 index 0000000..b715e0c --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/w_cabsl.c @@ -0,0 +1,20 @@ +/* + * cabs() wrapper for hypot(). + * + * Written by J.T. Conklin, <jtc@wimsey.com> + * Placed into the Public Domain, 1994. + * + * Modified by Steven G. Kargl for the long double type. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <complex.h> +#include <math.h> + +long double +cabsl(long double complex z) +{ + return hypotl(creall(z), cimagl(z)); +} diff --git a/libm/upstream-freebsd/lib/msun/src/w_drem.c b/libm/upstream-freebsd/lib/msun/src/w_drem.c new file mode 100644 index 0000000..0f68409 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/w_drem.c @@ -0,0 +1,15 @@ +/* + * drem() wrapper for remainder(). + * + * Written by J.T. Conklin, <jtc@wimsey.com> + * Placed into the Public Domain, 1994. + */ + +#include <math.h> + +double +drem(x, y) + double x, y; +{ + return remainder(x, y); +} diff --git a/libm/upstream-freebsd/lib/msun/src/w_dremf.c b/libm/upstream-freebsd/lib/msun/src/w_dremf.c new file mode 100644 index 0000000..4bfcff2 --- /dev/null +++ b/libm/upstream-freebsd/lib/msun/src/w_dremf.c @@ -0,0 +1,16 @@ +/* + * dremf() wrapper for remainderf(). + * + * Written by J.T. Conklin, <jtc@wimsey.com> + * Placed into the Public Domain, 1994. + */ +/* $FreeBSD$ */ + +#include "math.h" +#include "math_private.h" + +float +dremf(float x, float y) +{ + return remainderf(x, y); +} |