vtk-m/vtkm/Math.h.in
Kenneth Moreland 5d829f2142 Use std::Min/Max over fmin/fmax
We had a report that vtkm::Min/Max was significantly slower than other
products. This was traced back to the fact that these functions were not
completely inlining because they were calling fmin or fmax, and that
resulted in an actual C library call. It turns out using the templated
functions in the std namespace is faster.

This change has the VTK-m min/max functions use the std version in
almost all circumstances. The one exception (so far) is that fmin and
fmax are used for CUDA devices since the std functions are not declared
to run on the device and the nvcc compiler treats these functions
special.
2015-12-07 09:26:27 -07:00

952 lines
25 KiB
C

//=============================================================================
//
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//
//=============================================================================
$# This file uses the pyexpander macro processing utility to build the
$# FunctionInterface facilities that use a variable number of arguments.
$# Information, documentation, and downloads for pyexpander can be found at:
$#
$# http://pyexpander.sourceforge.net/
$#
$# To build the source code, execute the following (after installing
$# pyexpander, of course):
$#
$# expander.py Math.h.in > Math.h
$#
$# Ignore the following comment. It is meant for the generated file.
// **** DO NOT EDIT THIS FILE!!! ****
// This file is automatically generated by FunctionInterfaceDetailPre.h.in
#ifndef vtk_m_Math_h
#define vtk_m_Math_h
#include <vtkm/Types.h>
#include <vtkm/TypeTraits.h>
#include <vtkm/VecTraits.h>
#ifndef VTKM_CUDA
#include <limits.h>
#include <math.h>
#include <stdlib.h>
// The nonfinite and sign test functions are usually defined as macros, and
// boost seems to want to undefine those macros so that it can implement the
// C99 templates and other implementations of the same name. Get around the
// problem by using the boost version when compiling for a CPU.
VTKM_THIRDPARTY_PRE_INCLUDE
#include <boost/math/special_functions/fpclassify.hpp>
#include <boost/math/special_functions/sign.hpp>
VTKM_THIRDPARTY_POST_INCLUDE
#include <cmath>
#define VTKM_USE_BOOST_CLASSIFY
#define VTKM_USE_BOOST_SIGN
#endif // !VTKM_CUDA
#if !defined(__CUDA_ARCH__)
#define VTKM_USE_STL_MIN_MAX
#include <algorithm>
#endif
#if defined(VTKM_MSVC) && !defined(VTKM_CUDA)
VTKM_THIRDPARTY_PRE_INCLUDE
#include <boost/math/special_functions/acosh.hpp>
#include <boost/math/special_functions/asinh.hpp>
#include <boost/math/special_functions/atanh.hpp>
#include <boost/math/special_functions/cbrt.hpp>
#include <boost/math/special_functions/expm1.hpp>
#include <boost/math/special_functions/log1p.hpp>
#include <boost/math/special_functions/round.hpp>
VTKM_THIRDPARTY_POST_INCLUDE
#define VTKM_USE_BOOST_MATH
#if (_MSC_VER <= 1600) && !defined(VTKM_USE_STL_MIN_MAX)
#define VTKM_USE_STL_MIN_MAX
#include <algorithm>
#endif
#endif
#define VTKM_SYS_MATH_FUNCTION_32(func) func ## f
#define VTKM_SYS_MATH_FUNCTION_64(func) func
$py(
def unary_function(name, type, returntype, expression):
return '''VTKM_EXEC_CONT_EXPORT
{2} {0}({1} x) {{
return {3};
}}
'''.format(name, type, returntype, expression)
def unary_Vec_function(vtkmname):
return '''template<typename T, vtkm::IdComponent N>
VTKM_EXEC_CONT_EXPORT
vtkm::Vec<T,N> {0}(const vtkm::Vec<T,N> &x) {{
vtkm::Vec<T,N> result;
for (vtkm::IdComponent index = 0; index < N; index++)
{{
result[index] = vtkm::{0}(x[index]);
}}
return result;
}}
template<typename T>
VTKM_EXEC_CONT_EXPORT
vtkm::Vec<T,4> {0}(const vtkm::Vec<T,4> &x) {{
return vtkm::Vec<T,4>(vtkm::{0}(x[0]),
vtkm::{0}(x[1]),
vtkm::{0}(x[2]),
vtkm::{0}(x[3]));
}}
template<typename T>
VTKM_EXEC_CONT_EXPORT
vtkm::Vec<T,3> {0}(const vtkm::Vec<T,3> &x) {{
return vtkm::Vec<T,3>(vtkm::{0}(x[0]),
vtkm::{0}(x[1]),
vtkm::{0}(x[2]));
}}
template<typename T>
VTKM_EXEC_CONT_EXPORT
vtkm::Vec<T,2> {0}(const vtkm::Vec<T,2> &x) {{
return vtkm::Vec<T,2>(vtkm::{0}(x[0]),
vtkm::{0}(x[1]));
}}
'''.format(vtkmname)
def unary_math_function_no_vec(vtkmname, sysname, returntype = None):
return unary_function(vtkmname,
'vtkm::Float32',
'vtkm::Float32' if returntype == None else returntype,
'VTKM_SYS_MATH_FUNCTION_32(' + sysname + ')(x)') + \
unary_function(vtkmname,
'vtkm::Float64',
'vtkm::Float64' if returntype == None else returntype,
'VTKM_SYS_MATH_FUNCTION_64(' + sysname + ')(x)')
def unary_math_function(vtkmname, sysname):
return unary_math_function_no_vec(vtkmname, sysname) + \
unary_Vec_function(vtkmname)
def unary_template_function_no_vec(vtkmname,
expression,
returntype = None,
preexpression = ''):
return '''VTKM_EXEC_CONT_EXPORT
{2} {0}(vtkm::Float32 x) {{
{3} return {1};
}}
'''.format(vtkmname,
expression,
'vtkm::Float32' if returntype == None else returntype,
preexpression) + \
'''VTKM_EXEC_CONT_EXPORT
{2} {0}(vtkm::Float64 x) {{
{3} return {1};
}}
'''.format(vtkmname,
expression,
'vtkm::Float64' if returntype == None else returntype,
preexpression)
def binary_function(name, type, expression):
return '''VTKM_EXEC_CONT_EXPORT
{1} {0}({1} x, {1} y) {{
return {2};
}}
'''.format(name, type, expression)
def binary_math_function(vtkmname, sysname):
return binary_function(vtkmname,
'vtkm::Float32',
'VTKM_SYS_MATH_FUNCTION_32(' + sysname + ')(x,y)') + \
binary_function(vtkmname,
'vtkm::Float64',
'VTKM_SYS_MATH_FUNCTION_64(' + sysname + ')(x,y)')
def binary_template_function(vtkmname, expression):
return '''VTKM_EXEC_CONT_EXPORT
vtkm::Float32 {0}(vtkm::Float32 x, vtkm::Float32 y) {{
return {1};
}}
VTKM_EXEC_CONT_EXPORT
vtkm::Float64 {0}(vtkm::Float64 x, vtkm::Float64 y) {{
return {1};
}}
'''.format(vtkmname, expression)
)
$extend(unary_math_function)
$extend(unary_math_function_no_vec)
$extend(unary_Vec_function)
$extend(unary_template_function_no_vec)
$extend(binary_math_function)
$extend(binary_template_function)
namespace vtkm {
//-----------------------------------------------------------------------------
/// Returns the constant 2 times Pi.
///
VTKM_EXEC_CONT_EXPORT
vtkm::Float64 TwoPi()
{
return 6.28318530717958647692528676655900576;
}
/// Returns the constant Pi.
///
VTKM_EXEC_CONT_EXPORT
vtkm::Float64 Pi()
{
return 3.14159265358979323846264338327950288;
}
/// Returns the constant Pi halves.
///
VTKM_EXEC_CONT_EXPORT
vtkm::Float64 Pi_2()
{
return 1.57079632679489661923132169163975144;
}
/// Returns the constant Pi thirds.
///
VTKM_EXEC_CONT_EXPORT
vtkm::Float64 Pi_3()
{
return 1.04719755119659774615421446109316762;
}
/// Returns the constant Pi fourths.
///
VTKM_EXEC_CONT_EXPORT
vtkm::Float64 Pi_4()
{
return 0.78539816339744830961566084581987572;
}
/// Compute the sine of \p x.
///
$unary_math_function('Sin', 'sin')\
/// Compute the cosine of \p x.
///
$unary_math_function('Cos', 'cos')\
/// Compute the tangent of \p x.
///
$unary_math_function('Tan', 'tan')\
/// Compute the arc sine of \p x.
///
$unary_math_function('ASin', 'asin')\
/// Compute the arc cosine of \p x.
///
$unary_math_function('ACos', 'acos')\
/// Compute the arc tangent of \p x.
///
$unary_math_function('ATan', 'atan')\
/// Compute the arc tangent of \p x / \p y using the signs of both arguments
/// to determine the quadrant of the return value.
///
$binary_math_function('ATan2', 'atan2')\
/// Compute the hyperbolic sine of \p x.
///
$unary_math_function('SinH', 'sinh')\
/// Compute the hyperbolic cosine of \p x.
///
$unary_math_function('CosH', 'cosh')\
/// Compute the hyperbolic tangent of \p x.
///
$unary_math_function('TanH', 'tanh')\
/// Compute the hyperbolic arc sine of \p x.
///
#ifdef VTKM_USE_BOOST_MATH
$unary_template_function_no_vec('ASinH', 'boost::math::asinh(x)')\
$#
#else // !VTKM_USE_BOOST_MATH
$unary_math_function_no_vec('ASinH', 'asinh')\
$#
#endif // !VTKM_USE_BOOST_MATH
$unary_Vec_function('ASinH')\
/// Compute the hyperbolic arc cosine of \p x.
///
#ifdef VTKM_USE_BOOST_MATH
$unary_template_function_no_vec('ACosH', 'boost::math::acosh(x)')\
$#
#else // !VTKM_USE_BOOST_MATH
$unary_math_function_no_vec('ACosH', 'acosh')\
$#
#endif // !VTKM_USE_BOOST_MATH
$unary_Vec_function('ACosH')\
/// Compute the hyperbolic arc tangent of \p x.
///
#ifdef VTKM_USE_BOOST_MATH
$unary_template_function_no_vec('ATanH', 'boost::math::atanh(x)')\
$#
#else // !VTKM_USE_BOOST_MATH
$unary_math_function_no_vec('ATanH', 'atanh')\
$#
#endif // !VTKM_USE_BOOST_MATH
$unary_Vec_function('ATanH')\
//-----------------------------------------------------------------------------
/// Computes \p x raised to the power of \p y.
///
$binary_math_function('Pow', 'pow')\
/// Compute the square root of \p x.
///
$unary_math_function('Sqrt', 'sqrt')\
/// Compute the reciprocal square root of \p x. The result of this function is
/// equivalent to <tt>1/Sqrt(x)</tt>. However, on some devices it is faster to
/// compute the reciprocal square root than the regular square root. Thus, you
/// should use this function whenever dividing by the square root.
///
#ifdef VTKM_CUDA
$unary_math_function_no_vec('RSqrt', 'rsqrt')\
$#
#else // !VTKM_CUDA
$unary_template_function_no_vec('RSqrt', '1/vtkm::Sqrt(x)')\
$#
#endif // !VTKM_CUDA
$unary_Vec_function('RSqrt')\
/// Compute the cube root of \p x.
///
#ifdef VTKM_USE_BOOST_MATH
$unary_template_function_no_vec('Cbrt', 'boost::math::cbrt(x)')\
$#
#else // !VTKM_USE_BOOST_MATH
$unary_math_function_no_vec('Cbrt', 'cbrt')\
$#
#endif // !VTKM_USE_BOOST_MATH
$unary_Vec_function('Cbrt')\
/// Compute the reciprocal cube root of \p x. The result of this function is
/// equivalent to <tt>1/Cbrt(x)</tt>. However, on some devices it is faster to
/// compute the reciprocal cube root than the regular cube root. Thus, you
/// should use this function whenever dividing by the cube root.
///
#ifdef VTKM_CUDA
$unary_math_function_no_vec('RCbrt', 'rcbrt')\
$#
#else // !VTKM_CUDA
$unary_template_function_no_vec('RCbrt', '1/vtkm::Cbrt(x)')\
$#
#endif // !VTKM_CUDA
$unary_Vec_function('RCbrt')\
/// Computes e**\p x, the base-e exponential of \p x.
///
$unary_math_function('Exp', 'exp')\
/// Computes 2**\p x, the base-2 exponential of \p x.
///
#ifdef VTKM_MSVC
$unary_template_function_no_vec('Exp2', 'vtkm::Pow(2,x)')\
$#
#else // !VTKM_USE_BOOST_MATH
$unary_math_function_no_vec('Exp2', 'exp2')\
$#
#endif // !VTKM_USE_BOOST_MATH
$unary_Vec_function('Exp2')\
/// Computes (e**\p x) - 1, the of base-e exponental of \p x then minus 1. The
/// accuracy of this function is good even for very small values of x.
///
#ifdef VTKM_USE_BOOST_MATH
$unary_template_function_no_vec('ExpM1', 'boost::math::expm1(x)')\
$#
#else // !VTKM_USE_BOOST_MATH
$unary_math_function_no_vec('ExpM1', 'expm1')\
$#
#endif // !VTKM_USE_BOOST_MATH
$unary_Vec_function('ExpM1')\
/// Computes 10**\p x, the base-10 exponential of \p x.
///
#ifdef VTKM_CUDA
$unary_math_function_no_vec('Exp10', 'exp10')\
$#
#else // !VTKM_CUDA
$unary_template_function_no_vec('Exp10', 'vtkm::Pow(10, x);')\
$#
#endif // !VTKM_CUDA
$unary_Vec_function('Exp10')\
/// Computes the natural logarithm of \p x.
///
$unary_math_function('Log', 'log')\
/// Computes the logarithm base 2 of \p x.
///
#ifdef VTKM_MSVC
VTKM_EXEC_CONT_EXPORT
vtkm::Float32 Log2(vtkm::Float32 x) {
//windows and boost don't provide log2
//0.6931471805599453 is the constant value of log(2)
const vtkm::Float32 log2v = 0.6931471805599453f;
return vtkm::Log(x)/log2v;
}
VTKM_EXEC_CONT_EXPORT
vtkm::Float64 Log2(vtkm::Float64 x) {
//windows and boost don't provide log2
//0.6931471805599453 is the constant value of log(2)
const vtkm::Float64 log2v = 0.6931471805599453;
return vtkm::Log(x)/log2v;
}
#else // !VTKM_USE_BOOST_MATH
$unary_math_function_no_vec('Log2', 'log2')\
$#
#endif // !VTKM_USE_BOOST_MATH
$unary_Vec_function('Log2')\
/// Computes the logarithm base 10 of \p x.
///
$unary_math_function('Log10', 'log10')\
/// Computes the value of log(1+x) accurately for very small values of x.
///
#ifdef VTKM_USE_BOOST_MATH
$unary_template_function_no_vec('Log1P', 'boost::math::log1p(x)')\
$#
#else // !VTKM_USE_BOOST_MATH
$unary_math_function_no_vec('Log1P', 'log1p')\
$#
#endif // !VTKM_USE_BOOST_MATH
$unary_Vec_function('Log1P')\
//-----------------------------------------------------------------------------
/// Returns \p x or \p y, whichever is larger.
///
template<typename T>
VTKM_EXEC_CONT_EXPORT
T Max(const T &x, const T &y);
#ifdef VTKM_USE_STL_MIN_MAX
$binary_template_function('Max', '(std::max)(x, y)')\
$#
#else // !VTKM_USE_STL_MIN_MAX
$binary_math_function('Max', 'fmax')\
$#
#endif // !VTKM_USE_STL_MIN_MAX
/// Returns \p x or \p y, whichever is smaller.
///
template<typename T>
VTKM_EXEC_CONT_EXPORT
T Min(const T &x, const T &y);
#ifdef VTKM_USE_STL_MIN_MAX
$binary_template_function('Min', '(std::min)(x, y)')\
$#
#else // !VTKM_USE_STL_MIN_MAX
$binary_math_function('Min', 'fmin')\
$#
#endif // !VTKM_USE_STL_MIN_MAX
namespace detail {
template<typename T>
VTKM_EXEC_CONT_EXPORT
T Max(T x, T y, vtkm::TypeTraitsScalarTag)
{
return (x < y) ? y : x;
}
template<typename T>
VTKM_EXEC_CONT_EXPORT
T Max(const T &x, const T &y, vtkm::TypeTraitsVectorTag)
{
typedef vtkm::VecTraits<T> Traits;
T result;
for (vtkm::IdComponent index = 0; index < Traits::NUM_COMPONENTS; index++)
{
Traits::SetComponent(result,
index,
vtkm::Max(Traits::GetComponent(x, index),
Traits::GetComponent(y, index)));
}
return result;
}
template<typename T>
VTKM_EXEC_CONT_EXPORT
T Min(T x, T y, vtkm::TypeTraitsScalarTag)
{
return (x < y) ? x : y;
}
template<typename T>
VTKM_EXEC_CONT_EXPORT
T Min(const T &x, const T &y, vtkm::TypeTraitsVectorTag)
{
typedef vtkm::VecTraits<T> Traits;
T result;
for (vtkm::IdComponent index = 0; index < Traits::NUM_COMPONENTS; index++)
{
Traits::SetComponent(result,
index,
vtkm::Min(Traits::GetComponent(x, index),
Traits::GetComponent(y, index)));
}
return result;
}
} // namespace detail
/// Returns \p x or \p y, whichever is larger.
///
template<typename T>
VTKM_EXEC_CONT_EXPORT
T Max(const T &x, const T &y) {
return detail::Max(x, y, typename vtkm::TypeTraits<T>::DimensionalityTag());
}
/// Returns \p x or \p y, whichever is smaller.
///
template<typename T>
VTKM_EXEC_CONT_EXPORT
T Min(const T &x, const T &y) {
return detail::Min(x, y, typename vtkm::TypeTraits<T>::DimensionalityTag());
}
//-----------------------------------------------------------------------------
//#ifdef VTKM_CUDA
#define VTKM_USE_IEEE_NONFINITE
//#endif
#ifdef VTKM_USE_IEEE_NONFINITE
namespace detail {
union IEEE754Bits32 {
vtkm::UInt32 bits;
vtkm::Float32 scalar;
};
#define VTKM_NAN_BITS_32 0x7FC00000
#define VTKM_INF_BITS_32 0x7F800000
#define VTKM_NEG_INF_BITS_32 0xFF800000
#define VTKM_EPSILON_32 1e-5f
union IEEE754Bits64 {
vtkm::UInt64 bits;
vtkm::Float64 scalar;
};
#define VTKM_NAN_BITS_64 0x7FF8000000000000LL
#define VTKM_INF_BITS_64 0x7FF0000000000000LL
#define VTKM_NEG_INF_BITS_64 0xFFF0000000000000LL
#define VTKM_EPSILON_64 1e-9
template<typename T> struct FloatLimits;
template<>
struct FloatLimits<vtkm::Float32>
{
typedef vtkm::detail::IEEE754Bits32 BitsType;
VTKM_EXEC_CONT_EXPORT
static vtkm::Float32 Nan() {
BitsType nan = {VTKM_NAN_BITS_32};
return nan.scalar;
}
VTKM_EXEC_CONT_EXPORT
static vtkm::Float32 Infinity() {
BitsType inf = {VTKM_INF_BITS_32};
return inf.scalar;
}
VTKM_EXEC_CONT_EXPORT
static vtkm::Float32 NegativeInfinity() {
BitsType neginf = {VTKM_NEG_INF_BITS_32};
return neginf.scalar;
}
VTKM_EXEC_CONT_EXPORT
static vtkm::Float32 Epsilon() {
return VTKM_EPSILON_32;
}
};
template<>
struct FloatLimits<vtkm::Float64>
{
typedef vtkm::detail::IEEE754Bits64 BitsType;
VTKM_EXEC_CONT_EXPORT
static vtkm::Float64 Nan() {
BitsType nan = {VTKM_NAN_BITS_64};
return nan.scalar;
}
VTKM_EXEC_CONT_EXPORT
static vtkm::Float64 Infinity() {
BitsType inf = {VTKM_INF_BITS_64};
return inf.scalar;
}
VTKM_EXEC_CONT_EXPORT
static vtkm::Float64 NegativeInfinity() {
BitsType neginf = {VTKM_NEG_INF_BITS_64};
return neginf.scalar;
}
VTKM_EXEC_CONT_EXPORT
static vtkm::Float64 Epsilon() {
return VTKM_EPSILON_64;
}
};
#undef VTKM_NAN_BITS_32
#undef VTKM_INF_BITS_32
#undef VTKM_NEG_INF_BITS_32
#undef VTKM_EPSILON_32
#undef VTKM_NAN_BITS_64
#undef VTKM_INF_BITS_64
#undef VTKM_NEG_INF_BITS_64
#undef VTKM_EPSILON_64
} // namespace detail
/// Returns the representation for not-a-number (NaN).
///
template<typename T>
VTKM_EXEC_CONT_EXPORT
T Nan()
{
return detail::FloatLimits<T>::Nan();
}
/// Returns the representation for infinity.
///
template<typename T>
VTKM_EXEC_CONT_EXPORT
T Infinity()
{
return detail::FloatLimits<T>::Infinity();
}
/// Returns the representation for negative infinity.
///
template<typename T>
VTKM_EXEC_CONT_EXPORT
T NegativeInfinity()
{
return detail::FloatLimits<T>::NegativeInfinity();
}
/// Returns the difference between 1 and the least value greater than 1
/// that is representable.
///
template<typename T>
VTKM_EXEC_CONT_EXPORT
T Epsilon()
{
return detail::FloatLimits<T>::Epsilon();
}
#else // !VTKM_USE_IEEE_NONFINITE
/// Returns the representation for not-a-number (NaN).
///
template<typename T>
VTKM_EXEC_CONT_EXPORT
T Nan()
{
return std::numeric_limits<T>::quiet_NaN();
}
/// Returns the representation for infinity.
///
template<typename T>
VTKM_EXEC_CONT_EXPORT
T Infinity()
{
return std::numeric_limits<T>::infinity();
}
/// Returns the representation for negative infinity.
///
template<typename T>
VTKM_EXEC_CONT_EXPORT
T NegativeInfinity()
{
return -std::numeric_limits<T>::infinity();
}
/// Returns the difference between 1 and the least value greater than 1
/// that is representable.
///
template<typename T>
VTKM_EXEC_CONT_EXPORT
T Epsilon()
{
return std::numeric_limits<T>::epsilon();
}
#endif // !VTKM_USE_IEEE_NONFINITE
/// Returns the representation for not-a-number (NaN).
///
VTKM_EXEC_CONT_EXPORT vtkm::Float32 Nan32() {
return vtkm::Nan<vtkm::Float32>();
}
VTKM_EXEC_CONT_EXPORT vtkm::Float64 Nan64() {
return vtkm::Nan<vtkm::Float64>();
}
/// Returns the representation for infinity.
///
VTKM_EXEC_CONT_EXPORT vtkm::Float32 Infinity32() {
return vtkm::Infinity<vtkm::Float32>();
}
VTKM_EXEC_CONT_EXPORT vtkm::Float64 Infinity64() {
return vtkm::Infinity<vtkm::Float64>();
}
/// Returns the representation for negative infinity.
///
VTKM_EXEC_CONT_EXPORT vtkm::Float32 NegativeInfinity32() {
return vtkm::NegativeInfinity<vtkm::Float32>();
}
VTKM_EXEC_CONT_EXPORT vtkm::Float64 NegativeInfinity64() {
return vtkm::NegativeInfinity<vtkm::Float64>();
}
/// Returns the difference between 1 and the least value greater than 1
/// that is representable.
///
VTKM_EXEC_CONT_EXPORT vtkm::Float32 Epsilon32()
{
return vtkm::Epsilon<vtkm::Float32>();
}
VTKM_EXEC_CONT_EXPORT vtkm::Float64 Epsilon64()
{
return vtkm::Epsilon<vtkm::Float64>();
}
//-----------------------------------------------------------------------------
/// Returns true if \p x is not a number.
///
template<typename T>
VTKM_EXEC_CONT_EXPORT
bool IsNan(T x)
{
#ifdef VTKM_USE_BOOST_CLASSIFY
using boost::math::isnan;
#endif
return (isnan(x) != 0);
}
/// Returns true if \p x is positive or negative infinity.
///
template<typename T>
VTKM_EXEC_CONT_EXPORT
bool IsInf(T x)
{
#ifdef VTKM_USE_BOOST_CLASSIFY
using boost::math::isinf;
#endif
return (isinf(x) != 0);
}
/// Returns true if \p x is a normal number (not NaN or infinite).
///
template<typename T>
VTKM_EXEC_CONT_EXPORT
bool IsFinite(T x)
{
#ifdef VTKM_USE_BOOST_CLASSIFY
using boost::math::isfinite;
#endif
return (isfinite(x) != 0);
}
//-----------------------------------------------------------------------------
/// Round \p x to the smallest integer value not less than x.
///
$unary_math_function('Ceil', 'ceil')\
/// Round \p x to the largest integer value not greater than x.
///
$unary_math_function('Floor', 'floor')\
/// Round \p x to the nearest integral value.
///
#ifdef VTKM_USE_BOOST_MATH
$unary_template_function_no_vec('Round', 'boost::math::round(x)')\
$#
#else // !VTKM_USE_BOOST_MATH
$unary_math_function_no_vec('Round', 'round')\
$#
#endif // !VTKM_USE_BOOST_MATH
$unary_Vec_function('Round')\
//-----------------------------------------------------------------------------
/// Computes the remainder on division of 2 floating point numbers. The return
/// value is \p numerator - n \p denominator, where n is the quotient of \p
/// numerator divided by \p denominator rounded towards zero to an integer. For
/// example, <tt>FMod(6.5, 2.3)</tt> returns 1.9, which is 6.5 - 2*2.3.
///
$binary_math_function('FMod', 'fmod')\
/// Computes the remainder on division of 2 floating point numbers. The return
/// value is \p numerator - n \p denominator, where n is the quotient of \p
/// numerator divided by \p denominator rounded towards the nearest integer
/// (instead of toward zero like FMod). For example, <tt>FMod(6.5, 2.3)</tt>
/// returns -0.4, which is 6.5 - 3*2.3.
///
#ifdef VTKM_MSVC
template<typename T>
VTKM_EXEC_CONT_EXPORT
T Remainder(T numerator, T denominator)
{
T quotient = vtkm::Round(numerator/denominator);
return numerator - quotient*denominator;
}
#else // !VTKM_MSVC
$binary_math_function('Remainder', 'remainder')\
$#
#endif // !VTKM_MSVC
/// Returns the remainder on division of 2 floating point numbers just like
/// Remainder. In addition, this function also returns the \c quotient used to
/// get that remainder.
///
template<typename QType>
VTKM_EXEC_CONT_EXPORT
vtkm::Float32 RemainderQuotient(vtkm::Float32 numerator,
vtkm::Float32 denominator,
QType &quotient)
{
#ifdef VTKM_USE_BOOST_MATH
quotient = static_cast<QType>(boost::math::round(numerator/denominator));
return vtkm::Remainder(numerator, denominator);
#else
int iQuotient;
vtkm::Float32 result =
VTKM_SYS_MATH_FUNCTION_32(remquo)(numerator, denominator, &iQuotient);
quotient = iQuotient;
return result;
#endif
}
template<typename QType>
VTKM_EXEC_CONT_EXPORT
vtkm::Float64 RemainderQuotient(vtkm::Float64 numerator,
vtkm::Float64 denominator,
QType &quotient)
{
#ifdef VTKM_USE_BOOST_MATH
quotient = static_cast<QType>(boost::math::round(numerator/denominator));
return vtkm::Remainder(numerator, denominator);
#else
int iQuotient;
vtkm::Float64 result =
VTKM_SYS_MATH_FUNCTION_64(remquo)(numerator, denominator, &iQuotient);
quotient = iQuotient;
return result;
#endif
}
/// Gets the integral and fractional parts of \c x. The return value is the
/// fractional part and \c integral is set to the integral part.
///
VTKM_EXEC_CONT_EXPORT
vtkm::Float32 ModF(vtkm::Float32 x, vtkm::Float32 &integral)
{
return VTKM_SYS_MATH_FUNCTION_32(modf)(x, &integral);
}
VTKM_EXEC_CONT_EXPORT
vtkm::Float64 ModF(vtkm::Float64 x, vtkm::Float64 &integral)
{
return VTKM_SYS_MATH_FUNCTION_64(modf)(x, &integral);
}
//-----------------------------------------------------------------------------
/// Return the absolute value of \p x. That is, return \p x if it is positive or
/// \p -x if it is negative.
///
VTKM_EXEC_CONT_EXPORT
vtkm::Int32 Abs(vtkm::Int32 x)
{
#if VTKM_SIZE_INT == 4
return abs(x);
#else
#error Unknown size of Int32.
#endif
}
VTKM_EXEC_CONT_EXPORT
vtkm::Int64 Abs(vtkm::Int64 x)
{
#if VTKM_SIZE_LONG == 8
return labs(x);
#elif VTKM_SIZE_LONG_LONG == 8
return llabs(x);
#else
#error Unknown size of Int64.
#endif
}
$unary_math_function('Abs', 'fabs')\
/// Returns a nonzero value if \p x is negative.
///
$unary_template_function_no_vec('SignBit',
'static_cast<vtkm::Int32>(signbit(x))',
'vtkm::Int32',
'''#ifdef VTKM_USE_BOOST_SIGN
using boost::math::signbit;
#endif
''')\
/// Returns true if \p x is less than zero, false otherwise.
///
$unary_template_function_no_vec('IsNegative', '(vtkm::SignBit(x) != 0)', 'bool')\
/// Copies the sign of \p y onto \p x. If \p y is positive, returns Abs(\p x).
/// If \p y is negative, returns -Abs(\p x).
///
#ifdef VTKM_USE_BOOST_SIGN
$binary_template_function('CopySign', 'boost::math::copysign(x,y)')\
$#
#else // !VTKM_USE_BOOST_SIGN
$binary_math_function('CopySign', 'copysign')\
$#
#endif // !VTKM_USE_BOOST_SIGN
template<typename T, vtkm::IdComponent N>
VTKM_EXEC_CONT_EXPORT
vtkm::Vec<T,N> CopySign(const vtkm::Vec<T,N> &x, const vtkm::Vec<T,N> &y)
{
vtkm::Vec<T,N> result;
for (vtkm::IdComponent index = 0; index < N; index++)
{
result[index] = vtkm::CopySign(x[index], y[index]);
}
return result;
}
} // namespace vtkm
#endif //vtk_m_Math_h