VTK
|
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