Thanks to visit codestin.com
Credit goes to gist.github.com

Skip to content

Instantly share code, notes, and snippets.

@ewmoore
Last active December 15, 2015 16:19
Show Gist options
  • Select an option

  • Save ewmoore/5288394 to your computer and use it in GitHub Desktop.

Select an option

Save ewmoore/5288394 to your computer and use it in GitHub Desktop.
Sanity Checks for c99 complex math functions.
#include <fenv.h>
#include <float.h>
#include <stdio.h>
#include <math.h>
#include <complex.h>
const double NZERO = 1.0 * 0.0;
#define STRINGIZE_INT(A) #A
#define STRINGIZE(A) STRINGIZE_INT(A)
#define TEST_PRINTF(func, x, e, r) printf("%d: " STRINGIZE(func) "(%g + %gj): expected: %g + %gj: received: %g + %gj\n", __LINE__, creal(x), cimag(x), creal(e), cimag(e), creal(r), cimag(r))
#define TEST(func, x, e) do { \
double complex r = func(x); \
if (!cd_isclose(r, e)) { \
ret = 0; \
TEST_PRINTF(func, x, e, r); \
} \
} \
while(0)
#define TEST_RAISES(func, x, e, fpe) do { \
int except; \
double complex r; \
feclearexcept(FE_ALL_EXCEPT); \
r = func(x); \
except = fetestexcept(fpe); \
if (!(except & fpe && cd_isclose(r, e))) { \
ret = 0; \
TEST_PRINTF(func, x, e, r); \
} \
} \
while(0)
double complex cpack(double r, double i)
{
union {
double complex z;
double a[2];
} z1;
z1.a[0] = r;
z1.a[1] = i;
return z1.z;
}
int isclose(double a, double b)
{
double atol = 0.0;
double rtol = 1e-7;
if (isfinite(a) && isfinite(b)) {
return fabs(a - b) <= (atol + rtol*fabs(b));
}
else if (isinf(a) && isinf(b)) {
return (signbit(a) == signbit(b));
}
else {
return (isnan(a) && isnan(b));
}
}
int cd_isclose(double complex a, double complex b)
{
double ar = creal(a);
double ai = cimag(a);
double br = creal(b);
double bi = cimag(b);
return isclose(ar, br) && isclose(ai, bi);
}
int cd_isnan(double complex x)
{
return isnan(creal(x)) && isnan(cimag(x));
}
int cd_isinf(double complex x)
{
return isinf(creal(x)) && isinf(cimag(x));
}
int check_branch_cut(double complex (*func)(double complex), double complex x0, double complex dx, double re_sign, double im_sign, int sig_zero_ok)
{
double scale = DBL_EPSILON * 1e3;
double atol = 1e-4;
double complex y0 = func(x0);
double complex yp = func(x0 + dx*scale*cabs(x0)/cabs(dx));
double complex ym = func(x0 - dx*scale*cabs(x0)/cabs(dx));
if (fabs(creal(y0) - creal(yp)) >= atol)
return 0;
if (fabs(cimag(y0) - cimag(yp)) >= atol)
return 0;
if (fabs(creal(y0) - re_sign*creal(ym)) >= atol)
return 0;
if (fabs(cimag(y0) - im_sign*cimag(ym)) >= atol)
return 0;
if (sig_zero_ok) { /* check that signed zeros also work as a displacement. */
return 0;
}
return 1;
}
/*
* We assume that if we make it here at all, we have c99 complex support in
* the compiler that we are using.
*
* We define a single test_fname function for each function that will be
* tested. These function return 1 if the tests pass and 0 if the tests
* fail. These are go/no go tests and which test failed is not reported.
*/
/*==========================================================
* clog
*=========================================================*/
#define TEST_CLOG(x, e) TEST(clog, x, e)
#define TEST_RAISES_CLOG(x, e, fpe) TEST_RAISES(clog, x, e, fpe)
int test_clog()
{
int ret = 1;
const double NZERO = -1.0 * 0.0;
/* tests from test_umath.py: TestComplexFunctions: test_it
*/
TEST_CLOG(0.5, log(0.5));
/* tests from test_umath_complex.py: TestCLog: test_simple
*/
TEST_CLOG(1, 0);
TEST_CLOG(1 + 2*I, 0.80471895621705014 + 1.1071487177940904*I);
/* tests from test_umath_complex.py: TestCLog: test_special_values
* These are testing the the value in Appendix G.
*/
TEST_RAISES_CLOG(cpack(NZERO, 0), cpack(-INFINITY, M_PI), FE_DIVBYZERO);
TEST_RAISES_CLOG(cpack(0, 0), cpack(-INFINITY, 0), FE_DIVBYZERO);
TEST_CLOG(cpack(1, INFINITY), cpack(INFINITY, M_PI_2));
TEST_CLOG(cpack(1, NAN), cpack(NAN, NAN)); /* can raise FE_INVALID or not. */
TEST_CLOG(cpack(-INFINITY, 1), cpack(+INFINITY, M_PI));
TEST_CLOG(cpack(+INFINITY, 1), cpack(+INFINITY, 0));
TEST_CLOG(cpack(-INFINITY, +INFINITY), cpack(INFINITY, 0.75 * M_PI));
TEST_CLOG(cpack(+INFINITY, +INFINITY), cpack(INFINITY, 0.25 * M_PI));
TEST_CLOG(cpack(-INFINITY, NAN), cpack(INFINITY, NAN));
TEST_CLOG(cpack(+INFINITY, NAN), cpack(INFINITY, NAN));
TEST_CLOG(cpack(NAN, 1), cpack(NAN, NAN)); /* can raise FE_INVALID or not */
TEST_CLOG(cpack(NAN, INFINITY), cpack(INFINITY, NAN));
TEST_CLOG(cpack(NAN, NAN), cpack(NAN, NAN));
/* clog(conj(z)) = conj(clog(z)) */
/* tests concerning the sign of nan are not included. */
TEST_RAISES_CLOG(cpack(NZERO, NZERO), cpack(-INFINITY, -M_PI), FE_DIVBYZERO);
TEST_RAISES_CLOG(cpack(0, NZERO), cpack(-INFINITY, NZERO), FE_DIVBYZERO);
TEST_CLOG(cpack(1, -INFINITY), cpack(INFINITY, -M_PI_2));
TEST_CLOG(cpack(-INFINITY, -1), cpack(+INFINITY, -M_PI));
TEST_CLOG(cpack(+INFINITY, -1), cpack(+INFINITY, NZERO));
TEST_CLOG(cpack(-INFINITY, -INFINITY), cpack(INFINITY, -0.75 * M_PI));
TEST_CLOG(cpack(+INFINITY, -INFINITY), cpack(INFINITY, -0.25 * M_PI));
TEST_CLOG(cpack(NAN, -INFINITY), cpack(INFINITY, NAN));
if(!check_branch_cut(clog, -0.5, 1*I, 1, -1, 0)) {
ret = 0;
printf("clog branch cut bad!\n");
}
if(!check_branch_cut(clog, -0.5, 1*I, 1, -1, 1)) {
ret = 0;
printf("clog branch cut bad! 2\n");
}
return ret;
}
#undef TEST_CLOG
#undef TEST_RAISES_CLOG
/*==========================================================
* ctanh
*=========================================================*/
#define TEST_CTANH(x, e) TEST(ctanh, x, e)
#define TEST_RAISES_CTANH(x, e, fpe) TEST_RAISES(ctanh, x, e, fpe)
int test_ctanh()
{
int ret = 1;
/**** Test Appendix G special values ****/
TEST_CTANH(cpack(0.0, 0.0), cpack(0.0, 0.0));
TEST_RAISES_CTANH(cpack(1.0, INFINITY), cpack(NAN, NAN), FE_INVALID);
/* can raise FE_INVALID or not */
TEST_CTANH(cpack(1.0, NAN), cpack(NAN, NAN));
/* only for positive, nonzero imag part */
TEST_CTANH(cpack(INFINITY, 1.0), cpack(1.0, 0.0));
/* only for positive nonzero imag part */
TEST_CTANH(cpack(INFINITY, 2.0), cpack(1.0, NZERO));
/* signbit(cimag(r)) is unspecified. */
TEST_CTANH(cpack(INFINITY, INFINITY), cpack(1.0, 0.0));
/* signbit(cimag(r)) is unspecified */
TEST_CTANH(cpack(INFINITY, NAN), cpack(1.0, 0.0));
TEST_CTANH(cpack(NAN, 0.0), cpack(NAN, 0.0));
/* can raise FE_INVALID or not */
TEST_CTANH(cpack(NAN, 1.0), cpack(NAN, NAN));
TEST_CTANH(cpack(NAN, NAN), cpack(NAN, NAN));
/* ctanh(conj(z)) = conj(ctanh(z)) */
TEST_CTANH(cpack(0.0, NZERO), cpack(0.0, NZERO));
TEST_RAISES_CTANH(cpack(1.0, -INFINITY), cpack(NAN, NAN), FE_INVALID);
TEST_CTANH(cpack(NAN, NZERO), cpack(NAN, NZERO));
/* ctanh is odd */
TEST_CTANH(cpack(NZERO, NZERO), cpack(NZERO, NZERO));
TEST_RAISES_CTANH(cpack(-1.0, INFINITY), cpack(NAN, NAN), FE_INVALID);
/* can raise FE_INVALID or not */
TEST_CTANH(cpack(-1.0, NAN), cpack(NAN, NAN));
/* signbit(cimag(r)) is unspecified. */
TEST_CTANH(cpack(-INFINITY, -INFINITY), cpack(-1.0, 0.0));
/* signbit(cimag(r)) is unspecified */
TEST_CTANH(cpack(-INFINITY, NAN), cpack(-1.0, 0.0));
TEST_CTANH(cpack(NAN, NZERO), cpack(NAN, NZERO));
/* can raise FE_INVALID or not */
TEST_CTANH(cpack(NAN, -1.0), cpack(NAN, NAN));
/**** Github Issue 2321: nans for large arguments ****/
TEST_CTANH(cpack(1000.0, 0.0), cpack(1.0, 0.0));
return ret;
}
#undef TEST_CTANH
#undef TEST_RAISES_CTANH
int main(int argc, char** argv)
{
int tclog, tctanh;
tclog = test_clog();
printf("clog: %d\n\n", tclog);
tctanh = test_ctanh();
printf("ctanh: %d\n\n", tctanh);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment