svn commit: r251835 - user/peterj

Peter Jeremy peterj at FreeBSD.org
Mon Jun 17 08:49:09 UTC 2013


Author: peterj
Date: Mon Jun 17 08:49:08 2013
New Revision: 251835
URL: http://svnweb.freebsd.org/changeset/base/251835

Log:
  Add a libm test tool that I developed as part of the FreeBSD numerics work.
  
  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.

Added:
  user/peterj/
  user/peterj/README
  user/peterj/ctest.c   (contents, props changed)

Added: user/peterj/README
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/peterj/README	Mon Jun 17 08:49:08 2013	(r251835)
@@ -0,0 +1,6 @@
+My odds & ends
+
+ctest.c	 test libm exception conditions listed in WG14/N1256 G.6
+	 against a set of float, double and long double functions
+
+$FreeBSD$

Added: user/peterj/ctest.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/peterj/ctest.c	Mon Jun 17 08:49:08 2013	(r251835)
@@ -0,0 +1,1241 @@
+/*-
+ * Copyright (c) 2012 Peter Jeremy <peterj at 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.
+ */
+
+/*
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#endif
+#include <stdint.h>		/* for [u]intNN_t */
+#include <math.h>
+#include <complex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define __USE_GNU		/* Linux is broken */
+#include <dlfcn.h>
+
+#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;
+	}

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-user mailing list