/*=====================================================================* * Copyright (C) 2011 Paul Mineiro * * All rights reserved. * * * * Redistribution and use in source and binary forms, with * * or without modification, are permitted provided that the * * following conditions are met: * * * * * Redistributions of source code must retain the * * above copyright notice, this list of conditions and * * the following disclaimer. * * * * * Redistributions in binary form must reproduce the * * above copyright notice, this list of conditions and * * the following disclaimer in the documentation and/or * * other materials provided with the distribution. * * * * * Neither the name of Paul Mineiro nor the names * * of other contributors may be used to endorse or promote * * products derived from this software without specific * * prior written permission. * * * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER * * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * * POSSIBILITY OF SUCH DAMAGE. * * * * Contact: Paul Mineiro * *=====================================================================*/ #ifndef __FAST_EXP_H_ #define __FAST_EXP_H_ #include #include "cast.h" #include "sse.h" // Underflow of exponential is common practice in numerical routines, // so handle it here. static inline float fastpow2 (float p) { float offset = (p < 0) ? 1.0f : 0.0f; float clipp = (p < -126) ? -126.0f : p; int w = clipp; float z = clipp - w + offset; union { uint32_t i; float f; } v = { cast_uint32_t ( (1 << 23) * (clipp + 121.2740575f + 27.7280233f / (4.84252568f - z) - 1.49012907f * z) ) }; return v.f; } static inline float fastexp (float p) { return fastpow2 (1.442695040f * p); } static inline float fasterpow2 (float p) { float clipp = (p < -126) ? -126.0f : p; union { uint32_t i; float f; } v = { cast_uint32_t ( (1 << 23) * (clipp + 126.94269504f) ) }; return v.f; } static inline float fasterexp (float p) { return fasterpow2 (1.442695040f * p); } #ifdef __SSE2__ static inline v4sf vfastpow2 (const v4sf p) { v4sf ltzero = _mm_cmplt_ps (p, v4sfl (0.0f)); v4sf offset = _mm_and_ps (ltzero, v4sfl (1.0f)); v4sf lt126 = _mm_cmplt_ps (p, v4sfl (-126.0f)); v4sf clipp = _mm_or_ps (_mm_andnot_ps (lt126, p), _mm_and_ps (lt126, v4sfl (-126.0f))); v4si w = v4sf_to_v4si (clipp); v4sf z = clipp - v4si_to_v4sf (w) + offset; const v4sf c_121_2740838 = v4sfl (121.2740575f); const v4sf c_27_7280233 = v4sfl (27.7280233f); const v4sf c_4_84252568 = v4sfl (4.84252568f); const v4sf c_1_49012907 = v4sfl (1.49012907f); union { v4si i; v4sf f; } v = { v4sf_to_v4si ( v4sfl (1 << 23) * (clipp + c_121_2740838 + c_27_7280233 / (c_4_84252568 - z) - c_1_49012907 * z) ) }; return v.f; } static inline v4sf vfastexp (const v4sf p) { const v4sf c_invlog_2 = v4sfl (1.442695040f); return vfastpow2 (c_invlog_2 * p); } static inline v4sf vfasterpow2 (const v4sf p) { const v4sf c_126_94269504 = v4sfl (126.94269504f); v4sf lt126 = _mm_cmplt_ps (p, v4sfl (-126.0f)); v4sf clipp = _mm_or_ps (_mm_andnot_ps (lt126, p), _mm_and_ps (lt126, v4sfl (-126.0f))); union { v4si i; v4sf f; } v = { v4sf_to_v4si (v4sfl (1 << 23) * (clipp + c_126_94269504)) }; return v.f; } static inline v4sf vfasterexp (const v4sf p) { const v4sf c_invlog_2 = v4sfl (1.442695040f); return vfasterpow2 (c_invlog_2 * p); } #endif //__SSE2__ #endif // __FAST_EXP_H_