exp2 function in SSE version 2 The function exp2() is evaluated by performing argument reduction and then using Chebyshev polynomials to evaluate the function over a restricted range.
| 233 | // reduction and then using Chebyshev polynomials to evaluate the function |
| 234 | // over a restricted range. |
| 235 | inline __m128 sseExp2(__m128 x) |
| 236 | { |
| 237 | // y = exp2( x ) = exp2(integer + fraction) |
| 238 | // = exp2(integer) * exp2(fraction) |
| 239 | // = zf * mexp |
| 240 | |
| 241 | // Compute the largest integer not greater than x, i.e., floor(x) |
| 242 | // Note: cvttps_epi32 simply cast the float value to int. That means cvttps_epi32(-2.7) = -2 |
| 243 | // rather than -3, hence for negative numbers we need to add -1. This ensures that "fraction" |
| 244 | // is always in the range [0, 1). Note that _mm_castps_si128(0xFFFFFFFF) is -1. |
| 245 | // If x is outside the INT_MIN to INT_MAX range, _mm_cvttps_epi32 will return 0x80000000 |
| 246 | // (i.e. INT_MIN, just the sign bit set), which Intel calls the "integer indefinite" value. |
| 247 | // When 1 is subtracted from INT_MIN, it gives INT_MAX. So floor_x is wrong for values |
| 248 | // outside [INT_MIN, INT_MAX] but it's ignored thanks to the checks at the bottom. |
| 249 | // It's also wrong for x=NaN, but again it's ok since the polynomial returns NaN and |
| 250 | // hence the output is NaN, regardless of floor_x. |
| 251 | __m128i floor_x |
| 252 | = _mm_add_epi32( // add a pair of integer arguments |
| 253 | _mm_cvttps_epi32(x), // convert float to int via truncation |
| 254 | _mm_castps_si128( // reinterpret cast float to int |
| 255 | _mm_cmpnle_ps(EZERO, x))); // NOT( EZERO <= x ) ? 0xFFFFFFFF : 0 |
| 256 | |
| 257 | // Compute exp2(floor_x) by moving floor_x to the exponent bits of the floating-point number. |
| 258 | __m128 zf |
| 259 | = _mm_castsi128_ps( // reinterpret cast int to float |
| 260 | _mm_slli_epi32( // left shift by EXP_SHIFT |
| 261 | _mm_add_epi32(floor_x, EBIAS), // add a pair of integer arguments |
| 262 | EXP_SHIFT)); |
| 263 | |
| 264 | __m128 iexp = _mm_cvtepi32_ps(floor_x); // convert floor_x to float |
| 265 | __m128 fraction = _mm_sub_ps(x, iexp); // x - iexp |
| 266 | |
| 267 | // Compute exp2(fraction) using a polynomial approximation. |
| 268 | __m128 mexp |
| 269 | = _mm_add_ps( |
| 270 | _mm_mul_ps( |
| 271 | _mm_add_ps( |
| 272 | _mm_mul_ps( |
| 273 | _mm_add_ps( |
| 274 | _mm_mul_ps( |
| 275 | _mm_add_ps( |
| 276 | _mm_mul_ps(PNEXP4, fraction), |
| 277 | PNEXP3), |
| 278 | fraction), |
| 279 | PNEXP2), |
| 280 | fraction), |
| 281 | PNEXP1), |
| 282 | fraction), |
| 283 | PNEXP0); |
| 284 | |
| 285 | __m128 exp2 = _mm_mul_ps(zf, mexp); // zf * mexp |
| 286 | |
| 287 | // Handle underflow: |
| 288 | // If the (unbiased) exponent of zf is less than -126, the result is smaller than |
| 289 | // the smallest representable floating-point number and an underflow computation is |
| 290 | // potentially happening. When this happens, force the result to zero. |
| 291 | // Note that as described above, floor_x is inaccurate, so the test here uses x. |
| 292 | exp2 = _mm_andnot_ps( // NOT(...) AND exp2 |