Merge pull request #280 from CrHasher/libavfilter_integration
[vuplus_xbmc] / xbmc / utils / MathUtils.h
1 #pragma once
2 /*
3  *      Copyright (C) 2005-2008 Team XBMC
4  *      http://www.xbmc.org
5  *
6  *  This Program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2, or (at your option)
9  *  any later version.
10  *
11  *  This Program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with XBMC; see the file COPYING.  If not, write to
18  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19  *  http://www.gnu.org/copyleft/gpl.html
20  *
21  */
22
23 #include <stdint.h>
24 #include <cassert>
25 #include <climits>
26 #include <cmath>
27
28 /*! \brief Math utility class.
29  Note that the test() routine should return true for all implementations
30
31  See http://ldesoras.free.fr/doc/articles/rounding_en.pdf for an explanation
32  of the technique used on x86.
33  */
34 namespace MathUtils
35 {
36   // GCC does something stupid with optimization on release builds if we try
37   // to assert in these functions
38
39   /*! \brief Round to nearest integer.
40    This routine does fast rounding to the nearest integer.
41    In the case (k + 0.5 for any integer k) we round up to k+1, and in all other
42    instances we should return the nearest integer.
43    Thus, { -1.5, -0.5, 0.5, 1.5 } is rounded to { -1, 0, 1, 2 }.
44    It preserves the property that round(k) - round(k-1) = 1 for all doubles k.
45
46    Make sure MathUtils::test() returns true for each implementation.
47    \sa truncate_int, test
48    */
49   inline int round_int (double x)
50   {
51     assert(x > static_cast<double>(INT_MIN / 2) - 1.0);
52     assert(x < static_cast <double>(INT_MAX / 2) + 1.0);
53     const float round_to_nearest = 0.5f;
54     int i;
55     
56 #ifndef _LINUX
57     __asm
58     {
59       fld x
60       fadd st, st (0)
61       fadd round_to_nearest
62       fistp i
63       sar i, 1
64     }
65 #else
66 #if defined(__powerpc__) || defined(__ppc__)
67     i = floor(x + round_to_nearest);
68 #elif defined(__arm__)
69     //BIG FIXME here (still has issues with rounding -0.5 to zero and not -1)
70     //the asm codes below do the following - trunc(x+0.5)
71     //this isn't correct for negativ x - values - for example 
72     //-1 gets rounded to zero because trunc(-1+0.5) == 0
73     //this is a dirty hack until someone fixes this propably in asm
74     //i've created a trac ticket for this #11767
75     //this hacks decrements the x by 1 if it is negativ
76     // so for -1 it would be trunc(-2+0.5) - which would be correct -1 then ...
77     x = x < 0 ? x-1 : x;
78
79     __asm__ __volatile__ (
80                           "vmov.F64 d1,%[rnd_val]             \n\t" // Copy round_to_nearest into a working register
81                           "vadd.F64 %P[value],%P[value],d1    \n\t" // Add round_to_nearest to value
82                           "vcvt.S32.F64 %[result],%P[value]   \n\t" // Truncate(round towards zero) and store the result
83                           : [result] "=w"(i), [value] "+w"(x)  // Outputs
84                           : [rnd_val] "Dv" (round_to_nearest)  // Inputs
85                           : "d1");                             // Clobbers
86 #else
87     __asm__ __volatile__ (
88                           "fadd %%st\n\t"
89                           "fadd %%st(1)\n\t"
90                           "fistpl %0\n\t"
91                           "sarl $1, %0\n"
92                           : "=m"(i) : "u"(round_to_nearest), "t"(x) : "st"
93                           );
94 #endif
95 #endif
96     return (i);
97   }
98
99   /*! \brief Truncate to nearest integer.
100    This routine does fast truncation to an integer.
101    It should simply drop the fractional portion of the floating point number.
102
103    Make sure MathUtils::test() returns true for each implementation.
104    \sa round_int, test
105    */
106   inline int truncate_int(double x)
107   {
108     assert(x > static_cast<double>(INT_MIN / 2) - 1.0);
109     assert(x < static_cast <double>(INT_MAX / 2) + 1.0);
110
111 #if !defined(__powerpc__) && !defined(__ppc__) && !defined(__arm__)
112     const float round_towards_m_i = -0.5f;
113 #endif
114     int i;
115
116 #ifndef _LINUX
117     __asm
118     {
119       fld x
120       fadd st, st (0)
121       fabs
122       fadd round_towards_m_i
123       fistp i
124       sar i, 1
125     }
126 #else
127 #if defined(__powerpc__) || defined(__ppc__) || defined(__arm__)
128     return (int)x;
129 #else
130     __asm__ __volatile__ (
131                           "fadd %%st\n\t"
132                           "fabs\n\t"
133                           "fadd %%st(1)\n\t"
134                           "fistpl %0\n\t"
135                           "sarl $1, %0\n"
136                           : "=m"(i) : "u"(round_towards_m_i), "t"(x) : "st"
137                           );
138 #endif
139 #endif
140     if (x < 0)
141       i = -i;
142     return (i);
143   }
144
145   inline int64_t abs(int64_t a)
146   {
147     return (a < 0) ? -a : a;
148   }
149
150   inline void hack()
151   {
152     // stupid hack to keep compiler from dropping these
153     // functions as unused
154     MathUtils::round_int(0.0);
155     MathUtils::truncate_int(0.0);
156     MathUtils::abs(0);
157   }
158
159 #if 0
160   /*! \brief test routine for round_int and truncate_int
161    Must return true on all platforms.
162    */
163   inline bool test()
164   {
165     for (int i = -8; i < 8; ++i)
166     {
167       double d = 0.25*i;
168       int r = (i < 0) ? (i - 1) / 4 : (i + 2) / 4;
169       int t = i / 4;
170       if (round_int(d) != r || truncate_int(d) != t)
171         return false;
172     }
173     return true;
174   }
175 #endif
176 } // namespace MathUtils
177