VTK
dox/Common/Math/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 "vtkCommonMathModule.h" // For export macro
00056 #include "vtkObject.h"
00057 
00058 // Use the bit-representation trick only on X86, and only when producing
00059 // optimized code
00060 #if defined(NDEBUG) && (defined i386 || defined _M_IX86)
00061 #define VTK_USE_TRICK
00062 #endif
00063 
00064 // Linux puts the FPU in extended precision. Windows and FreeBSD keep it in
00065 // double precision.  If other operating systems for i386 (Solaris?) behave
00066 // like Linux, add them below.  Special care needs to be taken when dealing
00067 // with extended precision mode because even though we are eventually writing
00068 // out to a double-precision variable to capture the fixed-point or integer
00069 // results, the extra bits maintained in the internal computations disrupt
00070 // the bit-playing that we're doing here.
00071 #if defined(__linux__)
00072 #define VTK_EXT_PREC
00073 #endif
00074 
00075 //#define VTK_TEST_HACK_TO_EMULATE_LINUX_UNDER_WINDOWS
00076 #ifdef VTK_TEST_HACK_TO_EMULATE_LINUX_UNDER_WINDOWS
00077 #define VTK_EXT_PREC
00078 #endif
00079 
00080 
00081 class VTKCOMMONMATH_EXPORT vtkFastNumericConversion : public vtkObject
00082 {
00083 public:
00084   static vtkFastNumericConversion *New();
00085   vtkTypeMacro(vtkFastNumericConversion, vtkObject);
00086   void PrintSelf(ostream& os, vtkIndent indent);
00087 
00088   int TestQuickFloor(double val)
00089     {
00090     return vtkFastNumericConversion::QuickFloor(val);
00091     }
00092 
00093   int TestSafeFloor(double val)
00094     {
00095     return vtkFastNumericConversion::SafeFloor(val);
00096     }
00097 
00098   int TestRound(double val)
00099     {
00100     return vtkFastNumericConversion::Round(val);
00101     }
00102 
00103   int TestConvertFixedPointIntPart(double val)
00104     {
00105     int frac;
00106     return ConvertFixedPoint(val, frac);
00107     }
00108 
00109   int TestConvertFixedPointFracPart(double val)
00110     {
00111     int frac;
00112     ConvertFixedPoint(val, frac);
00113     return frac;
00114     }
00115 
00116 protected:
00117   //BTX
00123   static inline double BorrowBit() { return 1.5;};
00124 
00126 
00129   static inline double two30()
00130     {
00131       return static_cast<double>(static_cast<unsigned long>(1) << 30);
00132     }
00134 
00136 
00138   static inline double two52()
00139     {
00140       return (static_cast<unsigned long>(1) << (52-30)) * two30();
00141     }
00143 
00145 
00150   static inline double two51()
00151     {
00152       return (static_cast<unsigned long>(1) << (51-30)) * two30();
00153     }
00155 
00157 
00160   static inline double two63()
00161     {
00162       return (static_cast<unsigned long>(1) << (63-60)) * two30() * two30();
00163     }
00165 
00167 
00170   static inline double two62()
00171     {
00172       return (static_cast<unsigned long>(1) << (62-60)) * two30() * two30();
00173     }
00175 
00176   // Define number of bits of precision for various data types.
00177   // Note: INT_BITS is really 31, (rather than 32, since one of the bits is
00178   // just used for the two's-complement sign), but we say 30 because we don't
00179   // need to be able to handle 31-bit magnitudes correctly. I say that
00180   // because this is used for the QuickFloor code, and the SafeFloor code
00181   // retains an extra bit of fixed point precision which it shifts-out at the
00182   // end, thus reducing the magnitude of integers that it can handle. That's
00183   // an inherent limitation of using SafeFloor to prevent round-ups under any
00184   // circumstances, and there's no need to make QuickFloor handle a wider
00185   // range of numbers than SafeFloor.
00186 #define INT_BITS 30
00187 #define EXT_BITS 64
00188 #define DBL_BITS 53
00189 
00191 
00219 public:
00220 #ifdef VTK_EXT_PREC
00221   // Compute (0.5 ^ (EXT_BITS-INT_BITS)) as a compile-time constant
00222   static inline double RoundingTieBreaker()
00223     {
00224       return 1.0 / (two30() * (static_cast<unsigned long>(1) << (EXT_BITS - INT_BITS - 30)));
00225     }
00226 #else
00227   // Compute (0.5 ^ (DBL_BITS-INT_BITS)) as a compile-time constant
00228   static inline double RoundingTieBreaker()
00229     {
00230       return 1.0 / (static_cast<unsigned long>(1) << (DBL_BITS - INT_BITS));
00231     }
00232 #endif
00233 
00234 
00235 protected:
00237 
00241   static inline double QuickFloorDenormalizer()
00242     {return two52() * BorrowBit(); };
00244 
00246 
00251   static inline double SafeFloorDenormalizer()
00252     { return two51() * BorrowBit(); };
00254 
00256 
00259   static inline double QuickExtPrecTempDenormalizer()
00260     {return two63() * BorrowBit(); };
00262 
00264 
00267   static inline double SafeExtPrecTempDenormalizer()
00268     {return two62() * BorrowBit(); };
00270 
00271   static inline double QuickRoundAdjust() {return 0.5;};
00272   static inline double SafeRoundAdjust() {return 0.25;};
00273   static inline int SafeFinalShift() {return 1;};
00274 
00275 
00276 #ifdef VTK_WORDS_BIGENDIAN
00277   enum {exponent_pos = 0, mantissa_pos = 1};
00278 #else
00279   enum {exponent_pos = 1, mantissa_pos = 0};
00280 #endif
00281   //ETX
00282 
00283 public:
00284 
00286 
00297   void SetReservedFracBits(int bits)
00298     {
00299     // Add one to the requested number of fractional bits, to make
00300     // the conversion safe with respect to rounding mode. This is the
00301     // same as the difference between QuickFloor and SafeFloor.
00302     bits++;
00303     unsigned long mtime = this->GetMTime();
00304     this->SetinternalReservedFracBits(bits);
00305     if (mtime != this->GetMTime())
00306       {
00307       this->InternalRebuild();
00308       }
00309     };
00311 
00312   //BTX
00330   static int QuickFloor(const double &val);
00331 
00346   static int SafeFloor(const double &val);
00347 
00357   static int Round(const double &val);
00358 
00360 
00363   inline int ConvertFixedPoint(const double &val, int &fracPart)
00364     {
00365       union { int i[2]; double d; } u;
00366 #ifdef VTK_EXT_PREC
00367       u.d = (((val - fixRound)
00368               + this->epTempDenormalizer)
00369              - this->epTempDenormalizer)
00370         + this->fpDenormalizer;
00371 #else // ! VTK_EXT_PREC
00372       u.d = (val - fixRound)
00373         + this->fpDenormalizer;
00374 #endif // VTK_EXT_PREC
00375     fracPart = (u.i[mantissa_pos] & fracMask) >> 1;
00376     return u.i[mantissa_pos] >> this->internalReservedFracBits;
00377     }
00378   //ETX
00380 
00381 
00382 protected:
00383   //BTX
00384   vtkFastNumericConversion();
00385   ~vtkFastNumericConversion() {};
00386   void InternalRebuild(void);
00387 
00388 private:
00389   vtkSetMacro(internalReservedFracBits, int);
00390   vtkGetMacro(internalReservedFracBits, int);
00391 
00392 #ifndef VTK_LEGACY_SILENT
00393   static int QuickFloorInline(const double &val);
00394   static int SafeFloorInline(const double &val);
00395   static int RoundInline(const double &val);
00396 #endif
00397 
00398   int internalReservedFracBits;
00399   int fracMask;
00400 
00401   // Used when doing fixed point conversions with a certain number of bits
00402   // remaining for the fractional part, as opposed to the pure integer
00403   // flooring
00404   double fpDenormalizer;
00405 
00406   // Used when doing fixed point conversions in extended precision mode
00407   double epTempDenormalizer;
00408 
00409   // Adjustment for rounding based on the number of bits reserved for
00410   // fractional representation
00411   double fixRound;
00412   //ETX
00413 
00414   vtkFastNumericConversion(const vtkFastNumericConversion&); // Not implemented
00415   void operator=(const vtkFastNumericConversion&); // Not implemented
00416 };
00417 
00418 #ifndef VTK_LEGACY_SILENT
00419 inline int vtkFastNumericConversion::QuickFloorInline(const double &val)
00420 #else
00421 inline int vtkFastNumericConversion::QuickFloor(const double &val)
00422 #endif
00423 {
00424 #ifdef VTK_USE_TRICK
00425   union { int i[2]; double d; } u;
00426 #ifdef VTK_EXT_PREC
00427   u.d = (((val - (QuickRoundAdjust() - RoundingTieBreaker()))
00428           // Push off those extended precision bits
00429           + QuickExtPrecTempDenormalizer())
00430          // Pull back the wanted bits into double range
00431          - QuickExtPrecTempDenormalizer())
00432     + QuickFloorDenormalizer();
00433 #else // ! VTK_EXT_PREC
00434   u.d = (val - (QuickRoundAdjust() - RoundingTieBreaker()))
00435     + QuickFloorDenormalizer();
00436 #endif // VTK_EXT_PREC
00437   return u.i[mantissa_pos];
00438 #else // ! VTK_USE_TRICK
00439   return static_cast<int>(val);
00440 #endif // VTK_USE_TRICK
00441 }
00442 
00443 #ifndef VTK_LEGACY_SILENT
00444 inline int vtkFastNumericConversion::SafeFloorInline(const double &val)
00445 #else
00446 inline int vtkFastNumericConversion::SafeFloor(const double &val)
00447 #endif
00448 {
00449 #ifdef VTK_USE_TRICK
00450   union { int i[2]; double d; } u;
00451 #ifdef VTK_EXT_PREC
00452   u.d = (((val - SafeRoundAdjust())
00453           + SafeExtPrecTempDenormalizer())
00454          - SafeExtPrecTempDenormalizer())
00455     + SafeFloorDenormalizer();
00456 #else // ! VTK_EXT_PREC
00457   u.d = (val - SafeRoundAdjust())
00458     + SafeFloorDenormalizer();
00459 #endif // VTK_EXT_PREC
00460   return u.i[mantissa_pos] >> SafeFinalShift();
00461 #else // ! VTK_USE_TRICK
00462   return static_cast<int>(val);
00463 #endif // VTK_USE_TRICK
00464 }
00465 
00466 #ifndef VTK_LEGACY_SILENT
00467 inline int vtkFastNumericConversion::RoundInline(const double &val)
00468 #else
00469 inline int vtkFastNumericConversion::Round(const double &val)
00470 #endif
00471 {
00472 #ifdef VTK_USE_TRICK
00473   union { int i[2]; double d; } u;
00474 #ifdef VTK_EXT_PREC
00475   u.d = ((val
00476           + QuickExtPrecTempDenormalizer())
00477          - QuickExtPrecTempDenormalizer())
00478     + QuickFloorDenormalizer();
00479 #else // ! VTK_EXT_PREC
00480   u.d = val
00481     + QuickFloorDenormalizer();
00482 #endif // VTK_EXT_PREC
00483 return u.i[mantissa_pos];
00484 #else // ! VTK_USE_TRICK
00485 if (val>=0)
00486   {
00487   return static_cast<int>(val + 0.5);
00488   }
00489 else
00490   {
00491   return static_cast<int>(val - 0.5);
00492   }
00493 #endif // VTK_USE_TRICK
00494 }
00495 
00496 #endif