Jamoma API  0.6.0.a19
TTLimits.h
Go to the documentation of this file.
1 /** @file TTLimits.h
2  *
3  * @ingroup foundationLibrary
4  *
5  * @brief Limiting and Constraining Utilities
6 
7  * @details Defines several functions for constraining values within specified boundaries and preventing unwanted values. A variety of behaviors are offered, including clipping, wrapping and folding. Functions for handling <a href="http://en.wikipedia.org/wiki/Denormal_number">denormal values</a> are also defined. @n@n
8  * Exercise caution when using the functions defined here with unsigned values. Negative, signed integers have the potential to become very large numbers when casting to unsigned integers. This can cause errors during a boundary check, such as values clipping to the high boundary instead of the low boundary or numerous iterations of loop to bring a wrapped value back into the acceptable range.
9  *
10  * @author Timothy Place & Tristan Matthews
11  *
12  * @copyright Copyright © 2009, Timothy Place & Tristan Matthews @n
13  * This code is licensed under the terms of the "New BSD License" @n
14  * http://creativecommons.org/licenses/BSD/
15  */
16 
17 #ifndef __TT_LIMITS_H__
18 #define __TT_LIMITS_H__
19 
20 
21 #include <limits>
22 #ifdef TT_PLATFORM_LINUX
23 #include <cmath>
24 #define FLT_MAX std::numeric_limits<float>::max()
25 #define DBL_MAX std::numeric_limits<double>::max()
26 #endif
27 
28 
29 /** Filter out denormaled values, which can make processing extremely slow when present. Calculation is performed in-place.
30  @seealso TTZeroDenormal
31  */
32 template<class T>
33 static void TTZeroDenormal(T& value)
34 {
35 #ifndef TT_DISABLE_DENORMAL_FIX
36  if (!std::isnormal(value))
37  value = 0;
38 #endif
39 }
40 
41 
42 /** @fn T TTAntiDenormal(const T input)
43  @memberof TTLimits.h
44  @brief Filter out denormaled values, which can make processing extremely slow when present.
45  @seealso TTZeroDenormal
46  */
47 template<class T>
48 static T TTAntiDenormal(const T input)
49 {
50  T output = input;
51  TTZeroDenormal(output);
52  return output;
53 
54  // This function used to be implemented using the following algorithm:
55  //
56  // value += kTTAntiDenormalValue;
57  // value -= kTTAntiDenormalValue;
58  //
59  // That algorithm has the advantage of not branching. On the PPC this yielded a dramatic performance improvement.
60  // When benchmarked on Intel processors, however, it was significantly slightly slower (roughly 50%) than the more traditional
61  // branching version, which is now implemented in the TTZeroDenormal() function.
62 }
63 
64 
65 // Macros wrapping the above C++ templates
66 // We do this so that we can easily change the behavior of the routines for squashing denormals.
67 // On the PPC we don't want to waste cycles unneccessarily;
68 // On the Intel processors we can use SSE intrinsics as suggested by Nils Peters (see redmine ticket #799)
69 // or we can use SSE intrinsics to disable denormals on a processor completely, in which case these functions should not waste cycles doing anything;
70 // On ARM processors what happens? We might still need to squash denormals, or maybe there is an option as indicated @ http://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html
71 //
72 // Implementation Note: The __SSE3__ symbol is always defined in Xcode despite any changes you make to compiler settings
73 // On Linux, the __SSE3__ symbol is toggled based on passing the -msse3 flag to GCC
74 // On Windows, the __SSE3__ symbol is always UNdefined, despite any changes you make to compiler settings
75 // So this symbol is completely useless.
76 
77 #if defined ( TT_DISABLE_DENORMAL_FIX ) || defined ( TT_USE_SSE3_INSTRUCTIONS )
78 // #error hooray!
79  // When SSE3 is available, then we rely on the denormals being turned-off using a bit in the processor's control register
80  // http://software.intel.com/sites/products/documentation/studio/composer/en-us/2011/compiler_c/fpops/common/fpops_set_ftz_daz.htm
81 
82  // Do nothing for denormals
83  #define TT_ZERO_DENORMAL
84  #define TT_ANTI_DENORMAL
85 #else
86  #define TT_ZERO_DENORMAL(v) TTZeroDenormal(v)
87  #define TT_ANTI_DENORMAL(v) TTAntiDenormal(v) (v)
88 #endif
89 
90 
91 
92 /** Constrain a number to within a range. Calculation is performed in-place.
93  @seealso TTClip()
94  */
95 template<class T>
96 static void TTLimit(T& value, const T lowBound, const T highBound)
97 {
98  if (value < lowBound)
99  value = lowBound;
100  else if (value > highBound)
101  value = highBound;
102 }
103 
104 
105 /** Constrain a number to within a range.
106  @seealso TTLimit()
107  */
108 template<class T>
109 static T TTClip(const T input, const T lowBound, const T highBound)
110 {
111  T output = input;
112  TTLimit(output, lowBound, highBound);
113  return output;
114 
115  // This function used to be implemented using the following algorithm:
116  //
117  // value = T(((fabs(value - double(low_bound))) + (low_bound + high_bound)) - fabs(value - double(high_bound)));
118  // value /= 2; // relying on the compiler to optimize this, chosen to reduce compiler errors in Xcode
119  // return value;
120  //
121  // That algorithm has the advantage of not branching. On the PPC this yielded a dramatic performance improvement.
122  // When benchmarked on Intel processors, however, it was actually very slightly slower than the more traditional
123  // branching version, which is now implemented in the TTLimit() function.
124 }
125 
126 
127 /** A fast routine for clipping a number to a maximum range. The bottom end of the range is not checked. This routine does not use branching. */
128 template<class T>
129 static void TTLimitMax(T& value, const T highBound)
130 {
131  if (value > highBound)
132  value = highBound;
133 
134  // old algorithm -- see comments in TTClip() for details
135  // value = high_bound - value;
136  // #ifdef TT_PLATFORM_MAC
137  // value += fabs(value);
138  // #else
139  // value = T(value + fabs((double)value));
140  // #endif
141  // value = T(value * 0.5);
142  // value = high_bound - value;
143  // return value;
144 }
145 
146 
147 /** A fast routine for clipping a number on it's low range. The high end of the range is not checked.
148  This routine does not use branching. */
149 template<class T>
150 static void TTLimitMin(T& value, const T lowBound)
151 {
152  if (value < lowBound)
153  value = lowBound;
154 
155  // old algorithm -- see comments in TTClip() for details
156  // value -= low_bound;
157  // #ifdef TT_PLATFORM_MAC
158  // value += fabs(value);
159  // #else
160  // value = T(value + fabs((double)value));
161  // #endif
162  // value = T(value * 0.5);
163  // value = T(value + low_bound);
164  // return value;
165 }
166 
167 
168 /** Limit input to power-of-two values.
169  Non-power-of-two values are increased to the next-highest power-of-two upon return.
170  Only works for ints up to 32-bits.
171  @seealso http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
172  */
173 template<class T>
174 static void TTLimitPowerOfTwo(T& value)
175 {
176  value--;
177  value |= value >> 1;
178  value |= value >> 2;
179  value |= value >> 4;
180  value |= value >> 8;
181  value |= value >> 16;
182  value++;
183 }
184 
185 
186 /** Determine id a value is a power-of-two. Only works for ints. */
187 template<class T>
188 static TTBoolean TTIsPowerOfTwo(T value)
189 {
190  return (value > 0) && ((value & (value-1)) == 0);
191 }
192 
193 
194 /** A fast routine for wrapping around the range once. This is faster than doing an expensive module, where you know the range of the input
195  will not equal or exceed twice the range. */
196 template<class T>
197 static void TTOneWrap(T& value, const T low_bound, const T high_bound)
198 {
199  if ((value >= low_bound) && (value < high_bound))
200  return;
201  else if (value >= high_bound)
202  value = ((low_bound - 1) + (value - high_bound));
203  else
204  value = ((high_bound + 1) - (low_bound - value));
205 }
206 /** This routine wrapping around the range as much as necessary, Nils Peters, Nov. 2008 */
207 template<class T>
208 static void TTInfWrap(T& value, const T low_bound, const T high_bound)
209 {
210  if ((value >= low_bound) && (value < high_bound))
211  return; //nothing to wrap
212  /* let's wrap it */
213  else if (value - low_bound >= 0)
214  value = (fmod((double)value - low_bound, fabs((double)low_bound - high_bound)) + low_bound);
215  else
216  value = (-1.0 * fmod(-1.0 * (value - low_bound), fabs((double)low_bound - high_bound)) + high_bound);
217 }
218 
219 /** This routine folds numbers into the data range, Nils Peters, Nov. 2008 */
220 template<class T>
221 static void TTFold(T& value, const T low_bound, const T high_bound)
222 {
223  double foldRange;
224 
225  if ((value >= low_bound) && (value <= high_bound))
226  return; //nothing to fold
227  else {
228  foldRange = 2 * fabs((double)low_bound - high_bound);
229  value = fabs(remainder(value - low_bound, foldRange)) + low_bound;
230  }
231 }
232 
233 
234 
235 /** A utility for scaling one range of values onto another range of values. */
236 template<class T>
237 static T TTScale(T value, T inlow, T inhigh, T outlow, T outhigh)
238 {
239  double inscale, outdiff;
240 
241  inscale = 1 / (inhigh - inlow);
242  outdiff = outhigh - outlow;
243 
244  value = (value - inlow) * inscale;
245  value = (value * outdiff) + outlow;
246  return(value);
247 }
248 
249 /** Rounding utility. */
250 template<class T>
251 static TTInt32 TTRound(T value)
252 {
253  if (value > 0)
254  return((long)(value + 0.5));
255  else
256  return((long)(value - 0.5));
257 }
258 
259 
260 #if 0
261 #pragma mark -
262 #pragma mark - new code from Tristan
263 #endif
264 
265 
266 template <class T>
267 static T limitMin(T value, T low_bound)
268 {
269  value -= low_bound;
270 #ifdef TT_PLATFORM_MAC
271  value += fabs(value);
272 #else
273  value = T(value + fabs((double)value));
274 #endif
275  value = T(value * 0.5);
276  value = T(value + low_bound);
277  return value;
278 }
279 
280 // template specialization for the unsigned case in limitMin, as per http://redmine.jamoma.org/issues/show/300
281 // otherwise the algorithm can wrap around (below zero) and produce unexpected results
282 
283 template <class T>
284 static TTUInt8 limitMin(TTUInt8 value, TTUInt8 low_bound)
285 {
286  value -= std::min(low_bound, value); // so 0 at lowest
287 #ifdef TT_PLATFORM_MAC
288  value += value;
289 #else
290  value = TTUInt8(value + fabs((double)value));
291 #endif
292  value = TTUInt8(value * 0.5);
293  value = TTUInt8(value + low_bound);
294  return value;
295 }
296 
297 template <class T>
298 static TTUInt16 limitMin(TTUInt16 value, TTUInt16 low_bound)
299 {
300  value -= std::min(low_bound, value); // so 0 at lowest
301 #ifdef TT_PLATFORM_MAC
302  value += value;
303 #else
304  value = TTUInt16(value + fabs((double)value));
305 #endif
306  value = TTUInt16(value * 0.5);
307  value = TTUInt16(value + low_bound);
308  return value;
309 }
310 
311 template <class T>
312 static TTUInt32 limitMin(TTUInt32 value, TTUInt32 low_bound)
313 {
314  value -= std::min(low_bound, value); // so 0 at lowest
315 #ifdef TT_PLATFORM_MAC
316  value += value;
317 #else
318  value = TTUInt32(value + fabs((double)value));
319 #endif
320  value = TTUInt32(value * 0.5);
321  value = TTUInt32(value + low_bound);
322  return value;
323 }
324 
325 
326 template <class T>
327 static TTUInt64 limitMin(TTUInt64 value, TTUInt64 low_bound)
328 {
329  value -= std::min(low_bound, value); // so 0 at lowest
330 #ifdef TT_PLATFORM_MAC
331  value += value;
332 #else
333  value = TTUInt64(value + fabs((double)value));
334 #endif
335  value = TTUInt64(value * 0.5);
336  value = TTUInt64(value + low_bound);
337  return value;
338 }
339 
340 
341 /*
342 int main(int argc, char* argv[])
343 {
344  if (argc != 3) {
345  std::cout << "Usage: limitMin <value> <lowerBound>\n";
346  return 1;
347  }
348 
349  TTUInt16 u, l;
350 
351  std::cout << "Enter a value:\n";
352  u = atoi(argv[1]);
353  std::cout << "u is " << u << std::endl;
354  std::cout << "Enter a lower bound:\n";
355  l = atoi(argv[2]);
356  std::cout << "l is " << l << std::endl;
357 
358  long long iterations = 100000000LL;
359 
360  // execute a lot of times
361  while (iterations--)
362  TTUInt16 v = limitMin<TTUInt16>(u, l);
363 
364  return 0;
365 }
366 */
367 
368 
369 #endif // __TT_LIMITS_H__
370 
bool TTBoolean
Boolean flag, same as Boolean on the Mac.
Definition: TTBase.h:167
std::uint16_t TTUInt16
16 bit unsigned integer
Definition: TTBase.h:176
std::uint64_t TTUInt64
64 bit unsigned integer
Definition: TTBase.h:180
std::int32_t TTInt32
32 bit signed integer
Definition: TTBase.h:177
std::uint32_t TTUInt32
32 bit unsigned integer
Definition: TTBase.h:178
unsigned char TTUInt8
8 bit unsigned integer (char)
Definition: TTBase.h:174