Fused multiply add. This function is exact to rounding for all rounding modes. See also:** Documentation for [std::fma](https://en.cppreference.com/w/cpp/numeric/math/fma). \param x first operand \param y second operand \param z third operand \return ( \a x * \a y ) + \a z rounded as one operation. \exception FE_INVALID according to operator*() and operator+() unless any argument is a quiet NaN a
| 2806 | /// \exception FE_INVALID according to operator*() and operator+() unless any argument is a quiet NaN and no argument is a signaling NaN |
| 2807 | /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding the final addition |
| 2808 | inline half fma(half x, half y, half z) |
| 2809 | { |
| 2810 | #ifdef HALF_ARITHMETIC_TYPE |
| 2811 | 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_); |
| 2812 | #if HALF_ENABLE_CPP11_CMATH && FP_FAST_FMA |
| 2813 | return half(detail::binary, detail::float2half<half::round_style>(std::fma(fx, fy, fz))); |
| 2814 | #else |
| 2815 | return half(detail::binary, detail::float2half<half::round_style>(fx*fy+fz)); |
| 2816 | #endif |
| 2817 | #else |
| 2818 | int absx = x.data_ & 0x7FFF, absy = y.data_ & 0x7FFF, absz = z.data_ & 0x7FFF, exp = -15; |
| 2819 | unsigned int sign = (x.data_^y.data_) & 0x8000; |
| 2820 | bool sub = ((sign^z.data_)&0x8000) != 0; |
| 2821 | if(absx >= 0x7C00 || absy >= 0x7C00 || absz >= 0x7C00) |
| 2822 | return (absx>0x7C00 || absy>0x7C00 || absz>0x7C00) ? half(detail::binary, detail::signal(x.data_, y.data_, z.data_)) : |
| 2823 | (absx==0x7C00) ? half(detail::binary, (!absy || (sub && absz==0x7C00)) ? detail::invalid() : (sign|0x7C00)) : |
| 2824 | (absy==0x7C00) ? half(detail::binary, (!absx || (sub && absz==0x7C00)) ? detail::invalid() : (sign|0x7C00)) : z; |
| 2825 | if(!absx || !absy) |
| 2826 | return absz ? z : half(detail::binary, (half::round_style==std::round_toward_neg_infinity) ? (z.data_|sign) : (z.data_&sign)); |
| 2827 | for(; absx<0x400; absx<<=1,--exp) ; |
| 2828 | for(; absy<0x400; absy<<=1,--exp) ; |
| 2829 | detail::uint32 m = static_cast<detail::uint32>((absx&0x3FF)|0x400) * static_cast<detail::uint32>((absy&0x3FF)|0x400); |
| 2830 | int i = m >> 21; |
| 2831 | exp += (absx>>10) + (absy>>10) + i; |
| 2832 | m <<= 3 - i; |
| 2833 | if(absz) |
| 2834 | { |
| 2835 | int expz = 0; |
| 2836 | for(; absz<0x400; absz<<=1,--expz) ; |
| 2837 | expz += absz >> 10; |
| 2838 | detail::uint32 mz = static_cast<detail::uint32>((absz&0x3FF)|0x400) << 13; |
| 2839 | if(expz > exp || (expz == exp && mz > m)) |
| 2840 | { |
| 2841 | std::swap(m, mz); |
| 2842 | std::swap(exp, expz); |
| 2843 | if(sub) |
| 2844 | sign = z.data_ & 0x8000; |
| 2845 | } |
| 2846 | int d = exp - expz; |
| 2847 | mz = (d<23) ? ((mz>>d)|((mz&((static_cast<detail::uint32>(1)<<d)-1))!=0)) : 1; |
| 2848 | if(sub) |
| 2849 | { |
| 2850 | m = m - mz; |
| 2851 | if(!m) |
| 2852 | return half(detail::binary, static_cast<unsigned>(half::round_style==std::round_toward_neg_infinity)<<15); |
| 2853 | for(; m<0x800000; m<<=1,--exp) ; |
| 2854 | } |
| 2855 | else |
| 2856 | { |
| 2857 | m += mz; |
| 2858 | i = m >> 24; |
| 2859 | m = (m>>i) | (m&i); |
| 2860 | exp += i; |
| 2861 | } |
| 2862 | } |
| 2863 | if(exp > 30) |
| 2864 | return half(detail::binary, detail::overflow<half::round_style>(sign)); |
| 2865 | else if(exp < -10) |