• Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

dox/Common/vtkFastNumericConversion.h

Go to the documentation of this file.
00001 /*=========================================================================
00002 
00003   Program:   Visualization Toolkit
00004   Module:    $RCSfile: vtkFastNumericConversion.h,v $
00005   
00006   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
00007   All rights reserved.
00008   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
00009 
00010      This software is distributed WITHOUT ANY WARRANTY; without even
00011      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
00012      PURPOSE.  See the above copyright notice for more information.
00013 
00014 =========================================================================*/
00052 #ifndef __vtkFastNumericConversion_h
00053 #define __vtkFastNumericConversion_h
00054 
00055 #include "vtkObject.h"
00056 
00057 // Use the bit-representation trick only on X86, and only when producing
00058 // optimized code
00059 #if defined(NDEBUG) && (defined i386 || defined _M_IX86)
00060 #define VTK_USE_TRICK
00061 #endif
00062 
00063 // Linux puts the FPU in extended precision. Windows and FreeBSD keep it in
00064 // double precision.  If other operating systems for i386 (Solaris?) behave
00065 // like Linux, add them below.  Special care needs to be taken when dealing
00066 // with extended precision mode because even though we are eventually writing
00067 // out to a double-precision variable to capture the fixed-point or integer
00068 // results, the extra bits maintained in the internal computations disrupt
00069 // the bit-playing that we're doing here.
00070 #if defined(__linux__)
00071 #define VTK_EXT_PREC
00072 #endif
00073 
00074 //#define VTK_TEST_HACK_TO_EMULATE_LINUX_UNDER_WINDOWS
00075 #ifdef VTK_TEST_HACK_TO_EMULATE_LINUX_UNDER_WINDOWS
00076 #define VTK_EXT_PREC
00077 #endif
00078 
00079 
00080 class VTK_COMMON_EXPORT vtkFastNumericConversion : public vtkObject
00081 {
00082 public:
00083   static vtkFastNumericConversion *New();
00084   vtkTypeRevisionMacro(vtkFastNumericConversion, vtkObject);
00085   void PrintSelf(ostream& os, vtkIndent indent);
00086 
00089   int TestQuickFloor(double val);
00090 
00093   int TestSafeFloor(double val);
00094 
00097   int TestRound(double val);
00098 
00101   int TestConvertFixedPointIntPart(double val);
00102 
00105   int TestConvertFixedPointFracPart(double val);
00106 
00107 protected:
00108   //BTX
00114   static inline double BorrowBit() { return 1.5;};
00115 
00117 
00120   static inline double two30()
00121     {
00122       return static_cast<double>(static_cast<unsigned long>(1) << 30);
00123     }
00125 
00127 
00129   static inline double two52() 
00130     {
00131       return (static_cast<unsigned long>(1) << (52-30)) * two30();
00132     }
00134 
00136 
00141   static inline double two51() 
00142     {
00143       return (static_cast<unsigned long>(1) << (51-30)) * two30();
00144     }
00146 
00148 
00151   static inline double two63() 
00152     {
00153       return (static_cast<unsigned long>(1) << (63-60)) * two30() * two30();
00154     }
00156 
00158 
00161   static inline double two62() 
00162     {
00163       return (static_cast<unsigned long>(1) << (62-60)) * two30() * two30();
00164     }
00166 
00167   // Define number of bits of precision for various data types.
00168   // Note: INT_BITS is really 31, (rather than 32, since one of the bits is
00169   // just used for the two's-complement sign), but we say 30 because we don't
00170   // need to be able to handle 31-bit magnitudes correctly. I say that
00171   // because this is used for the QuickFloor code, and the SafeFloor code
00172   // retains an extra bit of fixed point precision which it shifts-out at the
00173   // end, thus reducing the magnitude of integers that it can handle. That's
00174   // an inherent limitation of using SafeFloor to prevent round-ups under any
00175   // circumstances, and there's no need to make QuickFloor handle a wider
00176   // range of numbers than SafeFloor.
00177 #define INT_BITS 30 
00178 #define EXT_BITS 64
00179 #define DBL_BITS 53
00180 
00209 public: 
00210 #ifdef VTK_EXT_PREC
00211   // Compute (0.5 ^ (EXT_BITS-INT_BITS)) as a compile-time constant
00212   static inline double RoundingTieBreaker()
00213     {
00214       return 1.0 / (two30() * (static_cast<unsigned long>(1) << (EXT_BITS - INT_BITS - 30)));
00215     }
00216 #else
00217   // Compute (0.5 ^ (DBL_BITS-INT_BITS)) as a compile-time constant
00218   static inline double RoundingTieBreaker()
00219     {
00220       return 1.0 / (static_cast<unsigned long>(1) << (DBL_BITS - INT_BITS));
00221     }
00222 #endif
00223 
00224 protected:
00226 
00230   static inline double QuickFloorDenormalizer() 
00231     {return two52() * BorrowBit(); };
00233 
00235 
00240   static inline double SafeFloorDenormalizer() 
00241     { return two51() * BorrowBit(); };
00243 
00245 
00248   static inline double QuickExtPrecTempDenormalizer() 
00249     {return two63() * BorrowBit(); };
00251 
00253 
00256   static inline double SafeExtPrecTempDenormalizer() 
00257     {return two62() * BorrowBit(); };
00259 
00260   static inline double QuickRoundAdjust() {return 0.5;};
00261   static inline double SafeRoundAdjust() {return 0.25;};
00262   static inline int SafeFinalShift() {return 1;};
00263 
00264 
00265 #ifdef VTK_WORDS_BIGENDIAN
00266   enum {exponent_pos = 0, mantissa_pos = 1};
00267 #else
00268   enum {exponent_pos = 1, mantissa_pos = 0};
00269 #endif 
00270   //ETX
00271 
00272 public:
00273 
00275 
00286   void SetReservedFracBits(int bits)
00287     {
00288     // Add one to the requested number of fractional bits, to make
00289     // the conversion safe with respect to rounding mode. This is the
00290     // same as the difference between QuickFloor and SafeFloor.
00291     bits++;
00292     unsigned long mtime = this->GetMTime();
00293     this->SetinternalReservedFracBits(bits);
00294     if (mtime != this->GetMTime())
00295       {
00296       this->InternalRebuild();
00297       }
00298     };
00300 
00304   void PerformanceTests(void);    
00305 
00306   //BTX
00308 
00325   inline static int QuickFloor(const double &val)
00326     {
00327 #ifdef VTK_USE_TRICK
00328       union { int i[2]; double d; } u;
00329 #ifdef VTK_EXT_PREC
00330       u.d = (((val - (QuickRoundAdjust() - RoundingTieBreaker())) 
00331               // Push off those extended precision bits
00332               + QuickExtPrecTempDenormalizer()) 
00333              // Pull back the wanted bits into double range
00334              - QuickExtPrecTempDenormalizer()) 
00335         + QuickFloorDenormalizer();
00336 #else // ! VTK_EXT_PREC
00337       u.d = (val - (QuickRoundAdjust() - RoundingTieBreaker())) 
00338         + QuickFloorDenormalizer();
00339 #endif // VTK_EXT_PREC
00340       return u.i[mantissa_pos];
00341 #else // ! VTK_USE_TRICK
00342       return static_cast<int>(val);
00343 #endif // VTK_USE_TRICK
00344     }
00346 
00348 
00362   inline static int SafeFloor(const double &val)
00363     {
00364 #ifdef VTK_USE_TRICK
00365       union { int i[2]; double d; } u;
00366 #ifdef VTK_EXT_PREC
00367       u.d = (((val - SafeRoundAdjust())
00368               + SafeExtPrecTempDenormalizer())
00369              - SafeExtPrecTempDenormalizer())
00370         + SafeFloorDenormalizer();
00371 #else // ! VTK_EXT_PREC
00372       u.d = (val - SafeRoundAdjust()) 
00373         + SafeFloorDenormalizer();
00374 #endif // VTK_EXT_PREC
00375       return u.i[mantissa_pos] >> SafeFinalShift();
00376 #else // ! VTK_USE_TRICK
00377       return static_cast<int>(val);
00378 #endif // VTK_USE_TRICK
00379     }
00381 
00383 
00392   inline static int Round(const double &val)
00393     {
00394 #ifdef VTK_USE_TRICK
00395       union { int i[2]; double d; } u;
00396 #ifdef VTK_EXT_PREC
00397       u.d = ((val 
00398               + QuickExtPrecTempDenormalizer()) 
00399              - QuickExtPrecTempDenormalizer())
00400         + QuickFloorDenormalizer();
00401 #else // ! VTK_EXT_PREC
00402       u.d = val  
00403         + QuickFloorDenormalizer();
00404 #endif // VTK_EXT_PREC
00405     return u.i[mantissa_pos];
00406 #else // ! VTK_USE_TRICK
00407     if (val>=0)
00408       {
00409       return static_cast<int>(val + 0.5);
00410       }
00411     else
00412       {
00413       return static_cast<int>(val - 0.5);
00414       }
00415 #endif // VTK_USE_TRICK
00416     }
00418 
00420 
00423   inline int ConvertFixedPoint(const double &val, int &fracPart)
00424     {
00425       union { int i[2]; double d; } u;
00426 #ifdef VTK_EXT_PREC
00427       u.d = (((val - fixRound)
00428               + this->epTempDenormalizer)
00429              - this->epTempDenormalizer)
00430         + this->fpDenormalizer;
00431 #else // ! VTK_EXT_PREC
00432       u.d = (val - fixRound) 
00433         + this->fpDenormalizer;
00434 #endif // VTK_EXT_PREC
00435     fracPart = (u.i[mantissa_pos] & fracMask) >> 1;
00436     return u.i[mantissa_pos] >> this->internalReservedFracBits;
00437     }
00438   //ETX
00440 
00441 
00442 protected:
00443   //BTX
00444   vtkFastNumericConversion()
00445     {
00446 #ifdef VTK_TEST_HACK_TO_EMULATE_LINUX_UNDER_WINDOWS
00447     _controlfp( _PC_64, MCW_PC );
00448 #endif
00449 
00450     this->fixRound = 0;
00451     this->internalReservedFracBits = 0;
00452     this->fracMask = 0;
00453     this->fpDenormalizer = 0;
00454     this->bare_time = 0;
00455     this->cast_time = 0;
00456     this->convert_time = 0;
00457     this->quickfloor_time = 0;
00458     this->safefloor_time = 0;
00459     this->round_time = 0;
00460     this->InternalRebuild();
00461     };
00462   ~vtkFastNumericConversion() {};
00463   void InternalRebuild(void);
00464 
00465 private:
00466   vtkSetMacro(internalReservedFracBits, int);
00467   vtkGetMacro(internalReservedFracBits, int);
00468   int internalReservedFracBits;
00469   int fracMask;
00470 
00471   // Used when doing fixed point conversions with a certain number of bits
00472   // remaining for the fractional part, as opposed to the pure integer
00473   // flooring
00474   double fpDenormalizer;
00475 
00476   // Used when doing fixed point conversions in extended precision mode
00477   double epTempDenormalizer;
00478 
00479   // Adjustment for rounding based on the number of bits reserved for
00480   // fractional representation
00481   double fixRound;
00482 
00483   double bare_time;
00484   double cast_time;
00485   double convert_time;
00486   double quickfloor_time;
00487   double safefloor_time;
00488   double round_time;
00489   //ETX
00490   
00491   vtkFastNumericConversion(const vtkFastNumericConversion&); // Not implemented
00492   void operator=(const vtkFastNumericConversion&); // Not implemented
00493 };
00494 
00495 #endif

Generated by  doxygen 1.7.1