Hi John, i think your sign-function (boost/math/special_functions/sign.hpp) is incomplete. Because the resulttype is int, not all cases can be covered correctly (nan, inf, -0). With my implementation this works and it follows the std-conventions (sgn(FP) -> FP, sgn(INT/BOOL) -> double). I also tried to optimize them (branch-free, vectorizable).
sgn(FP) -> FP ±0/±1 sgn(FP nan/inf) -> FP nan/inf sgn(INT) -> double +0/±1 sgn(UINT/BOOL) -> double +0/+1 regards Gero
namespace std
{
namespace detail
{
template <typename Type> struct type_floating_point
{
static_assert(std::is_arithmetic_v<Type>, "invalid type");
using type = std::conditional_t<std::is_floating_point_v<Type>, Type, float64_t>;
};
} // detail
template <typename Type>
using floating_point_t = typename detail::type_floating_point<Type>::type;
// is float80_t
template <typename Type> struct is_float80 : public bool_constant
<
#if defined(BOOST_CSTDFLOAT_FLOAT80_NATIVE_TYPE)
is_same_v<Type, float80_t>
#else
false
#endif
> {};
template <typename Type>
inline constexpr bool is_float80_v = is_float80<Type>::value;
// arithmetic
template <typename Type>
concept arithmetic = is_arithmetic_v<Type>;
// combined nan/inf
template <arithmetic Type>
[[nodiscard]] inline constexpr bool isnaninf(const Type a) noexcept
{
if constexpr (is_floating_point_v<Type>)
return bool(int(isnan(a)) | int(isinf(a)));
else
return false;
}
template <arithmetic Type>
[[nodiscard]] inline constexpr floating_point_t<Type> sgn(const Type a) noexcept
{
using value_type = floating_point_t<Type>;
auto calc = [&]() constexpr noexcept
{
if constexpr (is_floating_point_v<Type>)
{
auto get_one_zero = [&]() constexpr noexcept -> value_type
{
// abs reduces/prevents double conditional jumps
return (abs(a) > 0) ? value_type{1} : value_type{0};
};
if constexpr (is_float80_v<Type>)
{
// optimized for float80_t if supported
const bool
ni = isnaninf(a);
const float80_t
oz = get_one_zero();
return copysign(ni ? a : oz, a);
}
else
{
// generate better/smaller code in vector/loop-context than isnaninf(a) ? a : copysign(get_one_zero(), a);
return !isnaninf(a) ? copysign(get_one_zero(), a) : a;
//return isnaninf(a) ? a : copysign(get_one_zero(), a);
}
}
else if constexpr (is_same_v<Type, bool>)
{
// fukking bool in arithmetic
return int(a);
}
else
{
if constexpr (is_signed_v<Type>)
return int(int(a>0) - int(a<0));
else
return int(a>0);
}
};
return value_type(calc());
}
} // std
OpenPGP_signature
Description: OpenPGP digital signature
_______________________________________________ Boost-users mailing list [email protected] https://lists.boost.org/mailman/listinfo.cgi/boost-users
