VTK
vtkFastNumericConversion.h
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Visualization Toolkit
4  Module: vtkFastNumericConversion.h
5 
6  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7  All rights reserved.
8  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10  This software is distributed WITHOUT ANY WARRANTY; without even
11  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12  PURPOSE. See the above copyright notice for more information.
13 
14 =========================================================================*/
52 #ifndef __vtkFastNumericConversion_h
53 #define __vtkFastNumericConversion_h
54 
55 #include "vtkObject.h"
56 
57 // Use the bit-representation trick only on X86, and only when producing
58 // optimized code
59 #if defined(NDEBUG) && (defined i386 || defined _M_IX86)
60 #define VTK_USE_TRICK
61 #endif
62 
63 // Linux puts the FPU in extended precision. Windows and FreeBSD keep it in
64 // double precision. If other operating systems for i386 (Solaris?) behave
65 // like Linux, add them below. Special care needs to be taken when dealing
66 // with extended precision mode because even though we are eventually writing
67 // out to a double-precision variable to capture the fixed-point or integer
68 // results, the extra bits maintained in the internal computations disrupt
69 // the bit-playing that we're doing here.
70 #if defined(__linux__)
71 #define VTK_EXT_PREC
72 #endif
73 
74 //#define VTK_TEST_HACK_TO_EMULATE_LINUX_UNDER_WINDOWS
75 #ifdef VTK_TEST_HACK_TO_EMULATE_LINUX_UNDER_WINDOWS
76 #define VTK_EXT_PREC
77 #endif
78 
79 
81 {
82 public:
83  static vtkFastNumericConversion *New();
85  void PrintSelf(ostream& os, vtkIndent indent);
86 
87  int TestQuickFloor(double val)
88  {
90  }
91 
92  int TestSafeFloor(double val)
93  {
95  }
96 
97  int TestRound(double val)
98  {
100  }
101 
103  {
104  int frac;
105  return ConvertFixedPoint(val, frac);
106  }
107 
109  {
110  int frac;
111  ConvertFixedPoint(val, frac);
112  return frac;
113  }
114 
115 protected:
116  //BTX
122  static inline double BorrowBit() { return 1.5;};
123 
125 
128  static inline double two30()
129  {
130  return static_cast<double>(static_cast<unsigned long>(1) << 30);
131  }
133 
135 
137  static inline double two52()
138  {
139  return (static_cast<unsigned long>(1) << (52-30)) * two30();
140  }
142 
144 
149  static inline double two51()
150  {
151  return (static_cast<unsigned long>(1) << (51-30)) * two30();
152  }
154 
156 
159  static inline double two63()
160  {
161  return (static_cast<unsigned long>(1) << (63-60)) * two30() * two30();
162  }
164 
166 
169  static inline double two62()
170  {
171  return (static_cast<unsigned long>(1) << (62-60)) * two30() * two30();
172  }
174 
175  // Define number of bits of precision for various data types.
176  // Note: INT_BITS is really 31, (rather than 32, since one of the bits is
177  // just used for the two's-complement sign), but we say 30 because we don't
178  // need to be able to handle 31-bit magnitudes correctly. I say that
179  // because this is used for the QuickFloor code, and the SafeFloor code
180  // retains an extra bit of fixed point precision which it shifts-out at the
181  // end, thus reducing the magnitude of integers that it can handle. That's
182  // an inherent limitation of using SafeFloor to prevent round-ups under any
183  // circumstances, and there's no need to make QuickFloor handle a wider
184  // range of numbers than SafeFloor.
185 #define INT_BITS 30
186 #define EXT_BITS 64
187 #define DBL_BITS 53
188 
190 
218 public:
219 #ifdef VTK_EXT_PREC
220  // Compute (0.5 ^ (EXT_BITS-INT_BITS)) as a compile-time constant
221  static inline double RoundingTieBreaker()
222  {
223  return 1.0 / (two30() * (static_cast<unsigned long>(1) << (EXT_BITS - INT_BITS - 30)));
224  }
225 #else
226  // Compute (0.5 ^ (DBL_BITS-INT_BITS)) as a compile-time constant
227  static inline double RoundingTieBreaker()
228  {
229  return 1.0 / (static_cast<unsigned long>(1) << (DBL_BITS - INT_BITS));
230  }
231 #endif
232 
233 
234 protected:
236 
240  static inline double QuickFloorDenormalizer()
241  {return two52() * BorrowBit(); };
243 
245 
250  static inline double SafeFloorDenormalizer()
251  { return two51() * BorrowBit(); };
253 
255 
258  static inline double QuickExtPrecTempDenormalizer()
259  {return two63() * BorrowBit(); };
261 
263 
266  static inline double SafeExtPrecTempDenormalizer()
267  {return two62() * BorrowBit(); };
269 
270  static inline double QuickRoundAdjust() {return 0.5;};
271  static inline double SafeRoundAdjust() {return 0.25;};
272  static inline int SafeFinalShift() {return 1;};
273 
274 
275 #ifdef VTK_WORDS_BIGENDIAN
276  enum {exponent_pos = 0, mantissa_pos = 1};
277 #else
278  enum {exponent_pos = 1, mantissa_pos = 0};
279 #endif
280  //ETX
281 
282 public:
283 
285 
296  void SetReservedFracBits(int bits)
297  {
298  // Add one to the requested number of fractional bits, to make
299  // the conversion safe with respect to rounding mode. This is the
300  // same as the difference between QuickFloor and SafeFloor.
301  bits++;
302  unsigned long mtime = this->GetMTime();
303  this->SetinternalReservedFracBits(bits);
304  if (mtime != this->GetMTime())
305  {
306  this->InternalRebuild();
307  }
308  };
310 
311  //BTX
313 
330  inline static int QuickFloor(const double &val)
331  {
332 #ifdef VTK_USE_TRICK
333  union { int i[2]; double d; } u;
334 #ifdef VTK_EXT_PREC
335  u.d = (((val - (QuickRoundAdjust() - RoundingTieBreaker()))
336  // Push off those extended precision bits
337  + QuickExtPrecTempDenormalizer())
338  // Pull back the wanted bits into double range
339  - QuickExtPrecTempDenormalizer())
340  + QuickFloorDenormalizer();
341 #else // ! VTK_EXT_PREC
342  u.d = (val - (QuickRoundAdjust() - RoundingTieBreaker()))
343  + QuickFloorDenormalizer();
344 #endif // VTK_EXT_PREC
345  return u.i[mantissa_pos];
346 #else // ! VTK_USE_TRICK
347  return static_cast<int>(val);
348 #endif // VTK_USE_TRICK
349  }
351 
353 
367  inline static int SafeFloor(const double &val)
368  {
369 #ifdef VTK_USE_TRICK
370  union { int i[2]; double d; } u;
371 #ifdef VTK_EXT_PREC
372  u.d = (((val - SafeRoundAdjust())
373  + SafeExtPrecTempDenormalizer())
374  - SafeExtPrecTempDenormalizer())
375  + SafeFloorDenormalizer();
376 #else // ! VTK_EXT_PREC
377  u.d = (val - SafeRoundAdjust())
378  + SafeFloorDenormalizer();
379 #endif // VTK_EXT_PREC
380  return u.i[mantissa_pos] >> SafeFinalShift();
381 #else // ! VTK_USE_TRICK
382  return static_cast<int>(val);
383 #endif // VTK_USE_TRICK
384  }
386 
388 
397  inline static int Round(const double &val)
398  {
399 #ifdef VTK_USE_TRICK
400  union { int i[2]; double d; } u;
401 #ifdef VTK_EXT_PREC
402  u.d = ((val
403  + QuickExtPrecTempDenormalizer())
404  - QuickExtPrecTempDenormalizer())
405  + QuickFloorDenormalizer();
406 #else // ! VTK_EXT_PREC
407  u.d = val
408  + QuickFloorDenormalizer();
409 #endif // VTK_EXT_PREC
410  return u.i[mantissa_pos];
411 #else // ! VTK_USE_TRICK
412  if (val>=0)
413  {
414  return static_cast<int>(val + 0.5);
415  }
416  else
417  {
418  return static_cast<int>(val - 0.5);
419  }
420 #endif // VTK_USE_TRICK
421  }
423 
425 
428  inline int ConvertFixedPoint(const double &val, int &fracPart)
429  {
430  union { int i[2]; double d; } u;
431 #ifdef VTK_EXT_PREC
432  u.d = (((val - fixRound)
433  + this->epTempDenormalizer)
434  - this->epTempDenormalizer)
435  + this->fpDenormalizer;
436 #else // ! VTK_EXT_PREC
437  u.d = (val - fixRound)
438  + this->fpDenormalizer;
439 #endif // VTK_EXT_PREC
440  fracPart = (u.i[mantissa_pos] & fracMask) >> 1;
441  return u.i[mantissa_pos] >> this->internalReservedFracBits;
442  }
443  //ETX
445 
446 
447 protected:
448  //BTX
450  {
451 #ifdef VTK_TEST_HACK_TO_EMULATE_LINUX_UNDER_WINDOWS
452  _controlfp( _PC_64, MCW_PC );
453 #endif
454 
455  this->fixRound = 0;
456  this->internalReservedFracBits = 0;
457  this->fracMask = 0;
458  this->fpDenormalizer = 0;
459  };
461  void InternalRebuild(void);
462 
463 private:
464  vtkSetMacro(internalReservedFracBits, int);
465  vtkGetMacro(internalReservedFracBits, int);
466  int internalReservedFracBits;
467  int fracMask;
468 
469  // Used when doing fixed point conversions with a certain number of bits
470  // remaining for the fractional part, as opposed to the pure integer
471  // flooring
472  double fpDenormalizer;
473 
474  // Used when doing fixed point conversions in extended precision mode
475  double epTempDenormalizer;
476 
477  // Adjustment for rounding based on the number of bits reserved for
478  // fractional representation
479  double fixRound;
480  //ETX
481 
482  vtkFastNumericConversion(const vtkFastNumericConversion&); // Not implemented
483  void operator=(const vtkFastNumericConversion&); // Not implemented
484 };
485 
486 #endif
static int QuickFloor(const double &val)
int TestConvertFixedPointFracPart(double val)
abstract base class for most VTK objects
Definition: vtkObject.h:60
int TestConvertFixedPointIntPart(double val)
virtual void PrintSelf(ostream &os, vtkIndent indent)
virtual unsigned long GetMTime()
a simple class to control print indentation
Definition: vtkIndent.h:37
#define INT_BITS
Enables fast conversion of floating point to fixed point.
#define VTK_COMMON_EXPORT
#define DBL_BITS
static int SafeFloor(const double &val)
int ConvertFixedPoint(const double &val, int &fracPart)
static double QuickExtPrecTempDenormalizer()
#define EXT_BITS
static int Round(const double &val)
static vtkObject * New()