VTK
dox/Common/vtkFastNumericConversion.h
Go to the documentation of this file.
00001 /*=========================================================================
00002 
00003   Program:   Visualization Toolkit
00004   Module:    vtkFastNumericConversion.h
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   vtkTypeMacro(vtkFastNumericConversion, vtkObject);
00085   void PrintSelf(ostream& os, vtkIndent indent);
00086 
00087   int TestQuickFloor(double val)
00088     {
00089     return vtkFastNumericConversion::QuickFloor(val);
00090     }
00091 
00092   int TestSafeFloor(double val)
00093     {
00094     return vtkFastNumericConversion::SafeFloor(val);
00095     }
00096 
00097   int TestRound(double val)
00098     {
00099     return vtkFastNumericConversion::Round(val);
00100     }
00101 
00102   int TestConvertFixedPointIntPart(double val)
00103     {
00104     int frac;
00105     return ConvertFixedPoint(val, frac);
00106     }
00107 
00108   int TestConvertFixedPointFracPart(double val)
00109     {
00110     int frac;
00111     ConvertFixedPoint(val, frac);
00112     return frac;
00113     }
00114 
00115 protected:
00116   //BTX
00122   static inline double BorrowBit() { return 1.5;};
00123 
00125 
00128   static inline double two30()
00129     {
00130       return static_cast<double>(static_cast<unsigned long>(1) << 30);
00131     }
00133 
00135 
00137   static inline double two52()
00138     {
00139       return (static_cast<unsigned long>(1) << (52-30)) * two30();
00140     }
00142 
00144 
00149   static inline double two51()
00150     {
00151       return (static_cast<unsigned long>(1) << (51-30)) * two30();
00152     }
00154 
00156 
00159   static inline double two63()
00160     {
00161       return (static_cast<unsigned long>(1) << (63-60)) * two30() * two30();
00162     }
00164 
00166 
00169   static inline double two62()
00170     {
00171       return (static_cast<unsigned long>(1) << (62-60)) * two30() * two30();
00172     }
00174 
00175   // Define number of bits of precision for various data types.
00176   // Note: INT_BITS is really 31, (rather than 32, since one of the bits is
00177   // just used for the two's-complement sign), but we say 30 because we don't
00178   // need to be able to handle 31-bit magnitudes correctly. I say that
00179   // because this is used for the QuickFloor code, and the SafeFloor code
00180   // retains an extra bit of fixed point precision which it shifts-out at the
00181   // end, thus reducing the magnitude of integers that it can handle. That's
00182   // an inherent limitation of using SafeFloor to prevent round-ups under any
00183   // circumstances, and there's no need to make QuickFloor handle a wider
00184   // range of numbers than SafeFloor.
00185 #define INT_BITS 30
00186 #define EXT_BITS 64
00187 #define DBL_BITS 53
00188 
00190 
00218 public:
00219 #ifdef VTK_EXT_PREC
00220   // Compute (0.5 ^ (EXT_BITS-INT_BITS)) as a compile-time constant
00221   static inline double RoundingTieBreaker()
00222     {
00223       return 1.0 / (two30() * (static_cast<unsigned long>(1) << (EXT_BITS - INT_BITS - 30)));
00224     }
00225 #else
00226   // Compute (0.5 ^ (DBL_BITS-INT_BITS)) as a compile-time constant
00227   static inline double RoundingTieBreaker()
00228     {
00229       return 1.0 / (static_cast<unsigned long>(1) << (DBL_BITS - INT_BITS));
00230     }
00231 #endif
00232 
00233 
00234 protected:
00236 
00240   static inline double QuickFloorDenormalizer()
00241     {return two52() * BorrowBit(); };
00243 
00245 
00250   static inline double SafeFloorDenormalizer()
00251     { return two51() * BorrowBit(); };
00253 
00255 
00258   static inline double QuickExtPrecTempDenormalizer()
00259     {return two63() * BorrowBit(); };
00261 
00263 
00266   static inline double SafeExtPrecTempDenormalizer()
00267     {return two62() * BorrowBit(); };
00269 
00270   static inline double QuickRoundAdjust() {return 0.5;};
00271   static inline double SafeRoundAdjust() {return 0.25;};
00272   static inline int SafeFinalShift() {return 1;};
00273 
00274 
00275 #ifdef VTK_WORDS_BIGENDIAN
00276   enum {exponent_pos = 0, mantissa_pos = 1};
00277 #else
00278   enum {exponent_pos = 1, mantissa_pos = 0};
00279 #endif
00280   //ETX
00281 
00282 public:
00283 
00285 
00296   void SetReservedFracBits(int bits)
00297     {
00298     // Add one to the requested number of fractional bits, to make
00299     // the conversion safe with respect to rounding mode. This is the
00300     // same as the difference between QuickFloor and SafeFloor.
00301     bits++;
00302     unsigned long mtime = this->GetMTime();
00303     this->SetinternalReservedFracBits(bits);
00304     if (mtime != this->GetMTime())
00305       {
00306       this->InternalRebuild();
00307       }
00308     };
00310 
00311   //BTX
00313 
00330   inline static int QuickFloor(const double &val)
00331     {
00332 #ifdef VTK_USE_TRICK
00333       union { int i[2]; double d; } u;
00334 #ifdef VTK_EXT_PREC
00335       u.d = (((val - (QuickRoundAdjust() - RoundingTieBreaker()))
00336               // Push off those extended precision bits
00337               + QuickExtPrecTempDenormalizer())
00338              // Pull back the wanted bits into double range
00339              - QuickExtPrecTempDenormalizer())
00340         + QuickFloorDenormalizer();
00341 #else // ! VTK_EXT_PREC
00342       u.d = (val - (QuickRoundAdjust() - RoundingTieBreaker()))
00343         + QuickFloorDenormalizer();
00344 #endif // VTK_EXT_PREC
00345       return u.i[mantissa_pos];
00346 #else // ! VTK_USE_TRICK
00347       return static_cast<int>(val);
00348 #endif // VTK_USE_TRICK
00349     }
00351 
00353 
00367   inline static int SafeFloor(const double &val)
00368     {
00369 #ifdef VTK_USE_TRICK
00370       union { int i[2]; double d; } u;
00371 #ifdef VTK_EXT_PREC
00372       u.d = (((val - SafeRoundAdjust())
00373               + SafeExtPrecTempDenormalizer())
00374              - SafeExtPrecTempDenormalizer())
00375         + SafeFloorDenormalizer();
00376 #else // ! VTK_EXT_PREC
00377       u.d = (val - SafeRoundAdjust())
00378         + SafeFloorDenormalizer();
00379 #endif // VTK_EXT_PREC
00380       return u.i[mantissa_pos] >> SafeFinalShift();
00381 #else // ! VTK_USE_TRICK
00382       return static_cast<int>(val);
00383 #endif // VTK_USE_TRICK
00384     }
00386 
00388 
00397   inline static int Round(const double &val)
00398     {
00399 #ifdef VTK_USE_TRICK
00400       union { int i[2]; double d; } u;
00401 #ifdef VTK_EXT_PREC
00402       u.d = ((val
00403               + QuickExtPrecTempDenormalizer())
00404              - QuickExtPrecTempDenormalizer())
00405         + QuickFloorDenormalizer();
00406 #else // ! VTK_EXT_PREC
00407       u.d = val
00408         + QuickFloorDenormalizer();
00409 #endif // VTK_EXT_PREC
00410     return u.i[mantissa_pos];
00411 #else // ! VTK_USE_TRICK
00412     if (val>=0)
00413       {
00414       return static_cast<int>(val + 0.5);
00415       }
00416     else
00417       {
00418       return static_cast<int>(val - 0.5);
00419       }
00420 #endif // VTK_USE_TRICK
00421     }
00423 
00425 
00428   inline int ConvertFixedPoint(const double &val, int &fracPart)
00429     {
00430       union { int i[2]; double d; } u;
00431 #ifdef VTK_EXT_PREC
00432       u.d = (((val - fixRound)
00433               + this->epTempDenormalizer)
00434              - this->epTempDenormalizer)
00435         + this->fpDenormalizer;
00436 #else // ! VTK_EXT_PREC
00437       u.d = (val - fixRound)
00438         + this->fpDenormalizer;
00439 #endif // VTK_EXT_PREC
00440     fracPart = (u.i[mantissa_pos] & fracMask) >> 1;
00441     return u.i[mantissa_pos] >> this->internalReservedFracBits;
00442     }
00443   //ETX
00445 
00446 
00447 protected:
00448   //BTX
00449   vtkFastNumericConversion()
00450     {
00451 #ifdef VTK_TEST_HACK_TO_EMULATE_LINUX_UNDER_WINDOWS
00452     _controlfp( _PC_64, MCW_PC );
00453 #endif
00454 
00455     this->fixRound = 0;
00456     this->internalReservedFracBits = 0;
00457     this->fracMask = 0;
00458     this->fpDenormalizer = 0;
00459     };
00460   ~vtkFastNumericConversion() {};
00461   void InternalRebuild(void);
00462 
00463 private:
00464   vtkSetMacro(internalReservedFracBits, int);
00465   vtkGetMacro(internalReservedFracBits, int);
00466   int internalReservedFracBits;
00467   int fracMask;
00468 
00469   // Used when doing fixed point conversions with a certain number of bits
00470   // remaining for the fractional part, as opposed to the pure integer
00471   // flooring
00472   double fpDenormalizer;
00473 
00474   // Used when doing fixed point conversions in extended precision mode
00475   double epTempDenormalizer;
00476 
00477   // Adjustment for rounding based on the number of bits reserved for
00478   // fractional representation
00479   double fixRound;
00480   //ETX
00481 
00482   vtkFastNumericConversion(const vtkFastNumericConversion&); // Not implemented
00483   void operator=(const vtkFastNumericConversion&); // Not implemented
00484 };
00485 
00486 #endif