blob: a22b88fd21dc8f96cd957273dc23197b8eb6ef14 [file] [log] [blame]
//
// 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_UTILS_TEST_COMPARE_HPP
#define TEST_CONFORMANCE_CLCPP_UTILS_TEST_COMPARE_HPP
#include <random>
#include <limits>
#include <type_traits>
#include <algorithm>
#include <cmath>
#include "../common.hpp"
// Checks if x is equal to y.
template<class type, class delta_type, class op_type>
inline bool are_equal(const type& x,
const type& y,
const delta_type& delta,
op_type op,
typename std::enable_if<
is_vector_type<type>::value
&& std::is_integral<typename scalar_type<type>::type>::value
>::type* = 0)
{
(void) delta;
for(size_t i = 0; i < vector_size<type>::value; i++)
{
if(op.is_out_bool())
{
if(!((x.s[i] != 0) == (y.s[i] != 0)))
{
return false;
}
}
else if(!(x.s[i] == y.s[i]))
{
return false;
}
}
return true;
}
template<class type, class delta_type, class op_type>
inline bool are_equal(const type& x,
const type& y,
const delta_type& delta,
op_type op,
typename std::enable_if<
!is_vector_type<type>::value
&& std::is_integral<type>::value
>::type* = 0)
{
(void) delta;
if(op.is_out_bool())
{
if(!((x != 0) == (y != 0)))
{
return false;
}
}
return x == y;
}
template<class type, class type1, class type2, class op_type>
inline bool are_equal(const type& x,
const type1& y,
const type2& delta,
op_type op,
typename std::enable_if<
!is_vector_type<type>::value
&& std::is_floating_point<type>::value
>::type* = 0)
{
// x - expected
// y - result
// INFO:
// Whe don't care about subnormal values in OpenCL C++ tests
if(std::fpclassify(static_cast<type1>(x)) == FP_SUBNORMAL || std::fpclassify(y) == FP_SUBNORMAL)
{
return true;
}
// both are NaN
if((std::isnan)(static_cast<type1>(x)) && (std::isnan)(y))
{
return true;
}
// one is NaN
else if((std::isnan)(static_cast<type1>(x)) || (std::isnan)(y))
{
return false;
}
// Check for perfect match, it also covers inf, -inf
if(static_cast<type1>(x) != y)
{
// Check if values are close
if(std::abs(static_cast<type1>(x) - y) > (std::max)(std::numeric_limits<type2>::epsilon(), std::abs(delta)))
{
return false;
}
// Check ulp
if(op.use_ulp())
{
return !(std::abs(Ulp_Error(x, y)) > op.ulp());
}
}
return true;
}
template<class type, class type1, class type2, class op_type>
inline bool are_equal(const type& x,
const type1& y,
const type2& delta,
op_type op,
typename std::enable_if<
is_vector_type<type>::value
&& std::is_floating_point<typename scalar_type<type>::type>::value
>::type* = 0)
{
// x - expected
// y - result
for(size_t i = 0; i < vector_size<type>::value; i++)
{
if(!are_equal(x.s[i], y.s[i], delta.s[i], op))
{
return false;
}
}
return true;
}
template<class type, class type1, class func>
inline void print_error_msg(const type& expected, const type1& result, size_t i, func op)
{
log_error(
"ERROR: test_%s %s failed. Error at %lu: Expected: %s, got: %s\n",
op.str().c_str(),
op.decl_str().c_str(),
i,
format_value(expected).c_str(),
format_value(result).c_str()
);
}
#endif // TEST_CONFORMANCE_CLCPP_UTILS_TEST_COMPARE_HPP