Skip to content

Commit 1e94e6d

Browse files
authored
glm::fastPow, glm::fastExp, glm::fastLog polynomial approximation
1 parent 2d4c4b4 commit 1e94e6d

File tree

1 file changed

+95
-16
lines changed

1 file changed

+95
-16
lines changed

glm/gtx/fast_exponential.inl

Lines changed: 95 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,38 @@
22

33
namespace glm
44
{
5-
// fastPow:
5+
// fastPow
66
template<typename genType>
77
GLM_FUNC_QUALIFIER genType fastPow(genType x, genType y)
88
{
99
return exp(y * log(x));
1010
}
11+
12+
template<>
13+
GLM_FUNC_QUALIFIER float fastPow(float x, float y)
14+
{
15+
//negative y always reciprocal, pow(x, -y) = 1 / pow(x, abs(-y))
16+
//when x is lower than 1.0, you can use this formula. pow(x, y) = 1 / glm::fastPow(1 / x, y)
17+
// ex: when x is '0.3'... pow(0.3, y) = 1 / glm::fastPow(1 / 0.3, y)
18+
uint32_t mantissa = 1065353216U | ((*(uint32_t*)&x) & 0x007FFFFF);
19+
float mx = *(float*)&mantissa;
20+
float lnx = y * float(1.44269504088896338700) * ((((*(uint32_t*)&x) >> 23)-127) * float(0.69314718055994528623) + ((((float(-0.056571767549593956) * mx + float(0.4471786103806078)) * mx - float(1.4699399880154467)) * mx + float(2.8211719569953488)) * mx - float(1.7417780977156199)));
21+
uint32_t out = ((127U + uint32_t(lnx)) << 23U);
22+
lnx -= uint32_t(lnx);
23+
return (*(float*)(&out)) * ((float(0.34400110689651969) * lnx + float(0.65104678030290897)) * lnx + float(1.0024760564002857));
24+
}
25+
26+
template<>
27+
GLM_FUNC_QUALIFIER double fastPow(double x, double y)
28+
{
29+
//negative y always reciprocal, pow(x, -y) = 1 / pow(x, abs(-y))
30+
uint64_t mantissa = 4607182418800017408U | ((*(uint64_t*)&x) & 0x000FFFFFFFFFFFFF);
31+
double mx = *(double*)&mantissa;
32+
double lnx = y * double(1.44269504088896338700) * ((((*(uint64_t*)&x) >> 52)-1023) * double(0.69314718055994528623) + ((((double(-0.056571767549593956) * mx + double(0.4471786103806078)) * mx - double(1.4699399880154467)) * mx + double(2.8211719569953488)) * mx - double(1.7417780977156199)));
33+
uint64_t out = ((uint64_t)(1023U + uint64_t(lnx)) << 52U);
34+
lnx -= uint64_t(lnx);
35+
return (*(double*)(&out)) * ((double(0.34400110689651969) * lnx + double(0.65104678030290897)) * lnx + double(1.0024760564002857));
36+
}
1137

1238
template<length_t L, typename T, qualifier Q>
1339
GLM_FUNC_QUALIFIER vec<L, T, Q> fastPow(vec<L, T, Q> const& x, vec<L, T, Q> const& y)
@@ -34,17 +60,30 @@ namespace glm
3460
}
3561

