sgn/sign-function

Gero Peterhoff via Boost-users <[email protected]>
Newsgroups gmane.comp.lib.boost.user
Message-ID <[email protected]>
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

_______________________________________________
Boost-users mailing list
[email protected]
https://lists.boost.org/mailman/listinfo.cgi/boost-users
sgn.hpp (text/x-c++hdr, 2.1 KB)
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 (application/pgp-signature, 236 B) - not displayed
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.