|
virtual const char * | GetClassName () |
|
virtual int | IsA (const char *type) |
|
void | PrintSelf (ostream &os, vtkIndent indent) |
|
int | TestQuickFloor (double val) |
|
int | TestSafeFloor (double val) |
|
int | TestRound (double val) |
|
int | TestConvertFixedPointIntPart (double val) |
|
int | TestConvertFixedPointFracPart (double val) |
|
|
void | SetReservedFracBits (int bits) |
|
|
int | ConvertFixedPoint (const double &val, int &fracPart) |
|
virtual void | DebugOn () |
|
virtual void | DebugOff () |
|
unsigned char | GetDebug () |
|
void | SetDebug (unsigned char debugFlag) |
|
virtual void | Modified () |
|
virtual unsigned long | GetMTime () |
|
unsigned long | AddObserver (unsigned long event, vtkCommand *, float priority=0.0f) |
|
unsigned long | AddObserver (const char *event, vtkCommand *, float priority=0.0f) |
|
vtkCommand * | GetCommand (unsigned long tag) |
|
void | RemoveObserver (vtkCommand *) |
|
void | RemoveObservers (unsigned long event, vtkCommand *) |
|
void | RemoveObservers (const char *event, vtkCommand *) |
|
int | HasObserver (unsigned long event, vtkCommand *) |
|
int | HasObserver (const char *event, vtkCommand *) |
|
void | RemoveObserver (unsigned long tag) |
|
void | RemoveObservers (unsigned long event) |
|
void | RemoveObservers (const char *event) |
|
void | RemoveAllObservers () |
|
int | HasObserver (unsigned long event) |
|
int | HasObserver (const char *event) |
|
template<class U , class T > |
unsigned long | AddObserver (unsigned long event, U observer, void(T::*callback)(), float priority=0.0f) |
|
template<class U , class T > |
unsigned long | AddObserver (unsigned long event, U observer, void(T::*callback)(vtkObject *, unsigned long, void *), float priority=0.0f) |
|
int | InvokeEvent (unsigned long event, void *callData) |
|
int | InvokeEvent (const char *event, void *callData) |
|
int | InvokeEvent (unsigned long event) |
|
int | InvokeEvent (const char *event) |
|
const char * | GetClassName () const |
|
virtual void | Delete () |
|
virtual void | FastDelete () |
|
void | Print (ostream &os) |
|
virtual void | Register (vtkObjectBase *o) |
|
virtual void | UnRegister (vtkObjectBase *o) |
|
void | SetReferenceCount (int) |
|
void | PrintRevisions (ostream &os) |
|
virtual void | PrintHeader (ostream &os, vtkIndent indent) |
|
virtual void | PrintTrailer (ostream &os, vtkIndent indent) |
|
int | GetReferenceCount () |
|
Enables fast conversion of floating point to fixed point.
vtkFastNumericConversion uses a portable (assuming IEEE format) method for converting single and double precision floating point values to a fixed point representation. This allows fast integer floor operations on platforms, such as Intel X86, in which CPU floating point conversion algorithms are very slow. It is based on the techniques described in Chris Hecker's article, "Let's Get to the (Floating) Point", in Game Developer Magazine, Feb/Mar 1996, and the techniques described in Michael Herf's website, http://www.stereopsis.com/FPU.html. The Hecker article can be found at http://www.d6.com/users/checker/pdfs/gdmfp.pdf. Unfortunately, each of these techniques is incomplete, and doesn't convert properly, in a way that depends on how many bits are reserved for fixed point fractional use, due to failing to properly account for the default round-towards-even rounding mode of the X86. Thus, my implementation incorporates some rounding correction that undoes the rounding that the FPU performs during denormalization of the floating point value. Note that the rounding affect I'm talking about here is not the effect on the fistp instruction, but rather the effect that occurs during the denormalization of a value that occurs when adding it to a much larger value. The bits must be shifted to the right, and when a "1" bit falls off the edge, the rounding mode determines what happens next, in order to avoid completely "losing" the 1-bit. Furthermore, my implementation works on Linux, where the default precision mode is 64-bit extended precision.
This class is contributed to VTK by Chris Volpe of Applied Research Associates, Inc. (My employer requires me to say that – CRV)
This code assumes that the FPU is in round-to-nearest mode. It assumes, on Linux, that the default extended precision mode is in effect, and it assumes, on Windows, that the default double precision mode is in effect.
- Tests:
- vtkFastNumericConversion (Tests)
Definition at line 80 of file vtkFastNumericConversion.h.
static double vtkFastNumericConversion::RoundingTieBreaker |
( |
| ) |
|
|
inlinestatic |
Small amount to use as a rounding tie-breaker to prevent round-to-nearest-and-even mode from flooring-down odd numbered integers. But number to nudge by depends on number of bits mantissa in our floating point representation minus number of mantissa bits in the range of signed ints we need to handle. In order to ensure that flooring-down doesn't happen even for very large odd-integer values, the number of bits used to represent the tie-breaker (i.e. to the right of the binary-point), plus the number of bits needed to represent the integer (to the left of the binary point), can not exceeds the number of bits in the current precision mode. Thus, in selecting the tie-breaker value, we select the largest number of bits to the right of the binary point as possible while still maintaining that inequality. Thus, extended precision mode allows a larger number of bits to the right of the binary point. This, in turn, implies a smaller value of the tie-breaker. And a smaller tie-breaker will impose a tighter window on the range of values that are erroneously rounded-up by a floor operation. Under double precision, a QuickFloor of 0.9999998 (six 9's and an 8) correctly yields 0. A value must be very close to 1.0, in fact, at least as close as 0.9999999 (seven 9's)in order for the tie-breaker to bump it up to 1. Under extended precision, an even smaller tie-breaker can be used. In this mode, a QuickFloor of 0.9999999999 (ten 9's) correctly yields 0. A QuickFloor of 0.99999999999 (eleven 9's) gets rounded up to 1. Since these spurious round-ups occur only when the given value is virtually indistinguishable from the next higher integer, the results should be acceptable in most situations where performance is of the essence. Make this public so that clients can account for the RoundingTieBreaker if necessary
Definition at line 227 of file vtkFastNumericConversion.h.
static int vtkFastNumericConversion::QuickFloor |
( |
const double & |
val | ) |
|
|
inlinestatic |
Perform a quick flooring of the double-precision floating point value. The result is sometimes incorrect, but in a way that makes it acceptable for most uses. The naive way to implement floor(), given that the x86 FPU does round() by default, is to define floor(x) as round(x-.5). This would work fine except for the fact that the x86 FPU breaks rounding ties by selecting the even number. Thus, floor(4.0) = round(3.5) = 4, but floor(3.0) = round(2.5) = 2. As a result, subtracting .5 gives the wrong answer for odd integers. So, let's subtract just a TEENSY bit less than .5, to swing the odd-integer results up to their corect value. How teensy? Well, if it's too teensy, it will be insignificant compared to 0.5, and will become equivalent to 0.5. And if it's not teensy enough, we'll overshoot, causing results like floor(N-epsilon)==N, for some epsilon. Furthermore, the "too teensy" problem is exacerbated when trying to floor larger numbers, due to limitations of the representation's dynamic range. See the definition of RoundingTieBreaker() for details.
Definition at line 330 of file vtkFastNumericConversion.h.
static int vtkFastNumericConversion::SafeFloor |
( |
const double & |
val | ) |
|
|
inlinestatic |
Perform a SAFE flooring. Similar to QuickFloor, but modified to return the correct result always. Use this when it absolutely positively needs to be the correct answer all the time, and considering 0.9999999 as being equal to 1.0 is simply not acceptable. It works similarly to QuickFloor, but it retains one extra bit of fixed point precision in the conversion process, so that the problem with QuickFloor affects only an unneeded bit, and then it ditches that bit from the resulting integer with a right-shift. In other words, it rounds to the nearest one-half, choosing the EVEN one-half (i.e. the integer) as a tie-breaker, and then shifting off that half-integer bit. As a result of maintaining one extra bit of fixed point precision in the intermediate calculation, the range of integers supported is reduced by one bit. Plus, it takes a little longer to execute, due to the final bit shift.
Definition at line 367 of file vtkFastNumericConversion.h.