//=============================================================================
//
//  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 Math.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>
#include <cmath>
#endif // !VTKM_CUDA

#if !defined(__CUDA_ARCH__)
#define VTKM_USE_STL
#include <algorithm>
#endif

#if defined(VTKM_MSVC) && !defined(VTKM_CUDA)
#include <math.h>
#endif

#define VTKM_CUDA_MATH_FUNCTION_32(func) func ## f
#define VTKM_CUDA_MATH_FUNCTION_64(func) func

$py(
def unary_function(name, type, returntype, cuda_expression, std_expression):
  return '''static inline VTKM_EXEC_CONT
{2} {0}({1} x) {{
#ifdef VTKM_CUDA
  return {3};
#else
  return {4};
#endif
}}
'''.format(name, type, returntype, cuda_expression, std_expression)

def unary_Vec_function(vtkmname):
  return '''template<typename T, vtkm::IdComponent N>
static inline VTKM_EXEC_CONT
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>
static inline VTKM_EXEC_CONT
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>
static inline VTKM_EXEC_CONT
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>
static inline VTKM_EXEC_CONT
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_CUDA_MATH_FUNCTION_32(' + sysname + ')(x)',
                        'std::' + sysname + '(x)') + \
         unary_function(vtkmname,
                        'vtkm::Float64',
                        'vtkm::Float64' if returntype == None else returntype,
                        'VTKM_CUDA_MATH_FUNCTION_64(' + sysname + ')(x)',
                        'std::' + 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 '''static inline VTKM_EXEC_CONT
{2} {0}(vtkm::Float32 x) {{
{3}  return {1};
}}
'''.format(vtkmname,
           expression,
           'vtkm::Float32' if returntype == None else returntype,
           preexpression) + \
'''static inline VTKM_EXEC_CONT
{2} {0}(vtkm::Float64 x) {{
{3}  return {1};
}}
'''.format(vtkmname,
           expression,
           'vtkm::Float64' if returntype == None else returntype,
           preexpression)

def binary_function(name, type, cuda_expression, std_expression):
  return '''static inline VTKM_EXEC_CONT
{1} {0}({1} x, {1} y) {{
#ifdef VTKM_CUDA
  return {2};
#else
  return {3};
#endif
}}
'''.format(name, type, cuda_expression, std_expression)

def binary_math_function(vtkmname, sysname):
  return binary_function(vtkmname,
                         'vtkm::Float32',
                         'VTKM_CUDA_MATH_FUNCTION_32(' + sysname + ')(x,y)',
                         'std::' + sysname + '(x,y)') + \
         binary_function(vtkmname,
                         'vtkm::Float64',
                         'VTKM_CUDA_MATH_FUNCTION_64(' + sysname + ')(x,y)',
                         'std::' + sysname + '(x,y)')

def binary_template_function(vtkmname, expression):
  return '''static inline VTKM_EXEC_CONT
vtkm::Float32 {0}(vtkm::Float32 x, vtkm::Float32 y) {{
  return {1};
}}
static inline VTKM_EXEC_CONT
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.
///
static inline VTKM_EXEC_CONT
vtkm::Float64 TwoPi()
{
  return 6.28318530717958647692528676655900576;
}

/// Returns the constant Pi.
///
static inline VTKM_EXEC_CONT
vtkm::Float64 Pi()
{
  return 3.14159265358979323846264338327950288;
}

/// Returns the constant Pi halves.
///
static inline VTKM_EXEC_CONT
vtkm::Float64 Pi_2()
{
  return 1.57079632679489661923132169163975144;
}
/// Returns the constant Pi thirds.
///
static inline VTKM_EXEC_CONT
vtkm::Float64 Pi_3()
{
  return 1.04719755119659774615421446109316762;
}

/// Returns the constant Pi fourths.
///
static inline VTKM_EXEC_CONT
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.
///
$unary_math_function_no_vec('ASinH', 'asinh')\
$#
$unary_Vec_function('ASinH')\

/// Compute the hyperbolic arc cosine of \p x.
///
$unary_math_function_no_vec('ACosH', 'acosh')\
$#
$unary_Vec_function('ACosH')\

/// Compute the hyperbolic arc tangent of \p x.
///
$unary_math_function_no_vec('ATanH', 'atanh')\
$#
$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
static inline VTKM_EXEC_CONT
vtkm::Float32 RSqrt(vtkm::Float32 x) {
  return rsqrtf(x);
}
static inline VTKM_EXEC_CONT
vtkm::Float64 RSqrt(vtkm::Float64 x) {
  return rsqrt(x);
}
#else // !VTKM_CUDA
static inline VTKM_EXEC_CONT
vtkm::Float32 RSqrt(vtkm::Float32 x) {
  return 1/vtkm::Sqrt(x);
}
static inline VTKM_EXEC_CONT
vtkm::Float64 RSqrt(vtkm::Float64 x) {
  return 1/vtkm::Sqrt(x);
}
#endif // !VTKM_CUDA

$unary_Vec_function('RSqrt')\

/// Compute the cube root of \p x.
///
$unary_math_function_no_vec('Cbrt', 'cbrt')\
$#
$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
static inline VTKM_EXEC_CONT
vtkm::Float32 RCbrt(vtkm::Float32 x) {
  return rcbrtf(x);
}
static inline VTKM_EXEC_CONT
vtkm::Float64 RCbrt(vtkm::Float64 x) {
  return rcbrt(x);
}
#else // !VTKM_CUDA
static inline VTKM_EXEC_CONT
vtkm::Float32 RCbrt(vtkm::Float32 x) {
  return 1/vtkm::Cbrt(x);
}
static inline VTKM_EXEC_CONT
vtkm::Float64 RCbrt(vtkm::Float64 x) {
  return 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.
///
$unary_math_function_no_vec('Exp2', 'exp2')\
$#
$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.
///
$unary_math_function_no_vec('ExpM1', 'expm1')\
$#
$unary_Vec_function('ExpM1')\

/// Computes 10**\p x, the base-10 exponential of \p x.
///
#ifdef VTKM_CUDA
static inline VTKM_EXEC_CONT
vtkm::Float32 Exp10(vtkm::Float32 x) {
  return exp10f(x);
}
static inline VTKM_EXEC_CONT
vtkm::Float64 Exp10(vtkm::Float64 x) {
  return exp10(x);
}
#else // !VTKM_CUDA
static inline VTKM_EXEC_CONT
vtkm::Float32 Exp10(vtkm::Float32 x) {
  return vtkm::Pow(10, x);;
}
static inline VTKM_EXEC_CONT
vtkm::Float64 Exp10(vtkm::Float64 x) {
  return 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.
///
$unary_math_function_no_vec('Log2', 'log2')\
$#
$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.
///
$unary_math_function_no_vec('Log1P', 'log1p')\
$#
$unary_Vec_function('Log1P')\

//-----------------------------------------------------------------------------
/// Returns \p x or \p y, whichever is larger.
///
template<typename T>
static inline VTKM_EXEC_CONT
T Max(const T &x, const T &y);
#ifdef VTKM_USE_STL
$binary_template_function('Max', '(std::max)(x, y)')\
$#
#else // !VTKM_USE_STL
$binary_math_function('Max', 'fmax')\
$#
#endif // !VTKM_USE_STL

/// Returns \p x or \p y, whichever is smaller.
///
template<typename T>
static inline VTKM_EXEC_CONT
T Min(const T &x, const T &y);
#ifdef VTKM_USE_STL
$binary_template_function('Min', '(std::min)(x, y)')\
$#
#else // !VTKM_USE_STL
$binary_math_function('Min', 'fmin')\
$#
#endif // !VTKM_USE_STL

namespace detail {

template<typename T>
static inline VTKM_EXEC_CONT
T Max(T x, T y, vtkm::TypeTraitsScalarTag)
{
  return (x < y) ? y : x;
}

template<typename T>
static inline VTKM_EXEC_CONT
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>
static inline VTKM_EXEC_CONT
T Min(T x, T y, vtkm::TypeTraitsScalarTag)
{
  return (x < y) ? x : y;
}

template<typename T>
static inline VTKM_EXEC_CONT
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>
static inline VTKM_EXEC_CONT
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>
static inline VTKM_EXEC_CONT
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      0x7FC00000U
#define VTKM_INF_BITS_32      0x7F800000U
#define VTKM_NEG_INF_BITS_32  0xFF800000U
#define VTKM_EPSILON_32       1e-5f

union IEEE754Bits64 {
  vtkm::UInt64 bits;
  vtkm::Float64 scalar;
};
#define VTKM_NAN_BITS_64      0x7FF8000000000000ULL
#define VTKM_INF_BITS_64      0x7FF0000000000000ULL
#define VTKM_NEG_INF_BITS_64  0xFFF0000000000000ULL
#define VTKM_EPSILON_64       1e-9

template<typename T> struct FloatLimits;

template<>
struct FloatLimits<vtkm::Float32>
{
  typedef vtkm::detail::IEEE754Bits32 BitsType;

  VTKM_EXEC_CONT
  static vtkm::Float32 Nan() {
    BitsType nan = {VTKM_NAN_BITS_32};
    return nan.scalar;
  }

  VTKM_EXEC_CONT
  static vtkm::Float32 Infinity() {
    BitsType inf = {VTKM_INF_BITS_32};
    return inf.scalar;
  }

  VTKM_EXEC_CONT
  static vtkm::Float32 NegativeInfinity() {
    BitsType neginf = {VTKM_NEG_INF_BITS_32};
    return neginf.scalar;
  }

  VTKM_EXEC_CONT
  static vtkm::Float32 Epsilon() {
    return VTKM_EPSILON_32;
  }
};

template<int N>
struct FloatLimits< vtkm::Vec<vtkm::Float32,N> >
{
  typedef vtkm::detail::IEEE754Bits32 BitsType;

  VTKM_EXEC_CONT
  static vtkm::Vec<vtkm::Float32,N> Nan() {
    BitsType nan = {VTKM_NAN_BITS_32};
    return vtkm::Vec<vtkm::Float32,N>(nan.scalar);
  }

  VTKM_EXEC_CONT
  static vtkm::Vec<vtkm::Float32,N> Infinity() {
    BitsType inf = {VTKM_INF_BITS_32};
    return vtkm::Vec<vtkm::Float32,N>(inf.scalar);
  }

  VTKM_EXEC_CONT
  static vtkm::Vec<vtkm::Float32,N> NegativeInfinity() {
    BitsType neginf = {VTKM_NEG_INF_BITS_32};
    return vtkm::Vec<vtkm::Float32,N>(neginf.scalar);
  }

  VTKM_EXEC_CONT
  static vtkm::Vec<vtkm::Float32,N> Epsilon() {
    return vtkm::Vec<vtkm::Float32,N>(VTKM_EPSILON_32);
  }
};

template<>
struct FloatLimits<vtkm::Float64>
{
  typedef vtkm::detail::IEEE754Bits64 BitsType;

  VTKM_EXEC_CONT
  static vtkm::Float64 Nan() {
    BitsType nan = {VTKM_NAN_BITS_64};
    return nan.scalar;
  }

  VTKM_EXEC_CONT
  static vtkm::Float64 Infinity() {
    BitsType inf = {VTKM_INF_BITS_64};
    return inf.scalar;
  }

  VTKM_EXEC_CONT
  static vtkm::Float64 NegativeInfinity() {
    BitsType neginf = {VTKM_NEG_INF_BITS_64};
    return neginf.scalar;
  }

  VTKM_EXEC_CONT
  static vtkm::Float64 Epsilon() {
    return VTKM_EPSILON_64;
  }
};

template<int N>
struct FloatLimits< vtkm::Vec<vtkm::Float64,N> >
{
  typedef vtkm::detail::IEEE754Bits64 BitsType;

  VTKM_EXEC_CONT
  static vtkm::Vec<vtkm::Float64,N> Nan() {
    BitsType nan = {VTKM_NAN_BITS_64};
    return vtkm::Vec<vtkm::Float64,N>(nan.scalar);
  }

  VTKM_EXEC_CONT
  static vtkm::Vec<vtkm::Float64,N> Infinity() {
    BitsType inf = {VTKM_INF_BITS_64};
    return vtkm::Vec<vtkm::Float64,N>(inf.scalar);
  }

  VTKM_EXEC_CONT
  static vtkm::Vec<vtkm::Float64,N> NegativeInfinity() {
    BitsType neginf = {VTKM_NEG_INF_BITS_64};
    return vtkm::Vec<vtkm::Float64,N>(neginf.scalar);
  }

  VTKM_EXEC_CONT
  static vtkm::Vec<vtkm::Float64,N> Epsilon() {
    return vtkm::Vec<vtkm::Float64,N>(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>
static inline VTKM_EXEC_CONT
T Nan()
{
  return detail::FloatLimits<T>::Nan();
}

/// Returns the representation for infinity.
///
template<typename T>
static inline VTKM_EXEC_CONT
T Infinity()
{
  return detail::FloatLimits<T>::Infinity();
}

/// Returns the representation for negative infinity.
///
template<typename T>
static inline VTKM_EXEC_CONT
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>
static inline VTKM_EXEC_CONT
T Epsilon()
{
  return detail::FloatLimits<T>::Epsilon();
}

#else // !VTKM_USE_IEEE_NONFINITE

/// Returns the representation for not-a-number (NaN).
///
template<typename T>
static inline VTKM_EXEC_CONT
T Nan()
{
  return std::numeric_limits<T>::quiet_NaN();
}

/// Returns the representation for infinity.
///
template<typename T>
static inline VTKM_EXEC_CONT
T Infinity()
{
  return std::numeric_limits<T>::infinity();
}

/// Returns the representation for negative infinity.
///
template<typename T>
static inline VTKM_EXEC_CONT
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>
static inline VTKM_EXEC_CONT
T Epsilon()
{
  return std::numeric_limits<T>::epsilon();
}
#endif // !VTKM_USE_IEEE_NONFINITE

/// Returns the representation for not-a-number (NaN).
///
static inline VTKM_EXEC_CONT vtkm::Float32 Nan32() {
  return vtkm::Nan<vtkm::Float32>();
}
static inline VTKM_EXEC_CONT vtkm::Float64 Nan64() {
  return vtkm::Nan<vtkm::Float64>();
}

/// Returns the representation for infinity.
///
static inline VTKM_EXEC_CONT vtkm::Float32 Infinity32() {
  return vtkm::Infinity<vtkm::Float32>();
}
static inline VTKM_EXEC_CONT vtkm::Float64 Infinity64() {
  return vtkm::Infinity<vtkm::Float64>();
}

/// Returns the representation for negative infinity.
///
static inline VTKM_EXEC_CONT vtkm::Float32 NegativeInfinity32() {
  return vtkm::NegativeInfinity<vtkm::Float32>();
}
static inline VTKM_EXEC_CONT vtkm::Float64 NegativeInfinity64() {
  return vtkm::NegativeInfinity<vtkm::Float64>();
}

/// Returns the difference between 1 and the least value greater than 1
/// that is representable.
///
static inline VTKM_EXEC_CONT vtkm::Float32 Epsilon32()
{
  return vtkm::Epsilon<vtkm::Float32>();
}
static inline VTKM_EXEC_CONT vtkm::Float64 Epsilon64()
{
  return vtkm::Epsilon<vtkm::Float64>();
}

//-----------------------------------------------------------------------------
/// Returns true if \p x is not a number.
///
template<typename T>
static inline VTKM_EXEC_CONT
bool IsNan(T x)
{
#ifndef VTKM_CUDA
  using std::isnan;
#endif
  return (isnan(x) != 0);
}

/// Returns true if \p x is positive or negative infinity.
///
template<typename T>
static inline VTKM_EXEC_CONT
bool IsInf(T x)
{
#ifndef VTKM_CUDA
  using std::isinf;
#endif
  return (isinf(x) != 0);
}

/// Returns true if \p x is a normal number (not NaN or infinite).
///
template<typename T>
static inline VTKM_EXEC_CONT
bool IsFinite(T x)
{
#ifndef VTKM_CUDA
  using std::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.
///
$unary_math_function_no_vec('Round', 'round')\
$#
$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>
static inline VTKM_EXEC_CONT
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>
static inline VTKM_EXEC_CONT
vtkm::Float32 RemainderQuotient(vtkm::Float32 numerator,
                                vtkm::Float32 denominator,
                                QType &quotient)
{
  int iQuotient;
  vtkm::Float32 result = std::remquo(numerator, denominator, &iQuotient);
  quotient = iQuotient;
  return result;
}
template<typename QType>
static inline VTKM_EXEC_CONT
vtkm::Float64 RemainderQuotient(vtkm::Float64 numerator,
                                vtkm::Float64 denominator,
                                QType &quotient)
{
  int iQuotient;
  vtkm::Float64 result = std::remquo(numerator, denominator, &iQuotient);
  quotient = iQuotient;
  return result;
}

/// 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.
///
static inline VTKM_EXEC_CONT
vtkm::Float32 ModF(vtkm::Float32 x, vtkm::Float32 &integral)
{
  return std::modf(x, &integral);
}
static inline VTKM_EXEC_CONT
vtkm::Float64 ModF(vtkm::Float64 x, vtkm::Float64 &integral)
{
  return std::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.
///
static inline VTKM_EXEC_CONT
vtkm::Int32 Abs(vtkm::Int32 x)
{
#if VTKM_SIZE_INT == 4
  return abs(x);
#else
#error Unknown size of Int32.
#endif
}
static inline VTKM_EXEC_CONT
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',
'''#ifndef VTKM_CUDA
  using std::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).
///
$binary_math_function('CopySign', 'copysign')\
$#

template<typename T, vtkm::IdComponent N>
static inline VTKM_EXEC_CONT
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
