File: vtkFastNumericConversion.cxx

package info (click to toggle)
vtk 5.0.4-1.1
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 51,084 kB
  • ctags: 70,426
  • sloc: cpp: 524,166; ansic: 220,276; tcl: 43,377; python: 14,037; perl: 3,102; java: 1,436; yacc: 1,033; sh: 339; lex: 248; makefile: 197; asm: 154
file content (211 lines) | stat: -rw-r--r-- 7,126 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
/*=========================================================================

  Program:   Visualization Toolkit
  Module:    $RCSfile: vtkFastNumericConversion.cxx,v $

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
// .NAME vtkFastNumericConversion - Enables fast conversion of floating point to fixed point
// .SECTION Description
// 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 flooring on platforms, such as Intel X86, in which CPU floating point flooring
// 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 floor 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)


#include "vtkFastNumericConversion.h"
#include "vtkObjectFactory.h"
#include "vtkTimerLog.h"

vtkCxxRevisionMacro(vtkFastNumericConversion, "$Revision: 1.2 $");
vtkStandardNewMacro(vtkFastNumericConversion);

int vtkFastNumericConversion::TestQuickFloor(double val)
  {
  return vtkFastNumericConversion::QuickFloor(val);
  }

int vtkFastNumericConversion::TestSafeFloor(double val)
  {
  return vtkFastNumericConversion::SafeFloor(val);
  }

int vtkFastNumericConversion::TestRound(double val)
  {
  return vtkFastNumericConversion::Round(val);
  }

int vtkFastNumericConversion::TestConvertFixedPointIntPart(double val)
  {
  int frac;
  return this->ConvertFixedPoint(val, frac);
  }

int vtkFastNumericConversion::TestConvertFixedPointFracPart(double val)
  {
  int frac;
  this->ConvertFixedPoint(val, frac);
  return frac;
  }

void vtkFastNumericConversion::InternalRebuild()
  {
  int i; 
  this->fixRound=.5;
  for (i=this->internalReservedFracBits; i; i--)
    {
    this->fixRound *= .5;
    }
  this->fracMask = (1<<this->internalReservedFracBits)-1;
  this->fpDenormalizer = (((unsigned long)1) << (52-30-this->internalReservedFracBits)) * 
    this->two30() * this->BorrowBit();
  this->epTempDenormalizer = this->fpDenormalizer * (((unsigned long)1) << (63-52));
  }


void vtkFastNumericConversion::PrintSelf(ostream &os, vtkIndent indent)
  {
  os << indent << "ReservedFracBits: " << this->internalReservedFracBits << endl;
  os << indent << "Bare time from last PerformanceTest() call: " << this->bare_time << endl;
  os << indent << "Cast time from last PerformanceTest() call: " << this->cast_time << endl;
  os << indent << "ConvertFixedPoint time from last PerformanceTest() call: " << this->convert_time << endl;
  os << indent << "QuickFloor time from last PerformanceTest() call: " << this->quickfloor_time << endl;
  os << indent << "SafeFloor time from last PerformanceTest() call: " << this->safefloor_time << endl;
  os << indent << "Round time from last PerformanceTest() call: " << this->round_time << endl;
  if (this->bare_time != 0.0)
    {
    // Don't do this if we haven't run the tests yet.
    os << indent << "Speedup ratio from cast to quickfloor is: " << 
      (this->cast_time-this->bare_time)/(this->quickfloor_time-this->bare_time) << endl;
    os << indent << "Speedup ratio from cast to safefloor is: " << 
      (this->cast_time-this->bare_time)/(this->safefloor_time-this->bare_time) << endl;
    os << indent << "Speedup ratio from cast to round is: " << 
      (this->cast_time-this->bare_time)/(this->round_time-this->bare_time) << endl;
    }
  }


void vtkFastNumericConversion::PerformanceTests(void)
  {
  const int inner_count = 10000;
  const int outer_count = 10000;
  double *dval = new double[inner_count];
  int *ival = new int[inner_count];
  int *frac = new int[inner_count];

  
  int i,o;
  vtkTimerLog *timer = vtkTimerLog::New();

  for (i=0; i<inner_count; i++)
    {
    dval[i] = i;
    ival[i] = 0;
    }

  timer->StartTimer();
  for (o=0; o<outer_count; o++)
    {
    for (i=0; i<inner_count; i++)
      {
      // Pure bit copy
      ival[i] = *((int *)(&dval[i]));
      }
    }
  timer->StopTimer();
  this->bare_time = timer->GetElapsedTime();
  
 
  // Compute cast time
  timer->StartTimer();
  for (o=0; o<outer_count; o++)
    {
    for (i=0; i<inner_count; i++)
      {
      ival[i] = (int) dval[i];
      }
    }
  timer->StopTimer();
  this->cast_time = timer->GetElapsedTime();


  // Compute convert time
  timer->StartTimer();
  for (o=0; o<outer_count; o++)
    {
    for (i=0; i<inner_count; i++)
      {
      ival[i] = this->ConvertFixedPoint(dval[i], frac[i]);
      }
    }
  timer->StopTimer();
  this->convert_time = timer->GetElapsedTime();

  // Compute quickfloor time
  timer->StartTimer();
  for (o=0; o<outer_count; o++)
    {
    for (i=0; i<inner_count; i++)
      {
      ival[i] = vtkFastNumericConversion::QuickFloor(dval[i]);
      }
    }
  timer->StopTimer();
  this->quickfloor_time = timer->GetElapsedTime();

  // Compute safefloor time
  timer->StartTimer();
  for (o=0; o<outer_count; o++)
    {
    for (i=0; i<inner_count; i++)
      {
      ival[i] = vtkFastNumericConversion::SafeFloor(dval[i]);
      }
    }
  timer->StopTimer();
  this->safefloor_time = timer->GetElapsedTime();

  // Compute round time
  timer->StartTimer();
  for (o=0; o<outer_count; o++)
    {
    for (i=0; i<inner_count; i++)
      {
      ival[i] = vtkFastNumericConversion::Round(dval[i]);
      }
    }
  timer->StopTimer();
  this->round_time = timer->GetElapsedTime();



  delete [] dval;
  delete [] ival;
  delete [] frac;

  timer->Delete();
  }