%PDF- %PDF-
| Direktori : /usr/include/xsimd/math/ |
| Current File : //usr/include/xsimd/math/xsimd_basic_math.hpp |
/***************************************************************************
* Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and *
* Martin Renou *
* Copyright (c) QuantStack *
* *
* Distributed under the terms of the BSD 3-Clause License. *
* *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/
#ifndef XSIMD_BASIC_MATH_HPP
#define XSIMD_BASIC_MATH_HPP
#include "xsimd_numerical_constant.hpp"
#include "xsimd_rounding.hpp"
#include "../types/xsimd_traits.hpp"
namespace xsimd
{
/********************
* Basic operations *
********************/
template <class B>
batch_type_t<B> fmod(const simd_base<B>& x, const simd_base<B>& y);
template <class B>
batch_type_t<B> remainder(const simd_base<B>& x, const simd_base<B>& y);
template <class B>
batch_type_t<B> fdim(const simd_base<B>& x, const simd_base<B>& y);
template <class B>
batch_type_t<B> clip(const simd_base<B>& x, const simd_base<B>& lo, const simd_base<B>& hi);
template <class X, class Y>
batch_type_t<X> nextafter(const simd_base<X>& from, const simd_base<Y>& to);
/****************************
* Classification functions *
****************************/
template <class B>
typename simd_batch_traits<B>::batch_bool_type
isfinite(const simd_base<B>& x);
template <class B>
typename simd_batch_traits<B>::batch_bool_type
isinf(const simd_base<B>& x);
template <class B>
typename simd_batch_traits<B>::batch_bool_type
is_flint(const simd_base<B>& x);
template <class B>
typename simd_batch_traits<B>::batch_bool_type
is_odd(const simd_base<B>& x);
template <class B>
typename simd_batch_traits<B>::batch_bool_type
is_even(const simd_base<B>& x);
/***********************************
* Basic operations implementation *
***********************************/
namespace detail
{
template <class T>
struct get_batch_value_type
{
using type = T;
};
template <class T, std::size_t N>
struct get_batch_value_type<batch<T, N>>
{
using type = T;
};
template <class B>
using get_batch_value_type_t = typename get_batch_value_type<B>::type;
template <class B, bool is_int = std::is_integral<get_batch_value_type_t<B>>::value>
struct remainder_kernel
{
using batch_type = B;
using size_type = std::size_t;
static constexpr size_type double_size = batch_type::size;
static inline batch_type fmod(const batch_type& x, const batch_type& y)
{
return fnma(trunc(x / y), y, x);
}
static inline batch_type remainder(const batch_type& x, const batch_type& y)
{
return fnma(nearbyint(x / y), y, x);
}
template <class IB>
static inline batch_type to_double(const IB& b, size_type offset)
{
batch_type res;
for (size_type i = 0; i < double_size; ++i)
{
res[i] = b[i + offset];
}
return res;
}
template <class IB>
static inline void to_int(const batch_type& src, IB& dst, size_type offset)
{
for (size_type i = 0; i < double_size; ++i)
{
dst[i + offset] = src[i];
}
}
};
template <>
struct remainder_kernel<double, false>
{
using size_type = std::size_t;
static inline double fmod(double x, double y)
{
return std::fmod(x, y);
}
static inline double remainder(double x, double y)
{
return std::remainder(x, y);
}
template <class IB>
static inline double to_double(const IB& b, size_type offset)
{
double res = b[offset];
return res;
}
template <class IB>
static inline void to_int(double src, IB& dst, size_type offset)
{
dst[offset] = src;
}
};
template <class B>
struct remainder_kernel<B, true>
{
using batch_type = B;
using double_batch = typename simd_traits<double>::type;
using double_kernel = remainder_kernel<double_batch>;
using size_type = std::size_t;
static constexpr size_type int_size = B::size;
static constexpr size_type double_size = simd_traits<double>::size;
static inline batch_type fmod(const batch_type& x, const batch_type& y)
{
batch_type res;
for (size_type i = 0; i < int_size; i += double_size)
{
double_batch tmp = double_kernel::fmod(double_kernel::to_double(x, i),
double_kernel::to_double(y, i));
double_kernel::to_int(tmp, res, i);
}
return res;
}
static inline batch_type remainder(const batch_type& x, const batch_type& y)
{
batch_type res;
for (size_type i = 0; i < int_size; i += double_size)
{
double_batch tmp = double_kernel::remainder(double_kernel::to_double(x, i),
double_kernel::to_double(y, i));
double_kernel::to_int(tmp, res, i);
}
return res;
}
};
}
/**
* @brief Computes the floating-point remainder of the division operation \c x/y.
*
* The floating-point remainder of the division operation \c x/y calculated by this
* function is exactly the value <tt>x - n*y</tt>, where \c n is \c x/y with its fractional
* part truncated. The returned value has the same sign as \c x and is less than \c y in magnitude.
* @param x batch of floating point values.
* @param y batch of floating point values.
* @return the floating-point remainder of the division.
*/
template <class B>
inline batch_type_t<B> fmod(const simd_base<B>& x, const simd_base<B>& y)
{
return detail::remainder_kernel<B>::fmod(x(), y());
}
/**
* @brief Computes the IEEE remainder of the floating point division operation \c x/y.
*
* The IEEE floating-point remainder of the division operation \c x/y calculated by this
* function is exactly the value <tt>x - n*y</tt>, where the value n is the integral value
* nearest the exact value \c x/y. When <tt>|n-x/y| = 0.5</tt>, the value n is chosen to be even.
* In contrast to fmod, the returned value is not guaranteed to have the same sign as \c x.
* If the returned value is 0, it will have the same sign as \c x.
* @param x batch of floating point values.
* @param y batch of floating point values.
* @return the IEEE remainder remainder of the floating point division.
*/
template <class B>
inline batch_type_t<B> remainder(const simd_base<B>& x, const simd_base<B>& y)
{
return detail::remainder_kernel<B>::remainder(x(), y());
}
/**
* Computes the positive difference between \c x and \c y, that is,
* <tt>max(0, x-y)</tt>.
* @param x batch of floating point values.
* @param y batch of floating point values.
* @return the positive difference.
*/
template <class B>
inline batch_type_t<B> fdim(const simd_base<B>& x, const simd_base<B>& y)
{
return fmax(batch_type_t<B>(0.), x - y);
}
/**
* Clips the values of the batch \c x between those of the batches \c lo and \c hi.
* @param x batch of floating point values.
* @param lo batch of floating point values.
* @param hi batch of floating point values.
* @return the result of the clipping.
*/
template <class B>
inline batch_type_t<B> clip(const simd_base<B>& x, const simd_base<B>& lo, const simd_base<B>& hi)
{
return min(hi, max(x, lo));
}
// TODO move scalar version?
template <class T, class = typename std::enable_if<std::is_scalar<T>::value>::type>
inline T clip(const T& x, const T& lo, const T& hi)
{
return std::min(hi, std::max(x, lo));
}
namespace detail
{
template <class T, std::size_t N, bool is_int = std::is_integral<T>::value>
struct nextafter_kernel
{
using batch_type = batch<T, N>;
static inline batch_type next(const batch_type& b) noexcept
{
return b;
}
static inline batch_type prev(const batch_type& b) noexcept
{
return b;
}
};
template <class T, std::size_t N>
struct bitwise_cast_batch;
template <std::size_t N>
struct bitwise_cast_batch<float, N>
{
using type = batch<int32_t, N>;
};
template <std::size_t N>
struct bitwise_cast_batch<double, N>
{
using type = batch<int64_t, N>;
};
template <class T, std::size_t N>
struct nextafter_kernel<T, N, false>
{
using batch_type = batch<T, N>;
using int_batch = typename bitwise_cast_batch<T, N>::type;
using int_type = typename int_batch::value_type;
static inline batch_type next(const batch_type& b) noexcept
{
batch_type n = bitwise_cast<batch_type>(bitwise_cast<int_batch>(b) + int_type(1));
return select(b == infinity<batch_type>(), b, n);
}
static inline batch_type prev(const batch_type& b) noexcept
{
batch_type p = bitwise_cast<batch_type>(bitwise_cast<int_batch>(b) - int_type(1));
return select(b == minusinfinity<batch_type>(), b, p);
}
};
}
template <class X, class Y>
inline batch_type_t<X> nextafter(const simd_base<X>& from, const simd_base<Y>& to)
{
using kernel = detail::nextafter_kernel<typename batch_type_t<X>::value_type, batch_type_t<X>::size>;
return select(from == to,
from,
select(to > from,
kernel::next(from()),
kernel::prev(from())));
}
/*******************************************
* Classification functions implementation *
*******************************************/
/**
* Determines if the scalars in the given batch \c x are finite values,
* i.e. they are different from infinite or NaN.
* @param x batch of floating point values.
* @return a batch of booleans.
*/
template <class B>
inline typename simd_batch_traits<B>::batch_bool_type
isfinite(const simd_base<B>& x)
{
return (x - x) == batch_type_t<B>(0.);
}
namespace detail
{
template <class T, std::size_t N, bool is_int = std::is_integral<T>::value>
struct isinf_kernel
{
using batch_type = batch<T, N>;
using batch_bool_type = typename simd_batch_traits<batch_type>::batch_bool_type;
static inline batch_bool_type run(const batch_type& x)
{
return abs(x) == ::xsimd::infinity<batch_type_t<batch_type>>();
}
};
template <class T, std::size_t N>
struct isinf_kernel<T, N, true>
{
using batch_type = batch<T, N>;
using batch_bool_type = typename simd_batch_traits<batch_type>::batch_bool_type;
static inline batch_bool_type run(const batch_type&)
{
return batch_bool_type(false);
}
};
}
/**
* Determines if the scalars in the given batch \c x are positive
* or negative infinity.
* @param x batch of floating point values.
* @return a batch of booleans.
*/
template <class B>
inline typename simd_batch_traits<B>::batch_bool_type
isinf(const simd_base<B>& x)
{
using kernel_type = detail::isinf_kernel<typename batch_type_t<B>::value_type, batch_type_t<B>::size>;
return kernel_type::run(x());
//return abs(x) == infinity<batch_type_t<B>>();
}
template <class B>
inline typename simd_batch_traits<B>::batch_bool_type
is_flint(const simd_base<B>& x)
{
using b_type = batch_type_t<B>;
b_type frac = select(xsimd::isnan(x - x), nan<b_type>(), x - trunc(x));
return frac == b_type(0.);
}
template <class B>
inline typename simd_batch_traits<B>::batch_bool_type
is_odd(const simd_base<B>& x)
{
return is_even(x - batch_type_t<B>(1.));
}
template <class B>
inline typename simd_batch_traits<B>::batch_bool_type
is_even(const simd_base<B>& x)
{
return is_flint(x * batch_type_t<B>(0.5));
}
}
#endif