inline half fma()

in include/half.hpp [2808:2869]


	inline half fma(half x, half y, half z)
	{
	#ifdef HALF_ARITHMETIC_TYPE
		detail::internal_t fx = detail::half2float<detail::internal_t>(x.data_), fy = detail::half2float<detail::internal_t>(y.data_), fz = detail::half2float<detail::internal_t>(z.data_);
		#if HALF_ENABLE_CPP11_CMATH && FP_FAST_FMA
			return half(detail::binary, detail::float2half<half::round_style>(std::fma(fx, fy, fz)));
		#else
			return half(detail::binary, detail::float2half<half::round_style>(fx*fy+fz));
		#endif
	#else
		int absx = x.data_ & 0x7FFF, absy = y.data_ & 0x7FFF, absz = z.data_ & 0x7FFF, exp = -15;
		unsigned int sign = (x.data_^y.data_) & 0x8000;
		bool sub = ((sign^z.data_)&0x8000) != 0;
		if(absx >= 0x7C00 || absy >= 0x7C00 || absz >= 0x7C00)
			return	(absx>0x7C00 || absy>0x7C00 || absz>0x7C00) ? half(detail::binary, detail::signal(x.data_, y.data_, z.data_)) :
					(absx==0x7C00) ? half(detail::binary, (!absy || (sub && absz==0x7C00)) ? detail::invalid() : (sign|0x7C00)) :
					(absy==0x7C00) ? half(detail::binary, (!absx || (sub && absz==0x7C00)) ? detail::invalid() : (sign|0x7C00)) : z;
		if(!absx || !absy)
			return absz ? z : half(detail::binary, (half::round_style==std::round_toward_neg_infinity) ? (z.data_|sign) : (z.data_&sign));
		for(; absx<0x400; absx<<=1,--exp) ;
		for(; absy<0x400; absy<<=1,--exp) ;
		detail::uint32 m = static_cast<detail::uint32>((absx&0x3FF)|0x400) * static_cast<detail::uint32>((absy&0x3FF)|0x400);
		int i = m >> 21;
		exp += (absx>>10) + (absy>>10) + i;
		m <<= 3 - i;
		if(absz)
		{
			int expz = 0;
			for(; absz<0x400; absz<<=1,--expz) ;
			expz += absz >> 10;
			detail::uint32 mz = static_cast<detail::uint32>((absz&0x3FF)|0x400) << 13;
			if(expz > exp || (expz == exp && mz > m))
			{
				std::swap(m, mz);
				std::swap(exp, expz);
				if(sub)
					sign = z.data_ & 0x8000;
			}
			int d = exp - expz;
			mz = (d<23) ? ((mz>>d)|((mz&((static_cast<detail::uint32>(1)<<d)-1))!=0)) : 1;
			if(sub)
			{
				m = m - mz;
				if(!m)
					return half(detail::binary, static_cast<unsigned>(half::round_style==std::round_toward_neg_infinity)<<15);
				for(; m<0x800000; m<<=1,--exp) ;
			}
			else
			{
				m += mz;
				i = m >> 24;
				m = (m>>i) | (m&i);
				exp += i;
			}
		}
		if(exp > 30)
			return half(detail::binary, detail::overflow<half::round_style>(sign));
		else if(exp < -10)
			return half(detail::binary, detail::underflow<half::round_style>(sign));
		return half(detail::binary, detail::fixed2half<half::round_style,23,false,false,false>(m, exp-1, sign));
	#endif
	}