/*- * Copyright (c) 2012 Peter Jeremy * 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. */ /* * This program tests libm exception conditions listed in WG14/N1256 G.6 * against the set of float, double and long double functions this program * is linked against. Note that the libm can be incomplete - this program * uses dlfunc(3) to identify which functions are present. * * It is intended to be portable across operating systems and architectures. * * Command line arguments: * -v Verify that the various unions are the correct size and that the * test table is sane rather than performing the tests. * -r List each function being tested and the arguments being passed. * * Default: Only report missing functions and incorrect results. */ #ifdef __FreeBSD #include __FBSDID("$FreeBSD$"); #endif #include /* for [u]intNN_t */ #include #include #include #include #include #define __USE_GNU /* Linux is broken */ #include #ifndef __FreeBSD #define dlfunc(a,b) dlsym(a,b) #endif /* long doubles differ between architectures so define appropriate structures for each family */ #if defined(__i386__) || defined(__amd64__) /* From FreeBSD: stable/8/lib/libc/amd64/_fpmath.h 175402 2008-01-17 16:39:07Z bde */ #ifdef __amd64__ union IEEEl2bits { long double f; struct Ieeel2bits { uint32_t manl :32; uint32_t manh :32; uint32_t exp :15; uint32_t sign :1; uint32_t junkl :16; uint32_t junkh :32; } bits; struct { uint64_t man :64; uint64_t expsign :16; uint64_t junk :48; } xbits; uint64_t i; }; #else union IEEEl2bits { long double f; struct Ieeel2bits { uint32_t manl :32; uint32_t manh :32; uint32_t exp :15; uint32_t sign :1; uint32_t junkl :16; } bits; struct { uint32_t manl :32; uint32_t manh :32; uint32_t expsign :16; uint32_t junk :16; } xbits; }; #endif /* Unlike all the other formats, the units bit is explicit for x87 */ #define L_ZERO PACK3(0x0000, 0x00000000U, 0x00000000U) #define L_ONE PACK3(0x3fff, 0x80000000U, 0x00000000U) #define L_INF PACK3(0x7fff, 0x80000000U, 0x00000000U) #define L_NAN PACK3(0x7fff, 0xc0000000U, 0x00000000U) #define L_PI_4 PACK3(0x3ffe, 0xc90fdaa2U, 0x2168c235U) #define L_PI_2 PACK3(0x3fff, 0xc90fdaa2U, 0x2168c235U) #define L_3PI_4 PACK3(0x4000, 0x96cbe3f9U, 0x990e91a8U) #define L_PI PACK3(0x4000, 0xc90fdaa2U, 0x2168c235U) /* * On i386, sizeof(long double) is 12 but at least the Atom N270 only * actually writes 10 bytes. Since the result validation is done * using memcmp(), explicitly define the number of bytes to compare. */ #define sizeof_long_double 10 #define INF_EXP 0x7fff #elif defined(__arm__) /* From FreeBSD: stable/8/lib/libc/arm/_fpmath.h 186461 2008-12-23 22:20:59Z marcel */ /* Raspberry Pi is fully little-endian */ union IEEEl2bits { long double f; struct Ieeel2bits { uint32_t manl :32; uint32_t manh :20; uint32_t exp :11; uint32_t sign :1; } bits; struct { uint64_t man :52; uint64_t expsign :12; } xbits; uint64_t i; }; #define L_ZERO D_ZERO #define L_ONE D_ONE #define L_INF D_INF #define L_NAN D_NAN #define L_PI_4 D_PI_4 #define L_PI_2 D_PI_2 #define L_3PI_4 D_3PI_4 #define L_PI D_PI #define sizeof_long_double sizeof(long double) #define INF_EXP 0x7ff #elif defined(__sparc) /* From FreeBSD: stable/8/lib/libc/sparc64/_fpmath.h 175459 2008-01-18 21:25:51Z das */ #define FP_BIG_ENDIAN union IEEEl2bits { long double f; struct Ieeel2bits { uint32_t sign :1; uint32_t exp :15; uint32_t manhh :16; uint32_t manhl :32; uint32_t manlh :32; uint32_t manll :32; } bits; struct { uint64_t expsign :16; uint64_t manh :48; uint64_t manl :64; } xbits; uint64_t i[2]; }; #define L_ZERO { 0, 0x0000, 0x0000, 0x00000000U, 0x00000000U, 0x00000000U } #define L_ONE { 0, 0x3fff, 0x0000, 0x00000000U, 0x00000000U, 0x00000000U } #define L_INF { 0, 0x7fff, 0x0000, 0x00000000U, 0x00000000U, 0x00000000U } #define L_NAN { 0, 0x7fff, 0x8000, 0x00000000U, 0x00000000U, 0x00000000U } #define L_PI_4 { 0, 0x3ffe, 0x921f, 0xb54442d1U, 0x8469898cU, 0xc51701b8U } #define L_PI_2 { 0, 0x3fff, 0x921f, 0xb54442d1U, 0x8469898cU, 0xc51701b8U } #define L_3PI_4 { 0, 0x4000, 0x2d97, 0xc7f3321dU, 0x234f2729U, 0x93d1414aU } #define L_PI { 0, 0x4000, 0x921f, 0xb54442d1U, 0x8469898cU, 0xc51701b8U } #define sizeof_long_double sizeof(long double) #define INF_EXP 0x7fff #endif /* float and double are consistent across all architectures apart from endianness */ union IEEEf2bits { float f; uint32_t i; struct Ieeef2bits { #ifndef FP_BIG_ENDIAN uint32_t man :23; uint32_t exp :8; uint32_t sign :1; #else uint32_t sign :1; uint32_t exp :8; uint32_t man :23; #endif } bits; }; union IEEEd2bits { double f; uint64_t i; struct Ieeed2bits { #ifndef FP_BIG_ENDIAN uint32_t manl :32; uint32_t manh :20; uint32_t exp :11; uint32_t sign :1; #else /* _BIG_ENDIAN */ uint32_t sign :1; uint32_t exp :11; uint32_t manh :20; uint32_t manl :32; #endif } bits; struct { #ifndef FP_BIG_ENDIAN uint64_t man :52; uint64_t expsign :12; #else /* _BIG_ENDIAN */ uint64_t expsign :12; uint64_t man :52; #endif } xbits; }; typedef struct Ieeef2bits fbits; typedef struct Ieeed2bits dbits; typedef struct Ieeel2bits lbits; #ifdef FP_BIG_ENDIAN #define PACK2(exp, man) { 0, exp, man } #define PACK3(exp, manh, manl) { 0, exp, manh, manl } #else #define PACK2(exp, man) { man, exp } #define PACK3(exp, manh, manl) { manl, manh, exp } #endif #define F_ZERO PACK2(0x00, 0x000000) #define F_ONE PACK2(0x7f, 0x000000) #define F_INF PACK2(0xff, 0x000000) #define F_NAN PACK2(0xff, 0x400000) #define F_PI_4 PACK2(0x7e, 0x490fdb) #define F_PI_2 PACK2(0x7f, 0x490fdb) #define F_3PI_4 PACK2(0x80, 0x16cbe4) #define F_PI PACK2(0x80, 0x490fdb) #define D_ZERO PACK3(0x000, 0x00000, 0x00000000U) #define D_ONE PACK3(0x3ff, 0x00000, 0x00000000U) #define D_INF PACK3(0x7ff, 0x00000, 0x00000000U) #define D_NAN PACK3(0x7ff, 0x80000, 0x00000000U) #define D_PI_4 PACK3(0x3fe, 0x921fb, 0x54442d18U) #define D_PI_2 PACK3(0x3ff, 0x921fb, 0x54442d18U) #define D_3PI_4 PACK3(0x400, 0x2d97c, 0x7f3321d2U) #define D_PI PACK3(0x400, 0x921fb, 0x54442d18U) /* * 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; union IEEEf2bits a[2]; } float_complex; typedef union { double complex f; union IEEEd2bits a[2]; } double_complex; typedef union { long double complex f; union IEEEl2bits a[2]; } long_double_complex; #define REALPART(z) ((z).a[0]) #define IMAGPART(z) ((z).a[1]) typedef struct { long_double_complex l; double_complex d; float_complex f; } fpblock; /* * The following is a formal copy of WG14/N1256 G.6. The executable functions are * found via dlfunc() using the name. The arguments and expected result are strings * defining the value(s). These strings optionally begin with '+' or '-', indicating * that the value has that sign, if neither is specified, the value can have either * sign. 'x' and 'y' represent any finite value (including zero if this is not * separately specified). * * The exceptions and special conditions fields are currently ignored. * * The table is terminated by a NULL name. */ const struct test_c_c { const char *tname; const char *tare, *taim; /* arguments */ const char *trre, *trim; /* expected result */ const char *texc; /* exceptions */ const char *spec; /* special conditions */ } test_c_c[] = { { "cacos", "0", "+0", "+π/2", "-0" }, { "cacos", "0", "-0", "+π/2", "+0" }, { "cacos", "0", "NaN", "+π/2", "NaN" }, { "cacos", "+Inf", "+Inf", "+π/4", "-Inf" }, { "cacos", "+Inf", "-Inf", "+π/4", "+Inf" }, { "cacos", "-Inf", "+Inf", "+3π/4", "-Inf" }, { "cacos", "-Inf", "-Inf", "+3π/4", "+Inf" }, { "cacos", "Inf", "NaN", "NaN", "Inf" }, { "cacos", "+Inf", "+y", "+0", "-Inf" }, { "cacos", "+Inf", "-y", "+0", "+Inf" }, { "cacos", "-Inf", "+y", "+π", "-Inf" }, { "cacos", "-Inf", "-y", "+π", "+Inf" }, { "cacos", "NaN", "+Inf", "NaN", "-Inf" }, { "cacos", "NaN", "-Inf", "NaN", "+Inf" }, { "cacos", "NaN", "NaN", "NaN", "NaN" }, { "cacos", "NaN", "y", "NaN", "NaN", "[inv]" }, { "cacos", "x", "+Inf", "+π/2", "-Inf" }, { "cacos", "x", "-Inf", "+π/2", "+Inf" }, { "cacos", "x", "NaN", "NaN", "NaN", "[inv]" }, { "cacosh", "0", "+0", "+0", "+π/2" }, { "cacosh", "0", "-0", "+0", "-π/2" }, { "cacosh", "+Inf", "+Inf", "+Inf", "+π/4" }, { "cacosh", "+Inf", "-Inf", "+Inf", "-π/4" }, { "cacosh", "-Inf", "+Inf", "+Inf", "+3π/4" }, { "cacosh", "-Inf", "-Inf", "+Inf", "-3π/4" }, { "cacosh", "Inf", "NaN", "+Inf", "NaN" }, { "cacosh", "+Inf", "+y", "+Inf", "+0" }, { "cacosh", "+Inf", "-y", "+Inf", "-0" }, { "cacosh", "-Inf", "+y", "+Inf", "+π" }, { "cacosh", "-Inf", "-y", "+Inf", "-π" }, { "cacosh", "NaN", "Inf", "+Inf", "NaN" }, { "cacosh", "NaN", "NaN", "NaN", "NaN" }, { "cacosh", "NaN", "y", "NaN", "NaN", "[inv]" }, { "cacosh", "x", "+Inf", "+Inf", "+π/2" }, { "cacosh", "x", "-Inf", "+Inf", "-π/2" }, { "cacosh", "x", "NaN", "NaN", "NaN", "[inv]" }, { "casin", "-0", "+0", "-0", "+0" }, { "casin", "+0", "+0", "+0", "+0" }, { "casin", "-0", "-0", "-0", "-0" }, { "casin", "+0", "-0", "+0", "-0" }, { "casin", "-Inf", "+Inf", "-π/4", "+Inf" }, { "casin", "+Inf", "+Inf", "+π/4", "+Inf" }, { "casin", "-Inf", "-Inf", "-π/4", "-Inf" }, { "casin", "+Inf", "-Inf", "+π/4", "-Inf" }, { "casin", "NaN", "+Inf", "NaN", "+Inf" }, { "casin", "NaN", "-Inf", "NaN", "-Inf" }, { "casin", "-y", "+Inf", "-0", "+Inf" }, { "casin", "+y", "+Inf", "+0", "+Inf" }, { "casin", "-y", "-Inf", "-0", "-Inf" }, { "casin", "+y", "-Inf", "+0", "-Inf" }, { "casin", "-0", "NaN", "-0", "NaN" }, { "casin", "+0", "NaN", "+0", "NaN" }, { "casin", "Inf", "NaN", "NaN", "Inf" }, { "casin", "NaN", "NaN", "NaN", "NaN" }, { "casin", "y", "NaN", "NaN", "NaN", "[inv]" }, { "casin", "-Inf", "+x", "-π/2", "+Inf" }, { "casin", "+Inf", "+x", "+π/2", "+Inf" }, { "casin", "-Inf", "-x", "-π/2", "-Inf" }, { "casin", "+Inf", "-x", "+π/2", "-Inf" }, { "casin", "NaN", "x", "NaN", "NaN", "[inv]" }, { "casinh", "+0", "+0", "+0", "+0" }, { "casinh", "+0", "-0", "+0", "-0" }, { "casinh", "-0", "+0", "-0", "+0" }, { "casinh", "-0", "-0", "-0", "-0" }, { "casinh", "+Inf", "+Inf", "+Inf", "+π/4" }, { "casinh", "+Inf", "-Inf", "+Inf", "-π/4" }, { "casinh", "-Inf", "+Inf", "-Inf", "+π/4" }, { "casinh", "-Inf", "-Inf", "-Inf", "-π/4" }, { "casinh", "+Inf", "NaN", "+Inf", "NaN" }, { "casinh", "-Inf", "NaN", "-Inf", "NaN" }, { "casinh", "+Inf", "+y", "+Inf", "+0" }, { "casinh", "+Inf", "-y", "+Inf", "-0" }, { "casinh", "-Inf", "+y", "-Inf", "+0" }, { "casinh", "-Inf", "-y", "-Inf", "-0" }, { "casinh", "NaN", "+0", "NaN", "+0" }, { "casinh", "NaN", "-0", "NaN", "-0" }, { "casinh", "NaN", "Inf", "Inf", "NaN" }, { "casinh", "NaN", "NaN", "NaN", "NaN" }, { "casinh", "NaN", "y", "NaN", "NaN", "[inv]" }, { "casinh", "+x", "+Inf", "+Inf", "+π/2" }, { "casinh", "+x", "-Inf", "+Inf", "-π/2" }, { "casinh", "-x", "+Inf", "-Inf", "+π/2" }, { "casinh", "-x", "-Inf", "-Inf", "-π/2" }, { "casinh", "x", "NaN", "NaN", "NaN", "[inv]" }, { "catan", "-0", "+0", "-0", "+0" }, { "catan", "+0", "+0", "+0", "+0" }, { "catan", "-0", "-0", "-0", "-0" }, { "catan", "+0", "-0", "+0", "-0" }, { "catan", "NaN", "+0", "NaN", "+0" }, { "catan", "NaN", "-0", "NaN", "-0" }, { "catan", "-0", "+1", "-0", "+Inf", "{div0}" }, { "catan", "+0", "+1", "+0", "+Inf", "{div0}" }, { "catan", "-0", "-1", "-0", "-Inf", "{div0}" }, { "catan", "+0", "-1", "+0", "-Inf", "{div0}" }, { "catan", "-Inf", "+Inf", "-π/2", "+0" }, { "catan", "+Inf", "+Inf", "+π/2", "+0" }, { "catan", "-Inf", "-Inf", "-π/2", "-0" }, { "catan", "+Inf", "-Inf", "+π/2", "-0" }, { "catan", "NaN", "+Inf", "NaN", "+0" }, { "catan", "NaN", "-Inf", "NaN", "-0" }, { "catan", "-y", "+Inf", "-π/2", "+0" }, { "catan", "+y", "+Inf", "+π/2", "+0" }, { "catan", "-Inf", "NaN", "-π/2", "0" }, { "catan", "+Inf", "NaN", "+π/2", "0" }, { "catan", "NaN", "NaN", "NaN", "NaN" }, { "catan", "y", "NaN", "NaN", "NaN", "[inv]" }, { "catan", "-Inf", "+x", "-π/2", "+0" }, { "catan", "+Inf", "+x", "+π/2", "+0" }, { "catan", "-Inf", "-x", "-π/2", "-0" }, { "catan", "+Inf", "-x", "+π/2", "-0" }, { "catan", "NaN", "x", "NaN", "NaN", "[inv]" }, { "catanh", "+0", "+0", "+0", "+0" }, { "catanh", "+0", "-0", "+0", "-0" }, { "catanh", "-0", "+0", "-0", "+0" }, { "catanh", "-0", "-0", "-0", "-0" }, { "catanh", "+0", "NaN", "+0", "NaN" }, { "catanh", "-0", "NaN", "-0", "NaN" }, { "catanh", "+1", "+0", "+Inf", "+0", "{div0}" }, { "catanh", "+1", "-0", "+Inf", "-0", "{div0}" }, { "catanh", "-1", "+0", "-Inf", "+0", "{div0}" }, { "catanh", "-1", "-0", "-Inf", "-0", "{div0}" }, { "catanh", "+Inf", "+Inf", "+0", "+π/2" }, { "catanh", "+Inf", "-Inf", "+0", "-π/2" }, { "catanh", "-Inf", "+Inf", "-0", "+π/2" }, { "catanh", "-Inf", "-Inf", "-0", "-π/2" }, { "catanh", "+Inf", "NaN", "+0", "NaN" }, { "catanh", "-Inf", "NaN", "-0", "NaN" }, { "catanh", "+Inf", "+y", "+0", "+π/2" }, { "catanh", "+Inf", "-y", "+0", "-π/2" }, { "catanh", "NaN", "+Inf", "0", "+π/2" }, { "catanh", "NaN", "-Inf", "0", "-π/2" }, { "catanh", "NaN", "NaN", "NaN", "NaN" }, { "catanh", "NaN", "y", "NaN", "NaN", "[inv]" }, { "catanh", "+x", "+Inf", "+0", "+π/2" }, { "catanh", "+x", "-Inf", "+0", "-π/2" }, { "catanh", "-x", "+Inf", "-0", "+π/2" }, { "catanh", "-x", "-Inf", "-0", "-π/2" }, { "catanh", "x", "NaN", "NaN", "NaN", "[inv]" }, { "ccos", "-0", "+0", "+1", "+0" }, { "ccos", "+0", "+0", "+1", "-0" }, { "ccos", "-0", "-0", "+1", "-0" }, { "ccos", "+0", "-0", "+1", "+0" }, { "ccos", "Inf", "0", "NaN", "0", "{inv}" }, { "ccos", "NaN", "0", "NaN", "0" }, { "ccos", "-0", "+Inf", "+Inf", "+0" }, { "ccos", "+0", "+Inf", "+Inf", "-0" }, { "ccos", "-0", "-Inf", "+Inf", "-0" }, { "ccos", "+0", "-Inf", "+Inf", "+0" }, { "ccos", "Inf", "Inf", "Inf", "NaN", "{inv}" }, { "ccos", "NaN", "Inf", "+Inf", "NaN" }, { "ccos", "x", "+Inf", "+Inf*cos(x)", "-Inf*sin(x)" }, { "ccos", "x", "-Inf", "+Inf*cos(x)", "+Inf*sin(x)" }, { "ccos", "0", "NaN", "NaN", "0" }, { "ccos", "NaN", "NaN", "NaN", "NaN" }, { "ccos", "y", "NaN", "NaN", "NaN", "[inv]" }, { "ccos", "Inf", "x", "NaN", "NaN", "{inv}" }, { "ccos", "NaN", "x", "NaN", "NaN", "[inv]" }, { "ccosh", "+0", "+0", "+1", "+0" }, { "ccosh", "-0", "+0", "+1", "-0" }, { "ccosh", "+0", "-0", "+1", "-0" }, { "ccosh", "-0", "-0", "+1", "+0" }, { "ccosh", "0", "Inf", "NaN", "0", "{inv}" }, { "ccosh", "0", "NaN", "NaN", "0" }, { "ccosh", "+Inf", "+0", "+Inf", "+0" }, { "ccosh", "+Inf", "-0", "+Inf", "-0" }, { "ccosh", "-Inf", "+0", "+Inf", "-0" }, { "ccosh", "-Inf", "-0", "+Inf", "+0" }, { "ccosh", "Inf", "Inf", "Inf", "NaN", "{inv}" }, { "ccosh", "Inf", "NaN", "+Inf", "NaN" }, { "ccosh", "+Inf", "y", "+Inf*cos(y)", "+Inf*sin(y)" }, { "ccosh", "-Inf", "y", "+Inf*cos(y)", "-Inf*sin(y)" }, { "ccosh", "NaN", "0", "NaN", "0" }, { "ccosh", "NaN", "NaN", "NaN", "NaN" }, { "ccosh", "NaN", "y", "NaN", "NaN", "[inv]" }, { "ccosh", "x", "Inf", "NaN", "NaN", "{inv}" }, { "ccosh", "x", "NaN", "NaN", "NaN", "[inv]" }, { "cexp", "0", "+0", "+1", "+0" }, { "cexp", "0", "-0", "+1", "-0" }, { "cexp", "+Inf", "+0", "+Inf", "+0" }, { "cexp", "+Inf", "-0", "+Inf", "-0" }, { "cexp", "+Inf", "Inf", "Inf", "NaN", "{inv}" }, { "cexp", "-Inf", "Inf", "0", "0" }, { "cexp", "+Inf", "NaN", "Inf", "NaN" }, { "cexp", "-Inf", "NaN", "0", "0" }, { "cexp", "+Inf", "y", "+Inf*cos(y)", "+Inf*sin(y)" }, { "cexp", "-Inf", "y", "+0*cos(y)", "+0*sin(y)" }, { "cexp", "NaN", "+0", "NaN", "+0" }, { "cexp", "NaN", "-0", "NaN", "-0" }, { "cexp", "NaN", "NaN", "NaN", "NaN" }, { "cexp", "NaN", "y", "NaN", "NaN", "[inv]" }, { "cexp", "x", "Inf", "NaN", "NaN", "{inv}" }, { "cexp", "x", "NaN", "NaN", "NaN", "[inv]" }, { "clog", "+0", "+0", "-Inf", "+0", "{div0}" }, { "clog", "+0", "-0", "-Inf", "-0", "{div0}" }, { "clog", "-0", "+0", "-Inf", "+π", "{div0}" }, { "clog", "-0", "-0", "-Inf", "-π", "{div0}" }, { "clog", "+Inf", "+Inf", "+Inf", "+π/4" }, { "clog", "+Inf", "-Inf", "+Inf", "-π/4" }, { "clog", "-Inf", "+Inf", "+Inf", "+3π/4" }, { "clog", "-Inf", "-Inf", "+Inf", "-3π/4" }, { "clog", "Inf", "NaN", "+Inf", "NaN" }, { "clog", "+Inf", "+y", "+Inf", "+0" }, { "clog", "+Inf", "-y", "+Inf", "-0" }, { "clog", "-Inf", "+y", "+Inf", "+π" }, { "clog", "-Inf", "-y", "+Inf", "-π" }, { "clog", "NaN", "Inf", "+Inf", "NaN" }, { "clog", "NaN", "NaN", "NaN", "NaN" }, { "clog", "NaN", "y", "NaN", "NaN", "[inv]" }, { "clog", "x", "+Inf", "+Inf", "+π/2" }, { "clog", "x", "-Inf", "+Inf", "-π/2" }, { "clog", "x", "NaN", "NaN", "NaN", "[inv]" }, { "csin", "-0", "+0", "-0", "+0" }, { "csin", "+0", "+0", "+0", "+0" }, { "csin", "-0", "-0", "-0", "-0" }, { "csin", "+0", "-0", "+0", "-0" }, { "csin", "Inf", "0", "NaN", "0", "{inv}" }, { "csin", "NaN", "0", "NaN", "0" }, { "csin", "-0", "+Inf", "-0", "+Inf" }, { "csin", "+0", "+Inf", "+0", "+Inf" }, { "csin", "-0", "-Inf", "-0", "-Inf" }, { "csin", "+0", "-Inf", "+0", "-Inf" }, { "csin", "Inf", "Inf", "NaN", "Inf", "{inv}" }, { "csin", "NaN", "Inf", "NaN", "Inf" }, { "csin", "x", "+Inf", "+Inf*sin(x)", "+Inf*cos(x)" }, { "csin", "x", "-Inf", "+Inf*sin(x)", "-Inf*cos(x)" }, { "csin", "-0", "NaN", "-0", "NaN" }, { "csin", "+0", "NaN", "+0", "NaN" }, { "csin", "NaN", "NaN", "NaN", "NaN" }, { "csin", "y", "NaN", "NaN", "NaN", "[inv]" }, { "csin", "Inf", "x", "NaN", "NaN", "{inv}" }, { "csin", "NaN", "x", "NaN", "NaN", "[inv]" }, { "csinh", "+0", "+0", "+0", "+0" }, { "csinh", "+0", "-0", "+0", "-0" }, { "csinh", "-0", "+0", "-0", "+0" }, { "csinh", "-0", "-0", "-0", "-0" }, { "csinh", "0", "Inf", "0", "NaN", "{inv}" }, { "csinh", "0", "NaN", "0", "NaN" }, { "csinh", "+Inf", "+0", "+Inf", "+0" }, { "csinh", "+Inf", "-0", "+Inf", "-0" }, { "csinh", "-Inf", "+0", "-Inf", "+0" }, { "csinh", "-Inf", "-0", "-Inf", "-0" }, { "csinh", "Inf", "Inf", "Inf", "NaN", "{inv}" }, { "csinh", "Inf", "NaN", "Inf", "NaN" }, { "csinh", "+Inf", "y", "+Inf*cos(y)", "+Inf*sin(y)" }, { "csinh", "-Inf", "y", "-Inf*cos(y)", "+Inf*sin(y)" }, { "csinh", "NaN", "+0", "NaN", "+0" }, { "csinh", "NaN", "-0", "NaN", "-0" }, { "csinh", "NaN", "NaN", "NaN", "NaN" }, { "csinh", "NaN", "y", "NaN", "NaN", "[inv]" }, { "csinh", "x", "Inf", "NaN", "NaN", "{inv}" }, { "csinh", "x", "NaN", "NaN", "NaN", "[inv]" }, { "csqrt", "0", "+0", "+0", "+0" }, { "csqrt", "0", "-0", "+0", "-0" }, { "csqrt", "+Inf", "NaN", "+Inf", "NaN" }, { "csqrt", "-Inf", "NaN", "NaN", "Inf" }, { "csqrt", "+Inf", "+y", "+Inf", "+0" }, { "csqrt", "+Inf", "-y", "+Inf", "-0" }, { "csqrt", "-Inf", "+y", "+0", "+Inf" }, { "csqrt", "-Inf", "-y", "+0", "-Inf" }, { "csqrt", "NaN", "+Inf", "+Inf", "+Inf" }, { "csqrt", "NaN", "-Inf", "+Inf", "-Inf" }, { "csqrt", "NaN", "NaN", "NaN", "NaN" }, { "csqrt", "NaN", "y", "NaN", "NaN", "[inv]" }, { "csqrt", "x", "+Inf", "+Inf", "+Inf" }, { "csqrt", "x", "-Inf", "+Inf", "-Inf" }, { "csqrt", "x", "NaN", "NaN", "NaN", "[inv]" }, { "ctan", "-0", "+0", "-0", "+0" }, { "ctan", "+0", "+0", "+0", "+0" }, { "ctan", "-0", "-0", "-0", "-0" }, { "ctan", "+0", "-0", "+0", "-0" }, { "ctan", "Inf", "+Inf", "0", "+1" }, { "ctan", "Inf", "-Inf", "0", "-1" }, { "ctan", "NaN", "+Inf", "0", "+1" }, { "ctan", "NaN", "-Inf", "0", "-1" }, { "ctan", "x", "+Inf", "+0*sin(2*x)", "+1" }, { "ctan", "x", "-Inf", "+0*sin(2*x)", "-1" }, { "ctan", "-0", "NaN", "-0", "NaN" }, { "ctan", "+0", "NaN", "+0", "NaN" }, { "ctan", "NaN", "NaN", "NaN", "NaN" }, { "ctan", "y", "NaN", "NaN", "NaN", "[inv]" }, { "ctan", "Inf", "x", "NaN", "NaN", "{inv}" }, { "ctan", "NaN", "x", "NaN", "NaN", "[inv]" }, { "ctanh", "+0", "+0", "+0", "+0" }, { "ctanh", "+0", "-0", "+0", "-0" }, { "ctanh", "-0", "+0", "-0", "+0" }, { "ctanh", "-0", "-0", "-0", "-0" }, { "ctanh", "+Inf", "Inf", "+1", "0" }, { "ctanh", "-Inf", "Inf", "-1", "0" }, { "ctanh", "+Inf", "NaN", "+1", "0" }, { "ctanh", "-Inf", "NaN", "-1", "0" }, { "ctanh", "+Inf", "y", "+1", "+0*sin(2*y)" }, { "ctanh", "-Inf", "y", "-1", "+0*sin(2*y)" }, { "ctanh", "NaN", "+0", "NaN", "+0" }, { "ctanh", "NaN", "-0", "NaN", "-0" }, { "ctanh", "NaN", "NaN", "NaN", "NaN" }, { "ctanh", "NaN", "y", "NaN", "NaN", "[inv]" }, { "ctanh", "x", "Inf", "NaN", "NaN", "{inv}" }, { "ctanh", "x", "NaN", "NaN", "NaN", "[inv]" }, { NULL } }; /* argument/result string */ enum T_VAL { T_ZERO, T_FIN, T_INF, T_NAN, T_ONE, T_PI_4, T_PI_2, T_3PI_4, T_PI, T_COSX, T_COSY, T_SINX, T_SIN2X, T_SINY, T_SIN2Y, T_OINV, T_DIV0, T_INV, T_UNK }; /* Used to control state for iterating argument values */ enum STATE { S_COUNT = 32768, S_SSIN2X, S_SSINX, S_SSIN2Y, S_SSINY, S_SCOSX, S_SCOSY, S_NAN, S_MASK = 0xffff, S_NEG = 0x80000, S_POS = 0x40000, S_MULT = 0x20000 }; /* Map string name to enum and bit pattern of value */ struct t_val { const char *v_name; /* String name */ enum T_VAL v_val; /* Value */ fbits v_fval; /* float constant */ dbits v_dval; /* double constant */ lbits v_lval; /* long double constant */ }; /* Convert the name (without sign) to the constants */ const struct t_val * mapname(const char *in) { static const struct t_val t_map[] = { { "0", T_ZERO, F_ZERO, D_ZERO, L_ZERO }, { "0*cos(y)", T_COSY, F_ZERO, D_ZERO, L_ZERO }, { "0*sin(2*y)", T_SIN2Y,F_ZERO, D_ZERO, L_ZERO }, { "0*sin(y)", T_SINY, F_ZERO, D_ZERO, L_ZERO }, { "0*cos(x)", T_COSX, F_ZERO, D_ZERO, L_ZERO }, { "0*sin(2*x)", T_SIN2X,F_ZERO, D_ZERO, L_ZERO }, { "0*sin(x)", T_SINX, F_ZERO, D_ZERO, L_ZERO }, { "1", T_ONE, F_ONE, D_ONE, L_ONE }, { "3π/4", T_3PI_4,F_3PI_4,D_3PI_4,L_3PI_4 }, { "Inf", T_INF, F_INF, D_INF, L_INF }, { "Inf*cos(y)", T_COSY, F_INF, D_INF, L_INF }, { "Inf*sin(y)", T_SINY, F_INF, D_INF, L_INF }, { "Inf*cos(x)", T_COSX, F_INF, D_INF, L_INF }, { "Inf*sin(x)", T_SINX, F_INF, D_INF, L_INF }, { "NaN", T_NAN, F_NAN, D_NAN, L_NAN }, { "[inv]", T_OINV }, { "x", T_FIN, F_3PI_4,D_3PI_4,L_3PI_4 }, { "y", T_FIN, F_3PI_4,D_3PI_4,L_3PI_4 }, { "{div0}", T_DIV0 }, { "{inv}", T_INV }, { "π", T_PI, F_PI, D_PI, L_PI }, { "π/2", T_PI_2, F_PI_2, D_PI_2, L_PI_2 }, { "π/4", T_PI_4, F_PI_4, D_PI_4, L_PI_4 }, { NULL, T_UNK } }; int i; for (i = 0; t_map[i].v_name != NULL; i++) { if (strcmp(t_map[i].v_name, in) == 0) break; } return (&t_map[i]); } /* * vdecode() and do_validate() form partial sanity checks on the arguments * and results in test_c_c */ int vdecode(const char *name, const char *n, int isarg) { int sign; int val; int res; sign = (*n == '+' || *n == '-') ? *n++ : 0; val = mapname(n)->v_val; if (val > (isarg ? T_NAN : T_SIN2Y)) { printf("%s invalid %s '%s'\n", name, (isarg ? "arg" : "res"), n - !!sign); return (0); } if (!isarg) return (0); res = 0; if (sign != '-') res |= val + 1; if (sign != '+') res |= (val + 5) << 8; return (res); } /* validate test_c_c[] contents */ void do_validate() { const struct test_c_c *ep, *sp; int res1, res2, res3, res4; int64_t mask, val; if (sizeof(float) != sizeof(struct Ieeef2bits) || sizeof(float) != sizeof(union IEEEf2bits) || sizeof(float complex) != sizeof(float_complex)) printf("float: %zu %zu %zu %zu %zu\n", sizeof(float), sizeof(struct Ieeef2bits), sizeof(union IEEEf2bits), sizeof(float complex), sizeof(float_complex)); if (sizeof(double) != sizeof(struct Ieeed2bits) || sizeof(double) != sizeof(union IEEEd2bits) || sizeof(double complex) != sizeof(double_complex)) printf("double: %zu %zu %zu %zu %zu\n", sizeof(double), sizeof(struct Ieeed2bits), sizeof(union IEEEd2bits), sizeof(double complex), sizeof(double_complex)); if (sizeof(long double) != sizeof(struct Ieeel2bits) || sizeof(long double) != sizeof(union IEEEl2bits) || sizeof(long double complex) != sizeof(long_double_complex)) printf("long double: %zu %zu %zu %zu %zu\n", sizeof(long double), sizeof(struct Ieeel2bits), sizeof(union IEEEl2bits), sizeof(long double complex), sizeof(long_double_complex)); for (ep = test_c_c; ep->tname != NULL; ) { mask = 0; for (sp = ep; ep->tname != NULL && !strcmp(ep->tname, sp->tname); ep++) { res1 = vdecode(ep->tname, ep->tare, 1); res3 = res1 >> 8; res1 &= 0xff; res2 = vdecode(ep->tname, ep->taim, 2); res4 = res2 >> 8; res2 &= 0xff; vdecode(ep->tname, ep->trre, 0); vdecode(ep->tname, ep->trim, 0); val = 0; if (res1 > 0) { if (res2 > 0) val |= (int64_t)1 << (res1 + res2 * 8 - 9); if (res4 > 0) val |= (int64_t)1 << (res1 + res4 * 8 - 9); } if (res3 > 0) { if (res2 > 0) val |= (int64_t)1 << (res3 + res2 * 8 - 9); if (res4 > 0) val |= (int64_t)1 << (res3 + res4 * 8 - 9); } if (val & mask) printf("%s duplicate '%s,%s' 0x%016jx 0x%016jx %x %x %x %x\n", ep->tname, ep->tare, ep->taim, (intmax_t)mask, (intmax_t)val, res1, res3, res2, res4); mask |= val; } } } /* * Lookup an argument or result string and initialise the state and value (in fp). * * n is the input string describing the argument or expectud result. * state is used to return state information used to iterate through * arguments or define result information, based on enum STATE * fp is used to return the value associated with the input string. It contains * float, double and long double complex numbers. A single invocation of * decode will initialise either the real or imaginary parts of all 3. * ixexp - zero if the input string is an argument, non-zero for result. * ix is 0 for the real part or 1 for the imaginary part. */ int decode(const char *n, int *state, fpblock *fp, int isexp, int ix) { const struct t_val *val; int sign; sign = (*n == '+' || *n == '-') ? *n++ : 0; val = mapname(n); fp->f.a[ix].bits = val->v_fval; fp->d.a[ix].bits = val->v_dval; fp->l.a[ix].bits = val->v_lval; /* Reject values not allowed as arguments */ if (isexp == 0) { switch (val->v_val) { case T_FIN: *state = S_MULT | S_COUNT | ((sign == '+') ? S_POS : 0) | ((sign == '-') ? S_NEG : 0); if (sign == '-') { fp->f.a[ix].bits.sign = 1; fp->d.a[ix].bits.sign = 1; fp->l.a[ix].bits.sign = 1; } return (0); case T_NAN: *state = S_MASK; /*#### expand to more NaNs later */ return (0); case T_ZERO: case T_INF: case T_ONE: break; default: return (1); } switch (sign) { case '-': fp->f.a[ix].bits.sign = 1; fp->d.a[ix].bits.sign = 1; fp->l.a[ix].bits.sign = 1; /* Fall thru */ case '+': *state = S_MASK; break; default: *state = S_NEG; break; } return (0); } /* Process expected results */ switch (val->v_val) { case T_FIN: case T_ZERO: case T_INF: case T_ONE: case T_3PI_4: case T_PI: case T_PI_2: case T_PI_4: *state = 0; break; case T_NAN: *state = S_NAN; return (0); case T_COSX: *state = S_SCOSX; break; case T_COSY: *state = S_SCOSY; break; case T_SIN2X: *state = S_SSIN2X; break; case T_SINX: *state = S_SSINX; break; case T_SIN2Y: *state = S_SSIN2Y; break; case T_SINY: *state = S_SSINY; break; case T_OINV: case T_DIV0: case T_INV: case T_UNK: default: return (1); } switch (sign) { case '-': fp->f.a[ix].bits.sign = 1; fp->d.a[ix].bits.sign = 1; fp->l.a[ix].bits.sign = 1; break; case '+': break; default: *state |= S_NEG; break; } return (0); } /* * Verify the real or imaginary part (defined by "ix") of a return value * (in "act") matches the expected value (in "exp") for an input value "arg" * in the given state. check() needs to be called twice (with the results of * each or'd together) to check a complex result. "act" is forced positive * so that printing it with %e does not include a sign. The actual sign is * returned as part of the return value. * * Returns a variety of information as a bit pattern: * 00000007 - Value mismatch bits - L/D/F * 00000070 - Sign (0 == -ve) of the real L/D/F actual results * 00000700 - Sign (0 == -ve) of the imaginary L/D/F actual results * 00077000 - Pairs of bits (LLDDFF) indicating sign to be printed for the expected real result * 07700000 - Pairs of bits (LLDDFF) indicating sign to be printed for the expected imaginary result * For the latter two, bitpairs are an index into thu string "??+-" */ int check(const fpblock *arg, int ix, fpblock *act, const fpblock *exx, int state) { int sf, sd, sl; int asign, xsign; asign = (act->f.a[ix].bits.sign << 3) | (act->d.a[ix].bits.sign << 4) | (act->l.a[ix].bits.sign << 5); if (ix) asign <<= 3; /* Special case NaN */ if (state == S_NAN) { return ((isnan(act->f.a[ix].f) ? 0 : 1) | (isnan(act->d.a[ix].f) ? 0 : 2) | (isnan(act->l.a[ix].f) ? 0 : 4) | asign); } switch (state & S_MASK) { default: sf = sd = sl = 0; break; case S_SSIN2X: sf = signbit(sinf(arg->f.a[0].f * 2.0f)); sd = signbit(sin(arg->d.a[0].f * 2.0)); sl = signbit(sinl(arg->l.a[0].f * 2.0l)); break; case S_SSINX: sf = signbit(sinf(arg->f.a[0].f)); sd = signbit(sin(arg->d.a[0].f)); sl = signbit(sinl(arg->l.a[0].f)); break; case S_SSIN2Y: sf = signbit(sinf(arg->f.a[1].f * 2.0f)); sd = signbit(sin(arg->d.a[1].f * 2.0)); sl = signbit(sinl(arg->l.a[1].f * 2.0l)); break; case S_SSINY: sf = signbit(sinf(arg->f.a[1].f)); sd = signbit(sin(arg->d.a[1].f)); sl = signbit(sinl(arg->l.a[1].f)); break; case S_SCOSX: sf = signbit(cosf(arg->f.a[0].f)); sd = signbit(cos(arg->d.a[0].f)); sl = signbit(cosl(arg->l.a[0].f)); break; case S_SCOSY: sf = signbit(cosf(arg->f.a[1].f)); sd = signbit(cos(arg->d.a[1].f)); sl = signbit(cosl(arg->l.a[1].f)); break; } /* Ignore sign bit if we don't care */ if (state & S_NEG) { act->f.a[ix].bits.sign = 0; act->d.a[ix].bits.sign = 0; act->l.a[ix].bits.sign = 0; xsign = 0; } else { /* * s{f,d,l} indicates whether the signbit in the expected value should be * inverted before comparison. To avoid altering it, flip the "actual" * bit instead. The original signs are safely stored in asign. */ if (sf) act->f.a[ix].bits.sign = ~act->f.a[ix].bits.sign; if (sd) act->d.a[ix].bits.sign = ~act->d.a[ix].bits.sign; if (sl) act->l.a[ix].bits.sign = ~act->l.a[ix].bits.sign; /* Calculate the sign to be displayed for the expected result */ xsign = 00052000 | ((!!sf ^ exx->f.a[ix].bits.sign) << 9) | ((!!sd ^ exx->d.a[ix].bits.sign) << 11) | ((!!sl ^ exx->l.a[ix].bits.sign) << 13); if (ix) xsign <<= 6; } /* bitwise compare te distinguish +0 from -0 */ asign |= (memcmp(&act->f.a[ix], &exx->f.a[ix], sizeof(act->f.a[ix])) ? 1 : 0) | (memcmp(&act->d.a[ix], &exx->d.a[ix], sizeof(act->d.a[ix])) ? 2 : 0) | (memcmp(&act->l.a[ix], &exx->l.a[ix], sizeof_long_double) ? 4 : 0); /* Prevent "%e" displaying a sign. */ act->f.a[ix].bits.sign = 0; act->d.a[ix].bits.sign = 0; act->l.a[ix].bits.sign = 0; return (asign | xsign); } /* Iterate state & arg to the next test value. Return 0 if no more */ int nextval(int *state, fpblock *arg, int ix) { if ((*state & S_MASK) == S_MASK) return (0); if (*state == S_NEG) { arg->f.a[ix].bits.sign = 1; arg->d.a[ix].bits.sign = 1; arg->l.a[ix].bits.sign = 1; *state = S_MASK; return (1); } arg->l.a[ix].f = drand48() + scalblnl(drand48(), -40) + scalblnl(drand48(), -80); do { arg->l.a[ix].bits.exp = random() & INF_EXP; } while (arg->l.a[ix].bits.exp >= INF_EXP - 1); #if defined(__i386__) || defined(__amd64__) /* Ensure explicit units bit is correct */ if (arg->l.a[ix].bits.exp == 0) arg->l.a[ix].bits.manh &= 0x7fffffff; else arg->l.a[ix].bits.manh &= 0x80000000; #endif arg->d.a[ix].f = drand48() + scalblnl(drand48(), -32); do { arg->d.a[ix].bits.exp = random() & 0x7ff; } while (arg->d.a[ix].bits.exp >= 0x7fe); arg->f.a[ix].f = drand48(); do { arg->f.a[ix].bits.exp = random() & 0xff; } while (arg->f.a[ix].bits.exp >= 0xfe); if (*state & S_NEG) { arg->f.a[ix].bits.sign = 1; arg->d.a[ix].bits.sign = 1; arg->l.a[ix].bits.sign = 1; } else if (!(*state & S_POS)) { arg->f.a[ix].bits.sign = arg->d.a[ix].bits.sign = arg->l.a[ix].bits.sign = random() & 1; } (*state)--; return (1); } int main(int argc, char **argv) { const struct test_c_c *ep; int state1, state2, state3, state4, err, signr, signi; fpblock arg, act, exx; int report; char buf[16]; const char *prev; float complex (*tfc)(float complex a) = NULL; double complex (*tdc)(double complex a) = NULL; long double complex (*tlc)(long double complex a) = NULL; if (argc > 1 && !strcmp(argv[1], "-v")) { do_validate(); return (0); } report = (argc > 1 && !strcmp(argv[1], "-r")) ? 1 : 0; prev = ""; for (ep = test_c_c; ep->tname != NULL; ep++) { if (strcmp(prev, ep->tname)) { /* Function name has changed. Look up the entry points */ snprintf(buf, sizeof(buf), "%sf", ep->tname); tfc = (float complex (*)(float complex))dlfunc(RTLD_DEFAULT, buf); if (!tfc) printf("%s missing\n", buf); tdc = (double complex (*)(double complex))dlfunc(RTLD_DEFAULT, ep->tname); if (!tdc) printf("%s missing\n", ep->tname); snprintf(buf, sizeof(buf), "%sl", ep->tname); tlc = (long double complex (*)(long double complex))dlfunc(RTLD_DEFAULT, buf); if (!tlc) printf("%s missing\n", buf); prev = ep->tname; } /* Decode arguments & expected results */ if (decode(ep->tare, &state1, &arg, 0, 0) || decode(ep->taim, &state2, &arg, 0, 1) || decode(ep->trre, &state3, &exx, 1, 0) || decode(ep->trim, &state4, &exx, 1, 1)) { printf("%s: failed to parse (%s, %s) => (%s, %s)\n", ep->tname, ep->tare, ep->taim, ep->trre, ep->trim); continue; } do { decode(ep->taim, &state2, &arg, 0, 1); do { if (report) { printf("%6s: %+24.16e 0x%016jx %+24.16e 0x%016jx\n", ep->tname, arg.d.a[0].f, (uintmax_t)arg.d.a[0].i, arg.d.a[1].f, (uintmax_t)arg.d.a[1].i); continue; } /* Actually run the test */ if (tfc) act.f.f = (tfc)(arg.f.f); if (tdc) act.d.f = (tdc)(arg.d.f); if (tlc) act.l.f = (tlc)(arg.l.f); err = check(&arg, 0, &act, &exx, state3) | check(&arg, 1, &act, &exx, state4); if (tfc && (err & 1)) { /* float failed */ signr = exx.f.a[0].bits.sign; signi = exx.f.a[1].bits.sign; exx.f.a[0].bits.sign = 0; exx.f.a[1].bits.sign = 0; //23456789a123456789b123456789c123456789d123456789e123456789f123456789g123456789h123456789i123456789j123456789k123456789l //nnnnf: +n.nnnnnnnE+nn 0xNNNNNNNN +n.nnnnnnnE+nn 0xNNNNNNNN = +n.nnnnnnnE+nn 0xNNNNNNNN +n.nnnnnnnE+nn 0xNNNNNNNN // expected: +n.nnnnnnnE+nn 0xNNNNNNNN +n.nnnnnnnE+nn 0xNNNNNNNN printf("%6sf: %+14.7e 0x%08x %+14.7e 0x%08x = %c%-13.7e 0x%08x %c%-13.7e 0x%08x\n" "%54sexpected: %c%-13.7e 0x%08x %c%-13.7e 0x%08x\n", ep->tname, arg.f.a[0].f, arg.f.a[0].i, arg.f.a[1].f, arg.f.a[1].i, (err & 0010) ? '-' : '+', act.f.a[0].f, act.f.a[0].i, (err & 0100) ? '-' : '+', act.f.a[1].f, act.f.a[1].i, "", "??+-"[(err >> 9) & 3], exx.f.a[0].f, exx.f.a[0].i, "??+-"[(err >> 15) & 3], exx.f.a[1].f, exx.f.a[1].i); exx.f.a[0].bits.sign = signr; exx.f.a[1].bits.sign = signi; } if (tdc && (err & 2)) { /* double failed */ signr = exx.d.a[0].bits.sign; signi = exx.d.a[1].bits.sign; exx.d.a[0].bits.sign = 0; exx.d.a[1].bits.sign = 0; //23456789a123456789b123456789c123456789d123456789e123456789f123456789g123456789h123456789i123456789j123456789k123456789l //nnnnd: +n.nnnnnnnnnnnnnnnnE+nnn +n.nnnnnnnnnnnnnnnnE+nnn = +n.nnnnnnnnnnnnnnnnE+nnn +n.nnnnnnnnnnnnnnnnE+nnn // 0xNNNNNNNNNNNNNNNN 0xNNNNNNNNNNNNNNNN 0xNNNNNNNNNNNNNNNN 0xNNNNNNNNNNNNNNNN // expected: +n.nnnnnnnnnnnnnnnnE+nnn -+n.nnnnnnnnnnnnnnnnE+nnn // 0xNNNNNNNNNNNNNNNN 0xNNNNNNNNNNNNNNNN printf("%6sd: %+-24.16e %+-24.16e = %c%-23.16e %c%-23.16e\n" " 0x%016jx 0x%016jx 0x%016jx 0x%016jx\n" "%52sexpected: %c%-23.16e %c%-23.16e\n%63s0x%016jx 0x%016jx\n", ep->tname, arg.d.a[0].f, arg.d.a[1].f, (err & 0020) ? '-' : '+', act.d.a[0].f, (err & 0200) ? '-' : '+', act.d.a[1].f, (uintmax_t)arg.d.a[0].i, (uintmax_t)arg.d.a[1].i, (uintmax_t)act.d.a[0].i, (uintmax_t)act.d.a[1].i, "", "??+-"[(err >> 11) & 3], exx.d.a[0].f, "??+-"[(err >> 17) & 3], exx.d.a[1].f, "", (uintmax_t)exx.d.a[0].i, (uintmax_t)exx.d.a[1].i); exx.d.a[0].bits.sign = signr; exx.d.a[1].bits.sign = signi; } if (tlc && (err & 4)) { /* long double failed */ signr = exx.l.a[0].bits.sign; signi = exx.l.a[1].bits.sign; exx.l.a[0].bits.sign = 0; exx.l.a[1].bits.sign = 0; #if defined(__i386__) || defined(__amd64__) //23456789a123456789b123456789c123456789d123456789e123456789f123456789g123456789h123456789i123456789j123456789k123456789l //nnnnl: +n.nnnnnnnnnnnnnnnnnnnE+nnnn +n.nnnnnnnnnnnnnnnnnnnE+nnnn = +n.nnnnnnnnnnnnnnnnnnnE+nnnn +n.nnnnnnnnnnnnnnnnnnnE+nnnn // 0xNNNNNNNN NNNNNNNN 0xNNNN 0xNNNNNNNN NNNNNNNN 0xNNNN 0xNNNNNNNN NNNNNNNN 0xNNNN 0xNNNNNNNN NNNNNNNN 0xNNNN // expected: +n.nnnnnnnnnnnnnnnnnnnE+nnnn +n.nnnnnnnnnnnnnnnnnnnE+nnnn // 0xNNNNNNNN NNNNNNNN 0xNNNN 0xNNNNNNNN NNNNNNNN 0xNNNN printf("%6sl: %+-28.19Le %+-28.19Le = %c%-27.19Le %c%-27.19Le\n" " 0x%08x %08x 0x%04x 0x%08x %08x 0x%04x 0x%08x %08x 0x%04x 0x%08x %08x 0x%04x\n" "%60sexpected: %c%-27.19Le %c%-27.19Le\n%72s0x%08x %08x 0x%04x 0x%08x %08x 0x%04x\n", ep->tname, arg.l.a[0].f, arg.l.a[1].f, (err & 0040) ? '-' : '+', act.l.a[0].f, (err & 0400) ? '-' : '+', act.l.a[1].f, arg.l.a[0].bits.manh, arg.l.a[0].bits.manl, (int)arg.l.a[0].xbits.expsign, arg.l.a[1].bits.manh, arg.l.a[1].bits.manl, (int)arg.l.a[1].xbits.expsign, act.l.a[0].bits.manh, act.l.a[0].bits.manl, (int)act.l.a[0].xbits.expsign, act.l.a[1].bits.manh, act.l.a[1].bits.manl, (int)act.l.a[1].xbits.expsign, "", "??+-"[(err >> 13) & 3], exx.l.a[0].f, "??+-"[(err >> 19) & 3], exx.l.a[1].f, "", exx.l.a[0].bits.manh, exx.l.a[0].bits.manl, (int)exx.l.a[0].xbits.expsign, exx.l.a[1].bits.manh, exx.l.a[1].bits.manl, (int)exx.l.a[1].xbits.expsign); #elif defined(__arm__) //23456789a123456789b123456789c123456789d123456789e123456789f123456789g123456789h123456789i123456789j123456789k123456789l //nnnnd: +n.nnnnnnnnnnnnnnnnE+nnn +n.nnnnnnnnnnnnnnnnE+nnn = +n.nnnnnnnnnnnnnnnnE+nnn +n.nnnnnnnnnnnnnnnnE+nnn // 0xNNNNNNNNNNNNNNNN 0xNNNNNNNNNNNNNNNN 0xNNNNNNNNNNNNNNNN 0xNNNNNNNNNNNNNNNN // expected: +n.nnnnnnnnnnnnnnnnE+nnn +n.nnnnnnnnnnnnnnnnE+nnn // 0xNNNNNNNNNNNNNNNN 0xNNNNNNNNNNNNNNNN printf("%6sl: %+-24.16Le %+-24.16Le = %c%-23.16Le %c%-23.16Le\n" " 0x%016jx 0x%016jx 0x%016jx 0x%016jx\n" "%52sexpected: %c%-23.16Le %c%-23.16Le\n%63s0x%016jx 0x%016jx\n", ep->tname, arg.l.a[0].f, arg.l.a[1].f, (err & 0040) ? '-' : '+', act.l.a[0].f, (err & 0400) ? '-' : '+', act.l.a[1].f, (uintmax_t)arg.l.a[0].i, (uintmax_t)arg.l.a[1].i, (uintmax_t)act.l.a[0].i, (uintmax_t)act.l.a[1].i, "", "??+-"[(err >> 13) & 3], exx.l.a[0].f, "??+-"[(err >> 19) & 3], exx.l.a[1].f, "", (uintmax_t)exx.l.a[0].i, (uintmax_t)exx.l.a[1].i); #elif defined(__sparc) //23456789a123456789b123456789c123456789d123456789e123456789f123456789g123456789h123456789i123456789j123456789k123456789l //nnnnl: +n.nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn+nnnn +n.nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn+nnnn // 0xNNNNNNNNNNNNNNNN 0xNNNNNNNNNNNNNNNN 0xNNNNNNNNNNNNNNNN 0xNNNNNNNNNNNNNNNN // = +n.nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn+nnnn +n.nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn+nnnn // 0xNNNNNNNNNNNNNNNN 0xNNNNNNNNNNNNNNNN 0xNNNNNNNNNNNNNNNN 0xNNNNNNNNNNNNNNNN // want +n.nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn+nnnn +n.nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn+nnnn // 0xNNNNNNNNNNNNNNNN 0xNNNNNNNNNNNNNNNN 0xNNNNNNNNNNNNNNNN 0xNNNNNNNNNNNNNNNN printf("%6sl: %+-43.34Le %+-43.34Le\n" " 0x%016jx 0x%016jx 0x%016jx 0x%016jx\n" " = %c%-42.34Le %c%-42.34Le\n" " 0x%016jx 0x%016jx 0x%016jx 0x%016jx\n" " want %c%-42.34Le %c%-42.34Le\n" " 0x%016jx 0x%016jx 0x%016jx 0x%016jx\n", ep->tname, arg.l.a[0].f, arg.l.a[1].f, (uintmax_t)arg.l.a[0].i[0], (uintmax_t)arg.l.a[0].i[1], (uintmax_t)arg.l.a[1].i[0], (uintmax_t)arg.l.a[1].i[1], (err & 0040) ? '-' : '+', act.l.a[0].f, (err & 0400) ? '-' : '+', act.l.a[1].f, (uintmax_t)act.l.a[0].i[0], (uintmax_t)act.l.a[0].i[1], (uintmax_t)act.l.a[1].i[0], (uintmax_t)act.l.a[1].i[1], "??+-"[(err >> 13) & 3], exx.l.a[0].f, "??+-"[(err >> 19) & 3], exx.l.a[1].f, (uintmax_t)exx.l.a[0].i[0], (uintmax_t)exx.l.a[0].i[1], (uintmax_t)exx.l.a[1].i[0], (uintmax_t)exx.l.a[1].i[1]); #endif exx.l.a[0].bits.sign = signr; exx.l.a[1].bits.sign = signi; } } while (nextval(&state2, &arg, 1)); } while (nextval(&state1, &arg, 0)); } return (0); }