2 * erf function: Copyright (c) 2006 John Maddock
3 * This file is part of FFmpeg.
5 * FFmpeg is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * FFmpeg is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with FFmpeg; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 * Replacements for frequently missing libm functions
30 #include "attributes.h"
32 #include "mathematics.h"
34 #if HAVE_MIPSFPU && HAVE_INLINE_ASM
35 #include "libavutil/mips/libm_mips.h"
36 #endif /* HAVE_MIPSFPU && HAVE_INLINE_ASM*/
40 #define atanf(x) ((float)atan(x))
41 #endif /* HAVE_ATANF */
45 #define atan2f(y, x) ((float)atan2(y, x))
46 #endif /* HAVE_ATAN2F */
50 #define powf(x, y) ((float)pow(x, y))
51 #endif /* HAVE_POWF */
54 static av_always_inline double cbrt(double x)
56 return x < 0 ? -pow(-x, 1.0 / 3.0) : pow(x, 1.0 / 3.0);
58 #endif /* HAVE_CBRT */
61 static av_always_inline float cbrtf(float x)
63 return x < 0 ? -powf(-x, 1.0 / 3.0) : powf(x, 1.0 / 3.0);
65 #endif /* HAVE_CBRTF */
68 static av_always_inline double copysign(double x, double y)
70 uint64_t vx = av_double2int(x);
71 uint64_t vy = av_double2int(y);
72 return av_int2double((vx & UINT64_C(0x7fffffffffffffff)) | (vy & UINT64_C(0x8000000000000000)));
74 #endif /* HAVE_COPYSIGN */
78 #define cosf(x) ((float)cos(x))
79 #endif /* HAVE_COSF */
82 static inline double ff_eval_poly(const double *coeff, int size, double x) {
83 double sum = coeff[size-1];
85 for (i = size-2; i >= 0; --i) {
94 * Algorithm taken from the Boost project, source:
95 * http://www.boost.org/doc/libs/1_46_1/boost/math/special_functions/erf.hpp
96 * Use, modification and distribution are subject to the
97 * Boost Software License, Version 1.0 (see notice below).
98 * Boost Software License - Version 1.0 - August 17th, 2003
99 Permission is hereby granted, free of charge, to any person or organization
100 obtaining a copy of the software and accompanying documentation covered by
101 this license (the "Software") to use, reproduce, display, distribute,
102 execute, and transmit the Software, and to prepare derivative works of the
103 Software, and to permit third-parties to whom the Software is furnished to
104 do so, all subject to the following:
106 The copyright notices in the Software and this entire statement, including
107 the above license grant, this restriction and the following disclaimer,
108 must be included in all copies of the Software, in whole or in part, and
109 all derivative works of the Software, unless such copies or derivative
110 works are solely in the form of machine-executable object code generated by
111 a source language processor.
113 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
114 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
115 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
116 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
117 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
118 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
119 DEALINGS IN THE SOFTWARE.
121 static inline double erf(double z)
123 #ifndef FF_ARRAY_ELEMS
124 #define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
128 /* handle the symmetry: erf(-x) = -erf(x) */
132 /* branch based on range of z, and pick appropriate approximation */
136 return z * 1.125 + z * 0.003379167095512573896158903121545171688;
138 // Maximum Deviation Found: 1.561e-17
139 // Expected Error Term: 1.561e-17
140 // Maximum Relative Change in Control Points: 1.155e-04
141 // Max Error found at double precision = 2.961182e-17
143 static const double y = 1.044948577880859375;
144 static const double p[] = {
145 0.0834305892146531832907,
146 -0.338165134459360935041,
147 -0.0509990735146777432841,
148 -0.00772758345802133288487,
149 -0.000322780120964605683831,
151 static const double q[] = {
153 0.455004033050794024546,
154 0.0875222600142252549554,
155 0.00858571925074406212772,
156 0.000370900071787748000569,
159 return z * (y + ff_eval_poly(p, FF_ARRAY_ELEMS(p), zz) / ff_eval_poly(q, FF_ARRAY_ELEMS(q), zz));
161 /* here onwards compute erfc */
163 // Maximum Deviation Found: 3.702e-17
164 // Expected Error Term: 3.702e-17
165 // Maximum Relative Change in Control Points: 2.845e-04
166 // Max Error found at double precision = 4.841816e-17
167 static const double y = 0.405935764312744140625;
168 static const double p[] = {
169 -0.098090592216281240205,
170 0.178114665841120341155,
171 0.191003695796775433986,
172 0.0888900368967884466578,
173 0.0195049001251218801359,
174 0.00180424538297014223957,
176 static const double q[] = {
178 1.84759070983002217845,
179 1.42628004845511324508,
180 0.578052804889902404909,
181 0.12385097467900864233,
182 0.0113385233577001411017,
183 0.337511472483094676155e-5,
185 result = y + ff_eval_poly(p, FF_ARRAY_ELEMS(p), z - 0.5) / ff_eval_poly(q, FF_ARRAY_ELEMS(q), z - 0.5);
186 result *= exp(-z * z) / z;
190 // Max Error found at double precision = 6.599585e-18
191 // Maximum Deviation Found: 3.909e-18
192 // Expected Error Term: 3.909e-18
193 // Maximum Relative Change in Control Points: 9.886e-05
194 static const double y = 0.50672817230224609375;
195 static const double p[] = {
196 -0.0243500476207698441272,
197 0.0386540375035707201728,
198 0.04394818964209516296,
199 0.0175679436311802092299,
200 0.00323962406290842133584,
201 0.000235839115596880717416,
203 static const double q[] = {
205 1.53991494948552447182,
206 0.982403709157920235114,
207 0.325732924782444448493,
208 0.0563921837420478160373,
209 0.00410369723978904575884,
211 result = y + ff_eval_poly(p, FF_ARRAY_ELEMS(p), z - 1.5) / ff_eval_poly(q, FF_ARRAY_ELEMS(q), z - 1.5);
212 result *= exp(-z * z) / z;
216 // Maximum Deviation Found: 1.512e-17
217 // Expected Error Term: 1.512e-17
218 // Maximum Relative Change in Control Points: 2.222e-04
219 // Max Error found at double precision = 2.062515e-17
220 static const double y = 0.5405750274658203125;
221 static const double p[] = {
222 0.00295276716530971662634,
223 0.0137384425896355332126,
224 0.00840807615555585383007,
225 0.00212825620914618649141,
226 0.000250269961544794627958,
227 0.113212406648847561139e-4,
229 static const double q[] = {
231 1.04217814166938418171,
232 0.442597659481563127003,
233 0.0958492726301061423444,
234 0.0105982906484876531489,
235 0.000479411269521714493907,
237 result = y + ff_eval_poly(p, FF_ARRAY_ELEMS(p), z - 3.5) / ff_eval_poly(q, FF_ARRAY_ELEMS(q), z - 3.5);
238 result *= exp(-z * z) / z;
241 /* differ from Boost here, the claim of underflow of erfc(x) past 5.8 is
242 * slightly incorrect, change to 5.92
243 * (really somewhere between 5.9125 and 5.925 is when it saturates) */
245 // Max Error found at double precision = 2.997958e-17
246 // Maximum Deviation Found: 2.860e-17
247 // Expected Error Term: 2.859e-17
248 // Maximum Relative Change in Control Points: 1.357e-05
249 static const double y = 0.5579090118408203125;
250 static const double p[] = {
251 0.00628057170626964891937,
252 0.0175389834052493308818,
253 -0.212652252872804219852,
254 -0.687717681153649930619,
255 -2.5518551727311523996,
256 -3.22729451764143718517,
257 -2.8175401114513378771,
259 static const double q[] = {
261 2.79257750980575282228,
262 11.0567237927800161565,
263 15.930646027911794143,
264 22.9367376522880577224,
265 13.5064170191802889145,
266 5.48409182238641741584,
268 result = y + ff_eval_poly(p, FF_ARRAY_ELEMS(p), 1 / z) / ff_eval_poly(q, FF_ARRAY_ELEMS(q), 1 / z);
269 result *= exp(-z * z) / z;
272 /* handle the nan case, but don't use isnan for max portability */
275 /* finally return saturated result */
279 #endif /* HAVE_ERF */
283 #define expf(x) ((float)exp(x))
284 #endif /* HAVE_EXPF */
288 #define exp2(x) exp((x) * M_LN2)
289 #endif /* HAVE_EXP2 */
293 #define exp2f(x) ((float)exp2(x))
294 #endif /* HAVE_EXP2F */
298 /* Note: these do not follow the BSD/Apple/GNU convention of returning -1 for
299 -Inf, +1 for Inf, 0 otherwise, but merely follow the POSIX/ISO mandated spec of
300 returning a non-zero value for +/-Inf, 0 otherwise. */
301 static av_always_inline av_const int avpriv_isinff(float x)
303 uint32_t v = av_float2int(x);
304 if ((v & 0x7f800000) != 0x7f800000)
306 return !(v & 0x007fffff);
309 static av_always_inline av_const int avpriv_isinf(double x)
311 uint64_t v = av_double2int(x);
312 if ((v & 0x7ff0000000000000) != 0x7ff0000000000000)
314 return !(v & 0x000fffffffffffff);
318 (sizeof(x) == sizeof(float) \
321 #endif /* HAVE_ISINF */
324 static av_always_inline av_const int avpriv_isnanf(float x)
326 uint32_t v = av_float2int(x);
327 if ((v & 0x7f800000) != 0x7f800000)
329 return v & 0x007fffff;
332 static av_always_inline av_const int avpriv_isnan(double x)
334 uint64_t v = av_double2int(x);
335 if ((v & 0x7ff0000000000000) != 0x7ff0000000000000)
337 return (v & 0x000fffffffffffff) && 1;
341 (sizeof(x) == sizeof(float) \
344 #endif /* HAVE_ISNAN */
347 static av_always_inline av_const int avpriv_isfinitef(float x)
349 uint32_t v = av_float2int(x);
350 return (v & 0x7f800000) != 0x7f800000;
353 static av_always_inline av_const int avpriv_isfinite(double x)
355 uint64_t v = av_double2int(x);
356 return (v & 0x7ff0000000000000) != 0x7ff0000000000000;
359 #define isfinite(x) \
360 (sizeof(x) == sizeof(float) \
361 ? avpriv_isfinitef(x) \
362 : avpriv_isfinite(x))
363 #endif /* HAVE_ISFINITE */
366 static inline av_const double hypot(double x, double y)
372 if (isinf(x) || isinf(y))
373 return av_int2double(0x7ff0000000000000);
374 if (x == 0 || y == 0)
383 return x*sqrt(1 + y*y);
385 #endif /* HAVE_HYPOT */
389 #define ldexpf(x, exp) ((float)ldexp(x, exp))
390 #endif /* HAVE_LDEXPF */
394 #define llrint(x) ((long long)rint(x))
395 #endif /* HAVE_LLRINT */
399 #define llrintf(x) ((long long)rint(x))
400 #endif /* HAVE_LLRINT */
404 #define log2(x) (log(x) * 1.44269504088896340736)
405 #endif /* HAVE_LOG2 */
409 #define log2f(x) ((float)log2(x))
410 #endif /* HAVE_LOG2F */
414 #define log10f(x) ((float)log10(x))
415 #endif /* HAVE_LOG10F */
419 #define sinf(x) ((float)sin(x))
420 #endif /* HAVE_SINF */
423 static inline double rint(double x)
425 return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5);
427 #endif /* HAVE_RINT */
430 static av_always_inline av_const long int lrint(double x)
434 #endif /* HAVE_LRINT */
437 static av_always_inline av_const long int lrintf(float x)
439 return (int)(rint(x));
441 #endif /* HAVE_LRINTF */
444 static av_always_inline av_const double round(double x)
446 return (x > 0) ? floor(x + 0.5) : ceil(x - 0.5);
448 #endif /* HAVE_ROUND */
451 static av_always_inline av_const float roundf(float x)
453 return (x > 0) ? floor(x + 0.5) : ceil(x - 0.5);
455 #endif /* HAVE_ROUNDF */
458 static av_always_inline av_const double trunc(double x)
460 return (x > 0) ? floor(x) : ceil(x);
462 #endif /* HAVE_TRUNC */
465 static av_always_inline av_const float truncf(float x)
467 return (x > 0) ? floor(x) : ceil(x);
469 #endif /* HAVE_TRUNCF */
471 #endif /* AVUTIL_LIBM_H */