316 lines
8.5 KiB
C++
316 lines
8.5 KiB
C++
//
|
|
// Copyright (c) 2017 The Khronos Group Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
#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
|
|
{
|
|
// Reference functions for OpenCL comparison functions that
|
|
// are not already defined in STL.
|
|
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);
|
|
}
|
|
|
|
// Reference functions for OpenCL exp functions that
|
|
// are not already defined in STL.
|
|
cl_double exp10(const cl_double& x)
|
|
{
|
|
// 10^x = exp2( x * log2(10) )
|
|
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);
|
|
}
|
|
|
|
// Reference functions for OpenCL floating point functions that
|
|
// are not already defined in STL.
|
|
cl_double2 fract(cl_double x)
|
|
{
|
|
// Copied from math_brute_force/reference_math.c
|
|
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;
|
|
// remquo return the same value that is returned by the
|
|
// remainder function
|
|
r.s[0] = (std::remainder)(x,y);
|
|
// calulcate quo
|
|
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];
|
|
|
|
// fix edge cases
|
|
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;
|
|
}
|
|
|
|
// Reference functions for OpenCL half_math:: functions that
|
|
// are not already defined in STL.
|
|
cl_double divide(cl_double x, cl_double y)
|
|
{
|
|
return x / y;
|
|
}
|
|
|
|
cl_double recip(cl_double x)
|
|
{
|
|
return 1.0 / x;
|
|
}
|
|
|
|
// Reference functions for OpenCL other functions that
|
|
// are not already defined in STL.
|
|
cl_double mad(cl_double x, cl_double y, cl_double z)
|
|
{
|
|
return (x * y) + z;
|
|
}
|
|
|
|
// Reference functions for OpenCL power functions that
|
|
// are not already defined in STL.
|
|
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)
|
|
{
|
|
//powr(x, y) returns NaN for x < 0.
|
|
if( x < 0.0 )
|
|
return std::numeric_limits<cl_double>::quiet_NaN();
|
|
|
|
//powr ( x, NaN ) returns the NaN for x >= 0.
|
|
//powr ( NaN, y ) returns the NaN.
|
|
if((std::isnan)(x) || (std::isnan)(y) )
|
|
return std::numeric_limits<cl_double>::quiet_NaN();
|
|
|
|
if( x == 1.0 )
|
|
{
|
|
//powr ( +1, +-inf ) returns NaN.
|
|
if((std::abs)(y) == INFINITY )
|
|
return std::numeric_limits<cl_double>::quiet_NaN();
|
|
|
|
//powr ( +1, y ) is 1 for finite y. (NaN handled above)
|
|
return 1.0;
|
|
}
|
|
|
|
if( y == 0.0 )
|
|
{
|
|
//powr ( +inf, +-0 ) returns NaN.
|
|
//powr ( +-0, +-0 ) returns NaN.
|
|
if( x == 0.0 || x == std::numeric_limits<cl_double>::infinity())
|
|
return std::numeric_limits<cl_double>::quiet_NaN();
|
|
|
|
//powr ( x, +-0 ) is 1 for finite x > 0. (x <= 0, NaN, INF already handled above)
|
|
return 1.0;
|
|
}
|
|
|
|
if( x == 0.0 )
|
|
{
|
|
//powr ( +-0, -inf) is +inf.
|
|
//powr ( +-0, y ) is +inf for finite y < 0.
|
|
if( y < 0.0 )
|
|
return std::numeric_limits<cl_double>::infinity();
|
|
|
|
//powr ( +-0, y ) is +0 for y > 0. (NaN, y==0 handled above)
|
|
return 0.0;
|
|
}
|
|
|
|
// x = +inf
|
|
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);
|
|
|
|
//y = +-inf cases
|
|
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)
|
|
{
|
|
//rootn (x, 0) returns a NaN.
|
|
if(n == 0)
|
|
return std::numeric_limits<cl_double>::quiet_NaN();
|
|
|
|
//rootn ( x, n ) returns a NaN for x < 0 and n is even.
|
|
if(x < 0 && 0 == (n & 1))
|
|
return std::numeric_limits<cl_double>::quiet_NaN();
|
|
|
|
if(x == 0.0)
|
|
{
|
|
if(n > 0)
|
|
{
|
|
//rootn ( +-0, n ) is +0 for even n > 0.
|
|
if(0 == (n & 1))
|
|
{
|
|
return cl_double(0.0);
|
|
}
|
|
//rootn ( +-0, n ) is +-0 for odd n > 0.
|
|
else
|
|
{
|
|
return x;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//rootn ( +-0, n ) is +inf for even n < 0.
|
|
if(0 == ((-n) & 1))
|
|
{
|
|
return std::numeric_limits<cl_double>::infinity();
|
|
}
|
|
//rootn ( +-0, n ) is +-inf for odd n < 0.
|
|
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);
|
|
}
|
|
|
|
// Reference functions for OpenCL trigonometric functions that
|
|
// are not already defined in STL.
|
|
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)
|
|
// Fix edge cases for Windows
|
|
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 // defined(WIN32) || defined(_WIN32)
|
|
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 // TEST_CONFORMANCE_CLCPP_MATH_FUNCS_REFERENCE_HPP
|