inline half expm1()

in include/half.hpp [3007:3050]


	inline half expm1(half arg)
	{
	#if defined(HALF_ARITHMETIC_TYPE) && HALF_ENABLE_CPP11_CMATH
		return half(detail::binary, detail::float2half<half::round_style>(std::expm1(detail::half2float<detail::internal_t>(arg.data_))));
	#else
		unsigned int abs = arg.data_ & 0x7FFF, sign = arg.data_ & 0x8000;
		if(!abs)
			return arg;
		if(abs >= 0x7C00)
			return half(detail::binary, (abs==0x7C00) ? (0x7C00+(sign>>1)) : detail::signal(arg.data_));
		if(abs >= 0x4A00)
			return half(detail::binary, (arg.data_&0x8000) ? detail::rounded<half::round_style,true>(0xBBFF, 1, 1) : detail::overflow<half::round_style>());
		detail::uint32 m = detail::multiply64(static_cast<detail::uint32>((abs&0x3FF)+((abs>0x3FF)<<10))<<21, 0xB8AA3B29);
		int e = (abs>>10) + (abs<=0x3FF), exp;
		if(e < 14)
		{
			exp = 0;
			m >>= 14 - e;
		}
		else
		{
			exp = m >> (45-e);
			m = (m<<(e-14)) & 0x7FFFFFFF;
		}
		m = detail::exp2(m);
		if(sign)
		{
			int s = 0;
			if(m > 0x80000000)
			{
				++exp;
				m = detail::divide64(0x80000000, m, s);
			}
			m = 0x80000000 - ((m>>exp)|((m&((static_cast<detail::uint32>(1)<<exp)-1))!=0)|s);
			exp = 0;
		}
		else
			m -= (exp<31) ? (0x80000000>>exp) : 1;
		for(exp+=14; m<0x80000000 && exp; m<<=1,--exp) ;
		if(exp > 29)
			return half(detail::binary, detail::overflow<half::round_style>());
		return half(detail::binary, detail::rounded<half::round_style,true>(sign+(exp<<10)+(m>>21), (m>>20)&1, (m&0xFFFFF)!=0));
	#endif
	}