#ifndef TEST_CONFORMANCE_CLCPP_MATH_FUNCS_REFERENCE_HPP
#define TEST_CONFORMANCE_CLCPP_MATH_FUNCS_REFERENCE_HPP
#include <type_traits>
#include <cmath>
#include <limits>
#include "../common.hpp"
namespace reference
{
cl_float maxmag(const cl_float& x, const cl_float& y)
{
if((std::abs)(x) > (std::abs)(y))
{
return x;
}
else if((std::abs)(y) > (std::abs)(x))
{
return y;
}
return (std::fmax)(x, y);
}
cl_float minmag(const cl_float& x, const cl_float& y)
{
if((std::abs)(x) < (std::abs)(y))
{
return x;
}
else if((std::abs)(y) < (std::abs)(x))
{
return y;
}
return (std::fmin)(x, y);
}
cl_double exp10(const cl_double& x)
{
auto log2_10 = (std::log2)(static_cast<long double>(10.0));
cl_double x_log2_10 = static_cast<cl_double>(x * log2_10);
return (std::exp2)(x_log2_10);
}
cl_double2 fract(cl_double x)
{
cl_double2 r;
if((std::isnan)(x))
{
r.s[0] = std::numeric_limits<cl_double>::quiet_NaN();
r.s[1] = std::numeric_limits<cl_double>::quiet_NaN();
return r;
}
r.s[0] = (std::modf)(x, &(r.s[1]));
if(r.s[0] < 0.0 )
{
r.s[0] = 1.0f + r.s[0];
r.s[1] -= 1.0f;
if( r.s[0] == 1.0f )
r.s[0] = HEX_FLT(+, 1, fffffe, -, 1);
}
return r;
}
cl_double2 remquo(cl_double x, cl_double y)
{
cl_double2 r;
r.s[0] = (std::remainder)(x,y);
cl_double x_y = (x - r.s[0]) / y;
cl_uint quo = (std::abs)(x_y);
r.s[1] = quo & 0x0000007fU;
if(x_y < 0.0)
r.s[1] = -r.s[1];
if(!(std::isnan)(x) && y == 0.0)
{
r.s[1] = 0;
}
else if((std::isnan)(x) && (std::isnan)(y))
{
r.s[1] = 0;
}
return r;
}
cl_double divide(cl_double x, cl_double y)
{
return x / y;
}
cl_double recip(cl_double x)
{
return 1.0 / x;
}
cl_double mad(cl_double x, cl_double y, cl_double z)
{
return (x * y) + z;
}
cl_double rsqrt(const cl_double& x)
{
return cl_double(1.0) / ((std::sqrt)(x));
}
cl_double powr(const cl_double& x, const cl_double& y)
{
if( x < 0.0 )
return std::numeric_limits<cl_double>::quiet_NaN();
if((std::isnan)(x) || (std::isnan)(y) )
return std::numeric_limits<cl_double>::quiet_NaN();
if( x == 1.0 )
{
if((std::abs)(y) == INFINITY )
return std::numeric_limits<cl_double>::quiet_NaN();
return 1.0;
}
if( y == 0.0 )
{
if( x == 0.0 || x == std::numeric_limits<cl_double>::infinity())
return std::numeric_limits<cl_double>::quiet_NaN();
return 1.0;
}
if( x == 0.0 )
{
if( y < 0.0 )
return std::numeric_limits<cl_double>::infinity();
return 0.0;
}
if( (std::isinf)(x) )
{
if( y < 0 )
return 0;
return std::numeric_limits<cl_double>::infinity();
}
double fabsx = (std::abs)(x);
double fabsy = (std::abs)(y);
if( (std::isinf)(fabsy) )
{
if( y < 0.0 )
{
if( fabsx < 1.0 )
return std::numeric_limits<cl_double>::infinity();
return 0;
}
if( fabsx < 1.0 )
return 0.0;
return std::numeric_limits<cl_double>::infinity();
}
return (std::pow)(x, y);
}
cl_double rootn(const cl_double& x, const cl_int n)
{
if(n == 0)
return std::numeric_limits<cl_double>::quiet_NaN();
if(x < 0 && 0 == (n & 1))
return std::numeric_limits<cl_double>::quiet_NaN();
if(x == 0.0)
{
if(n > 0)
{
if(0 == (n & 1))
{
return cl_double(0.0);
}
else
{
return x;
}
}
else
{
if(0 == ((-n) & 1))
{
return std::numeric_limits<cl_double>::infinity();
}
else
{
return (std::copysign)(
std::numeric_limits<cl_double>::infinity(), x
);
}
}
}
cl_double r = (std::abs)(x);
r = (std::exp2)((std::log2)(r) / static_cast<cl_double>(n));
return (std::copysign)(r, x);
}
cl_double acospi(cl_double x)
{
return (std::acos)(x) / CL_M_PI;
}
cl_double asinpi(cl_double x)
{
return (std::asin)(x) / CL_M_PI;
}
cl_double atanpi(cl_double x)
{
return (std::atan)(x) / CL_M_PI;
}
cl_double cospi(cl_double x)
{
return (std::cos)(x * CL_M_PI);
}
cl_double sinpi(cl_double x)
{
return (std::sin)(x * CL_M_PI);
}
cl_double tanpi(cl_double x)
{
return (std::tan)(x * CL_M_PI);
}
cl_double atan2(cl_double x, cl_double y)
{
#if defined(WIN32) || defined(_WIN32)
if ((std::isinf)(x) && (std::isinf)(y)) {
cl_double retval = (y > 0) ? CL_M_PI_4 : 3.f * CL_M_PI_4;
return (x > 0) ? retval : -retval;
}
#endif
return (std::atan2)(x, y);
}
cl_double atan2pi(cl_double x, cl_double y)
{
return ::reference::atan2(x, y) / CL_M_PI;
}
cl_double2 sincos(cl_double x)
{
cl_double2 r;
r.s[0] = (std::sin)(x);
r.s[1] = (std::cos)(x);
return r;
}
}
#endif