From: Daniel Lehman dlehman25@gmail.com
with following changes: /double complex/_Dcomplex/ --- dlls/msvcr120/msvcr120.spec | 2 +- dlls/msvcr120/tests/msvcr120.c | 24 ++++++++ dlls/msvcr120_app/msvcr120_app.spec | 2 +- dlls/ucrtbase/ucrtbase.spec | 2 +- include/msvcrt/complex.h | 5 +- libs/musl/Makefile.in | 4 +- libs/musl/src/complex/__cexp.c | 87 +++++++++++++++++++++++++++ libs/musl/src/complex/cexp.c | 83 +++++++++++++++++++++++++ libs/musl/src/internal/complex_impl.h | 22 +++++++ 9 files changed, 225 insertions(+), 6 deletions(-) create mode 100644 libs/musl/src/complex/__cexp.c create mode 100644 libs/musl/src/complex/cexp.c create mode 100644 libs/musl/src/internal/complex_impl.h
diff --git a/dlls/msvcr120/msvcr120.spec b/dlls/msvcr120/msvcr120.spec index 5c588bd5889..19d396f7d90 100644 --- a/dlls/msvcr120/msvcr120.spec +++ b/dlls/msvcr120/msvcr120.spec @@ -2073,7 +2073,7 @@ @ stub ccosl @ cdecl ceil(double) @ cdecl -arch=!i386 ceilf(float) -@ stub cexp +@ cdecl cexp(int128) @ stub cexpf @ stub cexpl @ cdecl cimag(int128) diff --git a/dlls/msvcr120/tests/msvcr120.c b/dlls/msvcr120/tests/msvcr120.c index 21b1c00b4c3..2db3d4b0d2f 100644 --- a/dlls/msvcr120/tests/msvcr120.c +++ b/dlls/msvcr120/tests/msvcr120.c @@ -233,6 +233,7 @@ static double (__cdecl *p_creal)(_Dcomplex); static float (__cdecl *p_crealf)(_Fcomplex); static double (__cdecl *p_cimag)(_Dcomplex); static float (__cdecl *p_cimagf)(_Fcomplex); +static _Dcomplex (__cdecl *p_cexp)(_Dcomplex); static double (__cdecl *p_nexttoward)(double, double); static float (__cdecl *p_nexttowardf)(float, double); static double (__cdecl *p_nexttowardl)(double, double); @@ -299,6 +300,12 @@ static _Fcomplex __cdecl i386_FCbuild(float r, float i) } #endif
+static inline BOOL almost_equal(double d1, double d2) { + if(d1-d2>-1e-15 && d1-d2<1e-15) + return TRUE; + return FALSE; +} + #define SETNOFAIL(x,y) x = (void*)GetProcAddress(module,y) #define SET(x,y) do { SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y); } while(0)
@@ -357,6 +364,7 @@ static BOOL init(void) SET(p__Cbuild, "_Cbuild"); SET(p_creal, "creal"); SET(p_cimag, "cimag"); + SET(p_cexp, "cexp"); SET(p__FCbuild, "_FCbuild"); SET(p_crealf, "crealf"); SET(p_cimagf, "cimagf"); @@ -1956,6 +1964,21 @@ static void test__fsopen(void) p_setlocale(LC_ALL, "C"); }
+static void test_cexp(void) +{ + _Dcomplex c, r; + + c = p__Cbuild(0.0, M_PI); + r = p_cexp(c); + ok(r.r == -1.0, "r.r = %lf\n", r.r); + ok(almost_equal(r.i, 0.0), "got %e\n", r.i); + + c = p__Cbuild(0.0, INFINITY); + r = p_cexp(c); + ok(isnan(r.r), "r.r = %lf\n", r.r); + ok(isnan(r.i), "r.i = %lf\n", r.i); +} + START_TEST(msvcr120) { if (!init()) return; @@ -1983,4 +2006,5 @@ START_TEST(msvcr120) test_strcmp(); test_gmtime64(); test__fsopen(); + test_cexp(); } diff --git a/dlls/msvcr120_app/msvcr120_app.spec b/dlls/msvcr120_app/msvcr120_app.spec index fc2ac655c40..22d79412696 100644 --- a/dlls/msvcr120_app/msvcr120_app.spec +++ b/dlls/msvcr120_app/msvcr120_app.spec @@ -1740,7 +1740,7 @@ @ stub ccosl @ cdecl ceil(double) msvcr120.ceil @ cdecl -arch=!i386 ceilf(float) msvcr120.ceilf -@ stub cexp +@ cdecl cexp(int128) msvcr120.cexp @ stub cexpf @ stub cexpl @ cdecl cimag(int128) msvcr120.cimag diff --git a/dlls/ucrtbase/ucrtbase.spec b/dlls/ucrtbase/ucrtbase.spec index e03e0b51d60..4d0fb42ad32 100644 --- a/dlls/ucrtbase/ucrtbase.spec +++ b/dlls/ucrtbase/ucrtbase.spec @@ -2218,7 +2218,7 @@ @ stub ccosl @ cdecl ceil(double) @ cdecl -arch=!i386 ceilf(float) -@ stub cexp +@ cdecl cexp(int128) @ stub cexpf @ stub cexpl @ cdecl cimag(int128) diff --git a/include/msvcrt/complex.h b/include/msvcrt/complex.h index 53a72b6a000..f2680a258fa 100644 --- a/include/msvcrt/complex.h +++ b/include/msvcrt/complex.h @@ -24,8 +24,9 @@ typedef struct _C_float_complex typedef _C_double_complex _Dcomplex; typedef _C_float_complex _Fcomplex;
-double __cdecl cimag(_Dcomplex); -double __cdecl creal(_Dcomplex); +_Dcomplex __cdecl cexp(_Dcomplex); +double __cdecl cimag(_Dcomplex); +double __cdecl creal(_Dcomplex);
float __cdecl cimagf(_Fcomplex); float __cdecl crealf(_Fcomplex); diff --git a/libs/musl/Makefile.in b/libs/musl/Makefile.in index bcb14ffef78..2cfe9685334 100644 --- a/libs/musl/Makefile.in +++ b/libs/musl/Makefile.in @@ -1,8 +1,10 @@ EXTLIB = libmusl.a EXTRAINCL = -I$(srcdir)/src/internal -I$(srcdir)/arch/generic -EXTRADEFS = -D_ACRTIMP= -D_NO_CRT_MATH_INLINE +EXTRADEFS = -D_ACRTIMP= -D_NO_CRT_MATH_INLINE -fno-builtin
SOURCES = \ + src/complex/__cexp.c \ + src/complex/cexp.c \ src/math/__cos.c \ src/math/__cosdf.c \ src/math/__expo2.c \ diff --git a/libs/musl/src/complex/__cexp.c b/libs/musl/src/complex/__cexp.c new file mode 100644 index 00000000000..eb9f9a82790 --- /dev/null +++ b/libs/musl/src/complex/__cexp.c @@ -0,0 +1,87 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_exp.c */ +/*- + * 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 "complex_impl.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_cexp(x, expt) compute exp(x) * 2**expt. + * It is 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. + */ +_Dcomplex __ldexp_cexp(_Dcomplex 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 CMPLX(cos(y) * exp_x * scale1 * scale2, sin(y) * exp_x * scale1 * scale2); +} diff --git a/libs/musl/src/complex/cexp.c b/libs/musl/src/complex/cexp.c new file mode 100644 index 00000000000..4c5d8e1b068 --- /dev/null +++ b/libs/musl/src/complex/cexp.c @@ -0,0 +1,83 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cexp.c */ +/*- + * 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 "complex_impl.h" + +static const uint32_t +exp_ovfl = 0x40862e42, /* high bits of MAX_EXP * ln2 ~= 710 */ +cexp_ovfl = 0x4096b8e4; /* (MAX_EXP - MIN_DENORM_EXP) * ln2 */ + +_Dcomplex cexp(_Dcomplex 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 CMPLX(exp(x), y); + EXTRACT_WORDS(hx, lx, x); + /* cexp(0 + I y) = cos(y) + I sin(y) */ + if (((hx & 0x7fffffff) | lx) == 0) + return CMPLX(cos(y), sin(y)); + + if (hy >= 0x7ff00000) { + if (lx != 0 || (hx & 0x7fffffff) != 0x7ff00000) { + /* cexp(finite|NaN +- I Inf|NaN) = NaN + I NaN */ + return CMPLX(y - y, y - y); + } else if (hx & 0x80000000) { + /* cexp(-Inf +- I Inf|NaN) = 0 + I 0 */ + return CMPLX(0.0, 0.0); + } else { + /* cexp(+Inf +- I Inf|NaN) = Inf + I NaN */ + return CMPLX(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 CMPLX(exp_x * cos(y), exp_x * sin(y)); + } +} diff --git a/libs/musl/src/internal/complex_impl.h b/libs/musl/src/internal/complex_impl.h new file mode 100644 index 00000000000..47382c0e73c --- /dev/null +++ b/libs/musl/src/internal/complex_impl.h @@ -0,0 +1,22 @@ +#ifndef _COMPLEX_IMPL_H +#define _COMPLEX_IMPL_H + +#include <complex.h> +#include "libm.h" + +#undef __CMPLX +#undef CMPLX +#undef CMPLXF +#undef CMPLXL + +#define __CMPLX(x, y, t) \ + ((union { t __z; t __xy[2]; }){.__xy = {(x),(y)}}.__z) + +#define CMPLX(x, y) __CMPLX(x, y, _Dcomplex) +#define CMPLXF(x, y) __CMPLX(x, y, _Fcomplex) +#define CMPLXL(x, y) __CMPLX(x, y, long double) + +hidden _Dcomplex __ldexp_cexp(_Dcomplex,int); +hidden _Fcomplex __ldexp_cexpf(_Fcomplex,int); + +#endif