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
}