3662
// fastExp
37-
// Note: This function provides accurate results only for value between -1 and 1, else avoid it.
38-
template<typename T>
39-
GLM_FUNC_QUALIFIER T fastExp(T x)
63+
template<>
64+
GLM_FUNC_QUALIFIER float fastExp(float x)
4065
{
41-
// This has a better looking and same performance in release mode than the following code. However, in debug mode it's slower.
42-
// return 1.0f + x * (1.0f + x * 0.5f * (1.0f + x * 0.3333333333f * (1.0f + x * 0.25 * (1.0f + x * 0.2f))));
43-
T x2 = x * x;
44-
T x3 = x2 * x;
45-
T x4 = x3 * x;
46-
T x5 = x4 * x;
47-
return T(1) + x + (x2 * T(0.5)) + (x3 * T(0.1666666667)) + (x4 * T(0.041666667)) + (x5 * T(0.008333333333));
66+
//negative x always reciprocal, exp(-x) = 1 / exp(abs(-x))
67+
uint32_t out = ((127U + uint32_t(x *= 1.44269504088896338700f)) << 23U);
68+
float mx = x - uint32_t(x);
69+
/*
70+
//(accurate) 2 degree polynomial exp2(), interval [0, 1]
71+
return (*(float*)(&out)) * ((float(0.34400110689651969) * mx + float(0.65104678030290897)) * mx + float(1.0024760564002857));
72+
*/
73+
return (*(float*)(&out)) * (mx + 0.95696433397203284f);
74+
}
75+
76+
template<>
77+
GLM_FUNC_QUALIFIER double fastExp(double x)
78+
{
79+
//negative x always reciprocal, exp(-x) = 1 / exp(abs(-x))
80+
uint64_t out = ((uint64_t)(1023U + uint64_t(x *= 1.44269504088896338700)) << 52U);
81+
double mx = x - uint64_t(x);
82+
/*
83+
//(accurate) 2 degree polynomial exp2(), interval [0, 1]
84+
return (*(double*)(&out)) * ((double(0.34400110689651969) * mx + double(0.65104678030290897)) * mx + double(1.0024760564002857));
85+
*/
86+
return (*(double*)(&out)) * (mx + 0.95696433397203284);
4887
}
4988
/* // Try to handle all values of float... but often shower than std::exp, glm::floor and the loop kill the performance
5089
GLM_FUNC_QUALIFIER float fastExp(float x)
@@ -93,14 +132,22 @@ namespace glm
93132
return std::log(x);
94133
}
95134

96-
/* Slower than the VC7.1 function...
135+
// Slower than the VC7.1 function...
136+
template<>
97137
GLM_FUNC_QUALIFIER float fastLog(float x)
98138
{
99-
float y1 = (x - 1.0f) / (x + 1.0f);
100-
float y2 = y1 * y1;
101-
return 2.0f * y1 * (1.0f + y2 * (0.3333333333f + y2 * (0.2f + y2 * 0.1428571429f)));
139+
//x less than 1 always negative log(0.2) = -log(1 / 0.2)
140+
uint32_t mantissa = 1065353216U | ((*(uint32_t*)&x) & 0x007FFFFF);
141+
return (((*(uint32_t*)&x) >> 23)-127) * float(0.69314718055994528623) + ((float(-0.2390307190544787) * (*(float*)&mantissa) + float(1.4033913763229589)) * (*(float*)&mantissa) - float(1.1609366765682689));
142+
}
143+
144+
template<>
145+
GLM_FUNC_QUALIFIER double fastLog(double x)
146+
{
147+
//x less than 1 always negative log(0.2) = -log(1 / 0.2)
148+
uint64_t mantissa = 4607182418800017408U | ((*(uint64_t*)&x) & 0x000FFFFFFFFFFFFF);
149+
return (((*(uint64_t*)&x) >> 52)-1023) * double(0.69314718055994528623) + ((double(-0.2390307190544787) * (*(double*)&mantissa) + double(1.4033913763229589)) * (*(double*)&mantissa) - double(1.1609366765682689));
102150
}
103-
*/
104151

105152
template<length_t L, typename T, qualifier Q>
106153
GLM_FUNC_QUALIFIER vec<L, T, Q> fastLog(vec<L, T, Q> const& x)
@@ -115,6 +162,24 @@ namespace glm
115162
return fastExp(static_cast<genType>(0.69314718055994530941723212145818) * x);
116163
}
117164

165+
template<>
166+
GLM_FUNC_QUALIFIER float fastExp2(float x)
167+
{
168+
//negative x always reciprocal, exp2(-x) = 1 / exp2(abs(-x))
169+
uint32_t out = ((127U + uint32_t(x)) << 23U);
170+
x -= uint32_t(x);
171+
return (*(float*)(&out)) * ((float(0.34400110689651969) * x + float(0.65104678030290897)) * x + float(1.0024760564002857));
172+
}
173+
174+
template<>
175+
GLM_FUNC_QUALIFIER double fastExp2(double x)
176+
{
177+
//negative x always reciprocal, exp2(-x) = 1 / exp2(abs(-x))
178+
uint64_t out = ((uint64_t)(1023U + uint64_t(x)) << 52U);
179+
x -= uint64_t(x);
180+
return (*(double*)(&out)) * ((double(0.34400110689651969) * x + double(0.65104678030290897)) * x + double(1.0024760564002857));
181+
}
182+
118183
template<length_t L, typename T, qualifier Q>
119184
GLM_FUNC_QUALIFIER vec<L, T, Q> fastExp2(vec<L, T, Q> const& x)
120185
{
@@ -127,6 +192,20 @@ namespace glm
127192
{
128193
return fastLog(x) / static_cast<genType>(0.69314718055994530941723212145818);
129194
}
195+
196+
template<>
197+
GLM_FUNC_QUALIFIER float fastLog2(float x)
198+
{
199+
uint32_t mantissa = 1065353216U | ((*(uint32_t*)&x) & 0x007FFFFF);
200+
return (((*(uint32_t*)&x) >> 23)-127) + ((float(-0.34484843300001944) * (*(float*)&mantissa) + float(2.0246657790474698)) * (*(float*)&mantissa) - float(1.674877586071156));
201+
}
202+
203+
template<>
204+
GLM_FUNC_QUALIFIER double fastLog2(double x)
205+
{
206+
uint64_t mantissa = 4607182418800017408U | ((*(uint64_t*)&x) & 0x000FFFFFFFFFFFFF);
207+
return (((*(uint64_t*)&x) >> 52)-1023) + ((double(-0.34484843300001944) * (*(double*)&mantissa) + double(2.0246657790474698)) * (*(double*)&mantissa) - double(1.674877586071156));
208+
}
130209

131210
template<length_t L, typename T, qualifier Q>
132211
GLM_FUNC_QUALIFIER vec<L, T, Q> fastLog2(vec<L, T, Q> const& x)

0 commit comments

Comments
 (0)