MCPcopy Create free account
hub / github.com/AcademySoftwareFoundation/OpenColorIO / sseExp2

Function sseExp2

src/OpenColorIO/SSE.h:235–307  ·  view source on GitHub ↗

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.

Source from the content-addressed store, hash-verified

233// reduction and then using Chebyshev polynomials to evaluate the function
234// over a restricted range.
235inline __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

Callers 3

ssePowerFunction · 0.85
applyMethod · 0.85
EvaluateExp2Function · 0.85

Calls 1

sseSelectFunction · 0.85

Tested by 1

EvaluateExp2Function · 0.68