4namespace ftz {
namespace detail {
namespace math {
5 struct approx_result {
unsigned int bits, valid; };
6 native_constexpr
inline unsigned int approx_flush(
unsigned int x) {
7 return (x & 0x7f800000u) == 0u ? x & 0x80000000u : x;
9 native_constexpr
inline bool approx_finite(
unsigned int x) {
return (x & 0x7fffffffu) < 0x7f800000u; }
12 native_constexpr
inline approx_result approx_scale(
unsigned int word,
int shift,
unsigned int sign) {
13 approx_result r; r.bits=0u; r.valid=1u;
14 int exponent=(int)(word>>23)+shift;
15 if (exponent>=255) { r.valid=0u;
return r; }
17 r.bits=sign | ((exponent==0 && (word&0x007fffffu)==0x007fffffu) ? 0x00800000u : 0u);
20 r.bits=sign | ((
unsigned int)exponent<<23) | (word&0x007fffffu);
26 native_constexpr
inline approx_result approx_apply(
unsigned int operation,
unsigned int a,
unsigned int b) {
27 approx_result invalid; invalid.bits=invalid.valid=0u;
28 if (operation>3u || !approx_finite(a) ||
29 (operation==3u ? !approx_finite(b) : b!=0u))
return invalid;
30 a=approx_flush(a); b=approx_flush(b);
31 unsigned int aa=a&0x7fffffffu, bb=b&0x7fffffffu;
32 unsigned int sign=a&0x80000000u;
33 if (operation==0u && aa==0u)
return invalid;
34 if ((operation==1u || operation==2u) && sign!=0u && aa!=0u)
return invalid;
35 if (operation==2u && aa==0u)
return invalid;
36 if (operation==3u && bb==0u)
return invalid;
37 if ((operation==1u || operation==3u) && aa==0u) {
39 result.bits=operation==1u ? a : (a^b)&0x80000000u;
43 int exponent_a=(int)(aa>>23)-127;
44 unsigned int ma=0x3f800000u | (aa&0x007fffffu);
47 if (operation==0u || operation==3u) {
48 unsigned int mb=operation==3u ? 0x3f800000u|(bb&0x007fffffu) : ma;
49 float m=fp32_decode(mb);
50 r=fp32_decode(0x7ef311c3u-mb);
51 e=fp32_fma<false>(-m,r,1.0f); r=fp32_fma<false>(r,e,r);
52 e=fp32_fma<false>(-m,r,1.0f); r=fp32_fma<false>(r,e,r);
53 e=fp32_fma<false>(-m,r,1.0f); r=fp32_fma<false>(r,e,r);
55 r=fp32_mul<false>(fp32_decode(ma),r);
56 shift=exponent_a-((int)(bb>>23)-127); sign=(a^b)&0x80000000u;
57 }
else shift=-exponent_a;
59 unsigned int parity=1u-((aa>>23)&1u);
60 unsigned int mword=ma+(parity<<23);
61 float m=fp32_decode(mword);
62 r=fp32_decode(0x5f375a86u-(mword>>1));
63 p=fp32_mul<false>(m,r); e=fp32_fma<false>(-p,r,1.0f); h=fp32_mul<false>(0.5f,r); r=fp32_fma<false>(h,e,r);
64 p=fp32_mul<false>(m,r); e=fp32_fma<false>(-p,r,1.0f); h=fp32_mul<false>(0.5f,r); r=fp32_fma<false>(h,e,r);
65 p=fp32_mul<false>(m,r); e=fp32_fma<false>(-p,r,1.0f); h=fp32_mul<false>(0.5f,r); r=fp32_fma<false>(h,e,r);
66 shift=(exponent_a-(int)parity)/2;
67 if (operation==1u) r=fp32_mul<false>(m,r);
else shift=-shift;
70 return approx_scale(fp32_encode(r),shift,sign);
72 native_constexpr
inline approx_result approx_reciprocal(
unsigned int a) {
return approx_apply(0u,a,0u); }
73 native_constexpr
inline approx_result approx_sqrt(
unsigned int a) {
return approx_apply(1u,a,0u); }
74 native_constexpr
inline approx_result approx_rsqrt(
unsigned int a) {
return approx_apply(2u,a,0u); }
75 native_constexpr
inline approx_result approx_divide(
unsigned int a,
unsigned int b) {
return approx_apply(3u,a,b); }
77 native_constexpr
inline approx_result approx_div_prechecked_words(
unsigned int a,
unsigned int b) {
78 unsigned int aa=a&0x7fffffffu, bb=b&0x7fffffffu;
79 approx_result result; result.bits=result.valid=0u;
80 if (bb==0u)
return result;
81 unsigned int sign=(a^b)&0x80000000u;
82 if (aa==0u) { result.bits=sign; result.valid=1u;
return result; }
83 unsigned int ma=0x3f800000u|(aa&0x007fffffu);
84 unsigned int mb=0x3f800000u|(bb&0x007fffffu);
85 float m=fp32_decode(mb);
86 float r=fp32_decode(0x7ef311c3u-mb);
87 float e=fp32_fma<false>(-m,r,1.0f); r=fp32_fma<false>(r,e,r);
88 e=fp32_fma<false>(-m,r,1.0f); r=fp32_fma<false>(r,e,r);
89 e=fp32_fma<false>(-m,r,1.0f); r=fp32_fma<false>(r,e,r);
90 r=fp32_mul<false>(fp32_decode(ma),r);
91 int shift=((int)(aa>>23)-127)-((
int)(bb>>23)-127);
92 return approx_scale(fp32_encode(r),shift,sign);
94 native_constexpr
inline approx_result approx_sqrt_prechecked_words(
unsigned int a) {
95 unsigned int aa=a&0x7fffffffu;
96 approx_result result; result.bits=result.valid=0u;
97 if (aa==0u) { result.bits=a; result.valid=1u;
return result; }
98 if ((a&0x80000000u)!=0u)
return result;
99 unsigned int ma=0x3f800000u|(aa&0x007fffffu);
100 unsigned int parity=1u-((aa>>23)&1u);
101 unsigned int mword=ma+(parity<<23);
102 float m=fp32_decode(mword);
103 float r=fp32_decode(0x5f375a86u-(mword>>1));
104 float p=fp32_mul<false>(m,r), e=fp32_fma<false>(-p,r,1.0f), h=fp32_mul<false>(0.5f,r); r=fp32_fma<false>(h,e,r);
105 p=fp32_mul<false>(m,r); e=fp32_fma<false>(-p,r,1.0f); h=fp32_mul<false>(0.5f,r); r=fp32_fma<false>(h,e,r);
106 p=fp32_mul<false>(m,r); e=fp32_fma<false>(-p,r,1.0f); h=fp32_mul<false>(0.5f,r); r=fp32_fma<false>(h,e,r);
107 r=fp32_mul<false>(m,r);
108 int shift=(((int)(aa>>23)-127)-(int)parity)/2;
109 return approx_scale(fp32_encode(r),shift,0u);
FP32 bit casts, precise arithmetic and signed flush-to-zero normalization.