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 =========================================================================*/
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     double tempval;
00307 #ifdef VTK_EXT_PREC
00308     tempval = (((val - (QuickRoundAdjust() - RoundingTieBreaker())) 
00309         + QuickExtPrecTempDenormalizer()) // Push off those extended precision bits
00310       - QuickExtPrecTempDenormalizer()) // Pull back the wanted bits into double range
00311       + QuickFloorDenormalizer();
00312 #else // ! VTK_EXT_PREC
00313     tempval = (val - (QuickRoundAdjust() - RoundingTieBreaker())) 
00314       + QuickFloorDenormalizer();
00315 #endif // VTK_EXT_PREC
00316     return ((int*)&tempval)[mantissa_pos];
00317 #else // ! VTK_USE_TRICK
00318     return (int) val;
00319 #endif // VTK_USE_TRICK
00320     }
00322 
00324 
00338   inline static int SafeFloor(const double &val)
00339     {
00340 #ifdef VTK_USE_TRICK
00341     double tempval;
00342 #ifdef VTK_EXT_PREC
00343     tempval = (((val - SafeRoundAdjust())
00344         + SafeExtPrecTempDenormalizer())
00345       - SafeExtPrecTempDenormalizer())
00346       + SafeFloorDenormalizer();
00347 #else // ! VTK_EXT_PREC
00348     tempval = (val - SafeRoundAdjust()) 
00349       + SafeFloorDenormalizer();
00350 #endif // VTK_EXT_PREC
00351     return ((int*)&tempval)[mantissa_pos] >> SafeFinalShift();
00352 #else // ! VTK_USE_TRICK
00353     return (int) val;
00354 #endif // VTK_USE_TRICK
00355     }
00357 
00359 
00368   inline static int Round(const double &val)
00369     {
00370 #ifdef VTK_USE_TRICK
00371     double tempval;
00372 #ifdef VTK_EXT_PREC
00373     tempval = ((val 
00374         + QuickExtPrecTempDenormalizer()) 
00375       - QuickExtPrecTempDenormalizer())
00376       + QuickFloorDenormalizer();
00377 #else // ! VTK_EXT_PREC
00378     tempval =    val  
00379       + QuickFloorDenormalizer();
00380 #endif // VTK_EXT_PREC
00381     return ((int*)&tempval)[mantissa_pos];
00382 #else // ! VTK_USE_TRICK
00383     if (val>=0)
00384       {
00385       return (int) (val + 0.5);
00386       }
00387     else
00388       {
00389       return (int) (val - 0.5);
00390       }
00391 #endif // VTK_USE_TRICK
00392     }
00394 
00396 
00399   inline int ConvertFixedPoint(const double &val, int &fracPart)
00400     {
00401     double tempval;
00402 #ifdef VTK_EXT_PREC
00403     tempval = (((val - fixRound)
00404         + this->epTempDenormalizer)
00405       - this->epTempDenormalizer)
00406       + this->fpDenormalizer;
00407 #else // ! VTK_EXT_PREC
00408     tempval = (val - fixRound) 
00409       + this->fpDenormalizer;
00410 #endif // VTK_EXT_PREC
00411     fracPart = (((int*)&tempval)[mantissa_pos] & fracMask) >> 1;
00412     return ((int*)&tempval)[mantissa_pos] >> this->internalReservedFracBits;
00413     }
00414   //ETX
00416 
00417 
00418 protected:
00419   //BTX
00420   vtkFastNumericConversion()
00421     {
00422 #ifdef VTK_TEST_HACK_TO_EMULATE_LINUX_UNDER_WINDOWS
00423     _controlfp( _PC_64, MCW_PC );
00424 #endif
00425 
00426     this->fixRound = 0;
00427     this->internalReservedFracBits = 0;
00428     this->fracMask = 0;
00429     this->fpDenormalizer = 0;
00430     this->bare_time = 0;
00431     this->cast_time = 0;
00432     this->convert_time = 0;
00433     this->quickfloor_time = 0;
00434     this->safefloor_time = 0;
00435     this->round_time = 0;
00436     this->InternalRebuild();
00437     };
00438   ~vtkFastNumericConversion() {};
00439   void InternalRebuild(void);
00440 
00441 private:
00442   vtkSetMacro(internalReservedFracBits, int);
00443   vtkGetMacro(internalReservedFracBits, int);
00444   int internalReservedFracBits;
00445   int fracMask;
00446 
00447   // Used when doing fixed point conversions with a certain number of bits
00448   // remaining for the fractional part, as opposed to the pure integer
00449   // flooring
00450   double fpDenormalizer;
00451 
00452   // Used when doing fixed point conversions in extended precision mode
00453   double epTempDenormalizer;
00454 
00455   // Adjustment for rounding based on the number of bits reserved for
00456   // fractional representation
00457   double fixRound;
00458 
00459   double bare_time;
00460   double cast_time;
00461   double convert_time;
00462   double quickfloor_time;
00463   double safefloor_time;
00464   double round_time;
00465   //ETX
00466   
00467   vtkFastNumericConversion(const vtkFastNumericConversion&); // Not implemented
00468   void operator=(const vtkFastNumericConversion&); // Not implemented
00469 };
00470 
00471 #endif

Generated on Sat Sep 2 03:28:38 2006 for VTK by  doxygen 1.4.7