Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

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 =========================================================================*/
00049 #ifndef __vtkFastNumericConversion_h
00050 #define __vtkFastNumericConversion_h
00051 
00052 #include "vtkObject.h"
00053 
00054 // Use the bit-representation trick only on X86, and only when producing
00055 // optimized code
00056 #if defined(NDEBUG) && (defined i386 || defined _M_IX86)
00057 #define VTK_USE_TRICK
00058 #endif
00059 
00060 // Linux puts the FPU in extended precision. Windows and FreeBSD keep it in
00061 // double precision.  If other operating systems for i386 (Solaris?) behave
00062 // like Linux, add them below.  Special care needs to be taken when dealing
00063 // with extended precision mode because even though we are eventually writing
00064 // out to a double-precision variable to capture the fixed-point or integer
00065 // results, the extra bits maintained in the internal computations disrupt
00066 // the bit-playing that we're doing here.
00067 #if defined(__linux__)
00068 #define VTK_EXT_PREC
00069 #endif
00070 
00071 //#define VTK_TEST_HACK_TO_EMULATE_LINUX_UNDER_WINDOWS
00072 #ifdef VTK_TEST_HACK_TO_EMULATE_LINUX_UNDER_WINDOWS
00073 #define VTK_EXT_PREC
00074 #endif
00075 
00076 
00077 class VTK_COMMON_EXPORT vtkFastNumericConversion : public vtkObject
00078 {
00079 public:
00080   static vtkFastNumericConversion *New();
00081   vtkTypeRevisionMacro(vtkFastNumericConversion, vtkObject);
00082   void PrintSelf(ostream& os, vtkIndent indent);
00083 
00086   int TestQuickFloor(double val);
00087 
00090   int TestSafeFloor(double val);
00091 
00094   int TestRound(double val);
00095 
00098   int TestConvertFixedPointIntPart(double val);
00099 
00102   int TestConvertFixedPointFracPart(double val);
00103 
00104 protected:
00105   //BTX
00111   static inline double BorrowBit() { return 1.5;};
00112 
00116   static inline double two30() { return (double)(((unsigned long)1) << 30); };
00117 
00119 
00121   static inline double two52() 
00122     { return (((unsigned long)1) << (52-30)) * two30(); };
00124 
00126 
00131   static inline double two51() 
00132     { return (((unsigned long)1) << (51-30)) * two30(); }; 
00134 
00136 
00139   static inline double two63() 
00140     { return (((unsigned long)1) << (63-60)) * two30() * two30();};
00142 
00144 
00147   static inline double two62() 
00148     { return (((unsigned long)1) << (62-60)) * two30() * two30();};
00150 
00151   // Define number of bits of precision for various data types.
00152   // Note: INT_BITS is really 31, (rather than 32, since one of the bits is
00153   // just used for the two's-complement sign), but we say 30 because we don't
00154   // need to be able to handle 31-bit magnitudes correctly. I say that
00155   // because this is used for the QuickFloor code, and the SafeFloor code
00156   // retains an extra bit of fixed point precision which it shifts-out at the
00157   // end, thus reducing the magnitude of integers that it can handle. That's
00158   // an inherent limitation of using SafeFloor to prevent round-ups under any
00159   // circumstances, and there's no need to make QuickFloor handle a wider
00160   // range of numbers than SafeFloor.
00161 #define INT_BITS 30 
00162 #define EXT_BITS 64
00163 #define DBL_BITS 53
00164 
00193 public: 
00194 #ifdef VTK_EXT_PREC
00195   // Compute (0.5 ^ (EXT_BITS-INT_BITS)) as a compile-time constant
00196   static inline double RoundingTieBreaker() {return 1.0 / (two30() * (((unsigned long)1) << (EXT_BITS - INT_BITS - 30))); };
00197 #else
00198   // Compute (0.5 ^ (DBL_BITS-INT_BITS)) as a compile-time constant
00199   static inline double RoundingTieBreaker() { return 1.0 / (((unsigned long)1) << (DBL_BITS - INT_BITS)); };
00200 #endif
00201 
00202 protected:
00204 
00208   static inline double QuickFloorDenormalizer() 
00209     {return two52() * BorrowBit(); };
00211 
00213 
00218   static inline double SafeFloorDenormalizer() 
00219     { return two51() * BorrowBit(); };
00221 
00223 
00226   static inline double QuickExtPrecTempDenormalizer() 
00227     {return two63() * BorrowBit(); };
00229 
00231 
00234   static inline double SafeExtPrecTempDenormalizer() 
00235     {return two62() * BorrowBit(); };
00237 
00238   static inline double QuickRoundAdjust() {return 0.5;};
00239   static inline double SafeRoundAdjust() {return 0.25;};
00240   static inline int SafeFinalShift() {return 1;};
00241 
00242 
00243 #ifdef VTK_WORDS_BIGENDIAN
00244   enum {exponent_pos = 0, mantissa_pos = 1};
00245 #else
00246   enum {exponent_pos = 1, mantissa_pos = 0};
00247 #endif 
00248   //ETX
00249 
00250 public:
00251 
00253 
00264   void SetReservedFracBits(int bits)
00265     {
00266     // Add one to the requested number of fractional bits, to make
00267     // the conversion safe with respect to rounding mode. This is the
00268     // same as the difference between QuickFloor and SafeFloor.
00269     bits++;
00270     unsigned long mtime = this->GetMTime();
00271     this->SetinternalReservedFracBits(bits);
00272     if (mtime != this->GetMTime())
00273       {
00274       this->InternalRebuild();
00275       }
00276     };
00278 
00282   void PerformanceTests(void);    
00283 
00284   //BTX
00286 
00303   inline static int QuickFloor(const double &val)
00304     {
00305 #ifdef VTK_USE_TRICK
00306       union { int i[2]; double d; } u;
00307 #ifdef VTK_EXT_PREC
00308       u.d = (((val - (QuickRoundAdjust() - RoundingTieBreaker())) 
00309               // Push off those extended precision bits
00310               + QuickExtPrecTempDenormalizer()) 
00311              // Pull back the wanted bits into double range
00312              - QuickExtPrecTempDenormalizer()) 
00313         + QuickFloorDenormalizer();
00314 #else // ! VTK_EXT_PREC
00315       u.d = (val - (QuickRoundAdjust() - RoundingTieBreaker())) 
00316         + QuickFloorDenormalizer();
00317 #endif // VTK_EXT_PREC
00318       return u.i[mantissa_pos];
00319 #else // ! VTK_USE_TRICK
00320     return (int) val;
00321 #endif // VTK_USE_TRICK
00322     }
00324 
00326 
00340   inline static int SafeFloor(const double &val)
00341     {
00342 #ifdef VTK_USE_TRICK
00343       union { int i[2]; double d; } u;
00344 #ifdef VTK_EXT_PREC
00345       u.d = (((val - SafeRoundAdjust())
00346               + SafeExtPrecTempDenormalizer())
00347              - SafeExtPrecTempDenormalizer())
00348         + SafeFloorDenormalizer();
00349 #else // ! VTK_EXT_PREC
00350       u.d = (val - SafeRoundAdjust()) 
00351         + SafeFloorDenormalizer();
00352 #endif // VTK_EXT_PREC
00353       return u.i[mantissa_pos] >> SafeFinalShift();
00354 #else // ! VTK_USE_TRICK
00355     return (int) val;
00356 #endif // VTK_USE_TRICK
00357     }
00359 
00361 
00370   inline static int Round(const double &val)
00371     {
00372 #ifdef VTK_USE_TRICK
00373       union { int i[2]; double d; } u;
00374 #ifdef VTK_EXT_PREC
00375       u.d = ((val 
00376               + QuickExtPrecTempDenormalizer()) 
00377              - QuickExtPrecTempDenormalizer())
00378         + QuickFloorDenormalizer();
00379 #else // ! VTK_EXT_PREC
00380       u.d = val  
00381         + QuickFloorDenormalizer();
00382 #endif // VTK_EXT_PREC
00383     return u.i[mantissa_pos];
00384 #else // ! VTK_USE_TRICK
00385     if (val>=0)
00386       {
00387       return (int) (val + 0.5);
00388       }
00389     else
00390       {
00391       return (int) (val - 0.5);
00392       }
00393 #endif // VTK_USE_TRICK
00394     }
00396 
00398 
00401   inline int ConvertFixedPoint(const double &val, int &fracPart)
00402     {
00403       union { int i[2]; double d; } u;
00404 #ifdef VTK_EXT_PREC
00405       u.d = (((val - fixRound)
00406               + this->epTempDenormalizer)
00407              - this->epTempDenormalizer)
00408         + this->fpDenormalizer;
00409 #else // ! VTK_EXT_PREC
00410       u.d = (val - fixRound) 
00411         + this->fpDenormalizer;
00412 #endif // VTK_EXT_PREC
00413     fracPart = (u.i[mantissa_pos] & fracMask) >> 1;
00414     return u.i[mantissa_pos] >> this->internalReservedFracBits;
00415     }
00416   //ETX
00418 
00419 
00420 protected:
00421   //BTX
00422   vtkFastNumericConversion()
00423     {
00424 #ifdef VTK_TEST_HACK_TO_EMULATE_LINUX_UNDER_WINDOWS
00425     _controlfp( _PC_64, MCW_PC );
00426 #endif
00427 
00428     this->fixRound = 0;
00429     this->internalReservedFracBits = 0;
00430     this->fracMask = 0;
00431     this->fpDenormalizer = 0;
00432     this->bare_time = 0;
00433     this->cast_time = 0;
00434     this->convert_time = 0;
00435     this->quickfloor_time = 0;
00436     this->safefloor_time = 0;
00437     this->round_time = 0;
00438     this->InternalRebuild();
00439     };
00440   ~vtkFastNumericConversion() {};
00441   void InternalRebuild(void);
00442 
00443 private:
00444   vtkSetMacro(internalReservedFracBits, int);
00445   vtkGetMacro(internalReservedFracBits, int);
00446   int internalReservedFracBits;
00447   int fracMask;
00448 
00449   // Used when doing fixed point conversions with a certain number of bits
00450   // remaining for the fractional part, as opposed to the pure integer
00451   // flooring
00452   double fpDenormalizer;
00453 
00454   // Used when doing fixed point conversions in extended precision mode
00455   double epTempDenormalizer;
00456 
00457   // Adjustment for rounding based on the number of bits reserved for
00458   // fractional representation
00459   double fixRound;
00460 
00461   double bare_time;
00462   double cast_time;
00463   double convert_time;
00464   double quickfloor_time;
00465   double safefloor_time;
00466   double round_time;
00467   //ETX
00468   
00469   vtkFastNumericConversion(const vtkFastNumericConversion&); // Not implemented
00470   void operator=(const vtkFastNumericConversion&); // Not implemented
00471 };
00472 
00473 #endif

Generated on Mon Jan 21 23:07:17 2008 for VTK by  doxygen 1.4.3-20050530