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