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 00089 int TestQuickFloor(double val); 00090 00093 int TestSafeFloor(double val); 00094 00097 int TestRound(double val); 00098 00101 int TestConvertFixedPointIntPart(double val); 00102 00105 int TestConvertFixedPointFracPart(double val); 00106 00107 protected: 00108 //BTX 00114 static inline double BorrowBit() { return 1.5;}; 00115 00117 00120 static inline double two30() 00121 { 00122 return static_cast<double>(static_cast<unsigned long>(1) << 30); 00123 } 00125 00127 00129 static inline double two52() 00130 { 00131 return (static_cast<unsigned long>(1) << (52-30)) * two30(); 00132 } 00134 00136 00141 static inline double two51() 00142 { 00143 return (static_cast<unsigned long>(1) << (51-30)) * two30(); 00144 } 00146 00148 00151 static inline double two63() 00152 { 00153 return (static_cast<unsigned long>(1) << (63-60)) * two30() * two30(); 00154 } 00156 00158 00161 static inline double two62() 00162 { 00163 return (static_cast<unsigned long>(1) << (62-60)) * two30() * two30(); 00164 } 00166 00167 // Define number of bits of precision for various data types. 00168 // Note: INT_BITS is really 31, (rather than 32, since one of the bits is 00169 // just used for the two's-complement sign), but we say 30 because we don't 00170 // need to be able to handle 31-bit magnitudes correctly. I say that 00171 // because this is used for the QuickFloor code, and the SafeFloor code 00172 // retains an extra bit of fixed point precision which it shifts-out at the 00173 // end, thus reducing the magnitude of integers that it can handle. That's 00174 // an inherent limitation of using SafeFloor to prevent round-ups under any 00175 // circumstances, and there's no need to make QuickFloor handle a wider 00176 // range of numbers than SafeFloor. 00177 #define INT_BITS 30 00178 #define EXT_BITS 64 00179 #define DBL_BITS 53 00180 00209 public: 00210 #ifdef VTK_EXT_PREC 00211 // Compute (0.5 ^ (EXT_BITS-INT_BITS)) as a compile-time constant 00212 static inline double RoundingTieBreaker() 00213 { 00214 return 1.0 / (two30() * (static_cast<unsigned long>(1) << (EXT_BITS - INT_BITS - 30))); 00215 } 00216 #else 00217 // Compute (0.5 ^ (DBL_BITS-INT_BITS)) as a compile-time constant 00218 static inline double RoundingTieBreaker() 00219 { 00220 return 1.0 / (static_cast<unsigned long>(1) << (DBL_BITS - INT_BITS)); 00221 } 00222 #endif 00223 00224 protected: 00226 00230 static inline double QuickFloorDenormalizer() 00231 {return two52() * BorrowBit(); }; 00233 00235 00240 static inline double SafeFloorDenormalizer() 00241 { return two51() * BorrowBit(); }; 00243 00245 00248 static inline double QuickExtPrecTempDenormalizer() 00249 {return two63() * BorrowBit(); }; 00251 00253 00256 static inline double SafeExtPrecTempDenormalizer() 00257 {return two62() * BorrowBit(); }; 00259 00260 static inline double QuickRoundAdjust() {return 0.5;}; 00261 static inline double SafeRoundAdjust() {return 0.25;}; 00262 static inline int SafeFinalShift() {return 1;}; 00263 00264 00265 #ifdef VTK_WORDS_BIGENDIAN 00266 enum {exponent_pos = 0, mantissa_pos = 1}; 00267 #else 00268 enum {exponent_pos = 1, mantissa_pos = 0}; 00269 #endif 00270 //ETX 00271 00272 public: 00273 00275 00286 void SetReservedFracBits(int bits) 00287 { 00288 // Add one to the requested number of fractional bits, to make 00289 // the conversion safe with respect to rounding mode. This is the 00290 // same as the difference between QuickFloor and SafeFloor. 00291 bits++; 00292 unsigned long mtime = this->GetMTime(); 00293 this->SetinternalReservedFracBits(bits); 00294 if (mtime != this->GetMTime()) 00295 { 00296 this->InternalRebuild(); 00297 } 00298 }; 00300 00304 void PerformanceTests(void); 00305 00306 //BTX 00308 00325 inline static int QuickFloor(const double &val) 00326 { 00327 #ifdef VTK_USE_TRICK 00328 union { int i[2]; double d; } u; 00329 #ifdef VTK_EXT_PREC 00330 u.d = (((val - (QuickRoundAdjust() - RoundingTieBreaker())) 00331 // Push off those extended precision bits 00332 + QuickExtPrecTempDenormalizer()) 00333 // Pull back the wanted bits into double range 00334 - QuickExtPrecTempDenormalizer()) 00335 + QuickFloorDenormalizer(); 00336 #else // ! VTK_EXT_PREC 00337 u.d = (val - (QuickRoundAdjust() - RoundingTieBreaker())) 00338 + QuickFloorDenormalizer(); 00339 #endif // VTK_EXT_PREC 00340 return u.i[mantissa_pos]; 00341 #else // ! VTK_USE_TRICK 00342 return static_cast<int>(val); 00343 #endif // VTK_USE_TRICK 00344 } 00346 00348 00362 inline static int SafeFloor(const double &val) 00363 { 00364 #ifdef VTK_USE_TRICK 00365 union { int i[2]; double d; } u; 00366 #ifdef VTK_EXT_PREC 00367 u.d = (((val - SafeRoundAdjust()) 00368 + SafeExtPrecTempDenormalizer()) 00369 - SafeExtPrecTempDenormalizer()) 00370 + SafeFloorDenormalizer(); 00371 #else // ! VTK_EXT_PREC 00372 u.d = (val - SafeRoundAdjust()) 00373 + SafeFloorDenormalizer(); 00374 #endif // VTK_EXT_PREC 00375 return u.i[mantissa_pos] >> SafeFinalShift(); 00376 #else // ! VTK_USE_TRICK 00377 return static_cast<int>(val); 00378 #endif // VTK_USE_TRICK 00379 } 00381 00383 00392 inline static int Round(const double &val) 00393 { 00394 #ifdef VTK_USE_TRICK 00395 union { int i[2]; double d; } u; 00396 #ifdef VTK_EXT_PREC 00397 u.d = ((val 00398 + QuickExtPrecTempDenormalizer()) 00399 - QuickExtPrecTempDenormalizer()) 00400 + QuickFloorDenormalizer(); 00401 #else // ! VTK_EXT_PREC 00402 u.d = val 00403 + QuickFloorDenormalizer(); 00404 #endif // VTK_EXT_PREC 00405 return u.i[mantissa_pos]; 00406 #else // ! VTK_USE_TRICK 00407 if (val>=0) 00408 { 00409 return static_cast<int>(val + 0.5); 00410 } 00411 else 00412 { 00413 return static_cast<int>(val - 0.5); 00414 } 00415 #endif // VTK_USE_TRICK 00416 } 00418 00420 00423 inline int ConvertFixedPoint(const double &val, int &fracPart) 00424 { 00425 union { int i[2]; double d; } u; 00426 #ifdef VTK_EXT_PREC 00427 u.d = (((val - fixRound) 00428 + this->epTempDenormalizer) 00429 - this->epTempDenormalizer) 00430 + this->fpDenormalizer; 00431 #else // ! VTK_EXT_PREC 00432 u.d = (val - fixRound) 00433 + this->fpDenormalizer; 00434 #endif // VTK_EXT_PREC 00435 fracPart = (u.i[mantissa_pos] & fracMask) >> 1; 00436 return u.i[mantissa_pos] >> this->internalReservedFracBits; 00437 } 00438 //ETX 00440 00441 00442 protected: 00443 //BTX 00444 vtkFastNumericConversion() 00445 { 00446 #ifdef VTK_TEST_HACK_TO_EMULATE_LINUX_UNDER_WINDOWS 00447 _controlfp( _PC_64, MCW_PC ); 00448 #endif 00449 00450 this->fixRound = 0; 00451 this->internalReservedFracBits = 0; 00452 this->fracMask = 0; 00453 this->fpDenormalizer = 0; 00454 this->bare_time = 0; 00455 this->cast_time = 0; 00456 this->convert_time = 0; 00457 this->quickfloor_time = 0; 00458 this->safefloor_time = 0; 00459 this->round_time = 0; 00460 this->InternalRebuild(); 00461 }; 00462 ~vtkFastNumericConversion() {}; 00463 void InternalRebuild(void); 00464 00465 private: 00466 vtkSetMacro(internalReservedFracBits, int); 00467 vtkGetMacro(internalReservedFracBits, int); 00468 int internalReservedFracBits; 00469 int fracMask; 00470 00471 // Used when doing fixed point conversions with a certain number of bits 00472 // remaining for the fractional part, as opposed to the pure integer 00473 // flooring 00474 double fpDenormalizer; 00475 00476 // Used when doing fixed point conversions in extended precision mode 00477 double epTempDenormalizer; 00478 00479 // Adjustment for rounding based on the number of bits reserved for 00480 // fractional representation 00481 double fixRound; 00482 00483 double bare_time; 00484 double cast_time; 00485 double convert_time; 00486 double quickfloor_time; 00487 double safefloor_time; 00488 double round_time; 00489 //ETX 00490 00491 vtkFastNumericConversion(const vtkFastNumericConversion&); // Not implemented 00492 void operator=(const vtkFastNumericConversion&); // Not implemented 00493 }; 00494 00495 #endif