View Issue Details [ Jump to Notes ] | [ Print ] | ||||||||
ID | Project | Category | View Status | Date Submitted | Last Update | ||||
0006558 | ITK | public | 2008-03-07 05:20 | 2010-10-21 11:15 | |||||
Reporter | Andreas Keil | ||||||||
Assigned To | MichelKitware | ||||||||
Priority | normal | Severity | major | Reproducibility | always | ||||
Status | closed | Resolution | fixed | ||||||
Platform | OS | OS Version | |||||||
Product Version | |||||||||
Target Version | Fixed in Version | ||||||||
Summary | 0006558: Physical coordinates of a pixel - Severe inconsistency and bug in ImageBase | ||||||||
Description | Problems: 1) The implementation of the conversion between physical coordinates and indexes differs from the documentation. The former uses corner-based coordinates whereas the latter describes center-based coordinates. 2) The implementation contains a severe bug since it uses truncation (instead of either flooring or rounding). This yields wrong indexes for negative coordinates. Severity: This bug affects every application/filter using physical coordinates of ITK images (esp. registration and reconstruction). It has to be fixed immediately. Solution: Decide about whether to use center-based or corner-based coordinates and correct the implementation (and perhaps documentation). Summary: - The code and documentation are inconsistent and one or the other has to be fixed. - Backwards compatibility cannot be achieved - either the docs or the code have to be changed. - ImageBase definitly contains a bug which has to be fixed since it uses truncation instead of floor(). - The two possibilities received the following supporters: + center-based: Andreas, Steve, Rupert, Edson, Simon + corner-based: Maarten, Eliana Arguments for center-based: + More intuitive. People from image processing interprete voxels as smapled data which is best represented at the center of the PSF. + If a single coordinate is required for representing a voxel in an algorithm, the center is usually the better choice. + Spacing is not necessarily equal to the extent (not stored in ITK images) of a voxel. + Origin would not have to change when downsampling an image. + Natural expression of formulas for interpolation. + Lower-left(-back) coordinates do not remain lower-left(-back) coordinates after transformations like a 180-degrees rotation. Transformations mandatorily have to return center-based coordinates in order to work. + Voxels do not have to be interpreted as rectangular objects. They could be circles, gaussians, ... + Consistency with DICOM. Arguments for corner-based: + More intuituve. People from graphics/rendering interprete voxels as cubes of color which are easier to handle when represented using corners. + There may be filters assuming corner-based physical coordinates. Non-countig argument for corner-based: - Backwards compatibility of the code. Backwards compatibility cannot be kept anyways since truncation is wrong for negative physical coordinates and has to be replaced by rounding in both proposed solutinos (round or floor). Negative coordinates are also not exotic, they appear as soon as one centers the coordinate frame in a volume, e.g. Please also see the implications of changing the implementation which Rupert mentions in his last post (see additional information). | ||||||||
Additional Information | In the following sections, I gathered all the messages on this issue posted on the ITK users list: 2007-12-14 to 2007-12-19 (4 messages) 2008-01-08 to 2008-01-09 (3 messages) 2008-01-29 to 2008-01-30 (6 messages) --------------------------------------------------------------- Hi, I think I have discovered an inconsistency between the ITK Software Guide (p.40) and the implementation of itk::Image (all the methods taking physical points / continuous indices as arguments): The trunctation of continuous index coordinates to integers does not yield the correct pixel coordinates as expected by looking at the definition in the software guide. A simple example is: Image spacing: 1mm Image origin: 0mm/0mm The pixel with index (1/1) would (according to the software guide) have the following extents: 0.5mm/0.5mm to 1.5mm/1.5mm However, the physical point 0.6mm/0.6mm gets mapped to the index 0/0 by the method TransformPhysicalPointToIndex. The solution would be to check those conversion methods as well as others (like IsInside) and replace integer truncations with rounding. If my reasoning is correct, I'll file a bug report. However, I'd like to have some confirmation first. Thanks, Andreas. --------------------------------------------------------------- Hi Andreas, I agree with you that according to the software guide, mapping (0.6, 0.6) should yield an index of (0,0). On the other hand, I think that the definition of origin in the software guide is not intuitive. It says "the image origin is associated with the co-ordinates of the first pixel in the image". Probably, it would be more accurate to say that the image origin is associated with the >center< of the first pixel in the image. However, by using this definition, the extent of an image with origin (0,0) contains negative co-ordinates. I would find it more intuitive if the extent of such an image is something like (0,0) - (size1, size2). This would be the case if the origin of the image is associated with the bottom-left corner of the first pixel. If in the itk code, the origin of an itk image co-incides with the bottom left corner of the first pixel, then I would prefer to change the software guide and not the code. Best regards Maarten Nieber --------------------------------------------------------------- Hi Maarten, thank you for your reply (which other list subscribers may find below). My initial posting was biased towards changing the ITK implementation rather than the documentation for the following reasons: Working with the physical coordinates of a voxel usually means that one needs a single coordinate representation of a voxel. Algorithms relying one this single physical coordinate would usually prefer the center of a voxel for their space-related computations. Moreover, ITK images only reflect the spacing between voxels which is not necessarily equal to the width of a voxel. I am pretty sure that there are cases where the voxel width is smaller than the spacing (in CT for example). In this case, the term "spacing" would also be ambigious if it would not refer to the distance between adjacent voxels' centers. What do others think about this? I would appreciate a clearification as the definitions of image origin and spacing really matter for my application in 3D reconstruction. Thank you, Andreas. --------------------------------------------------------------- Hi Andreas, with respect to the "co-ordinate representation of a voxel", I'm not completely sure what you mean, but I think that for the conversion between index and physical point, the following functions are needed: - given a physical point, there should be a function that returns the index of the pixel that contains this physical point. - given a pixel index, there should be a function that returns the physical point at the center of this pixel. In my opinion, for an 2x2 image with spacing: 1mm and origin: 0mm/0mm, the function PhysicalPointToIndex( 0.6, 0.6 ) should return the index (0,0). The function IndexToPhysicalPointAtPixelCenter( 0, 0 ) should return the point (0.5, 0.5). The extent of the image should be (0,0) - (2,2). (Of course, the function arguments should be itkPoint, I simplified the notation). Again, this is just my preference. Best regards Maarten --------------------------------------------------------------- Dear all, I would like to try a restart of the discussion related to the definition of physical coordinates if ITK images: As mentioned in my earlier post (see below), the documentation and implementation differ in this point. The two proposed solutions are either fixing the documentation (ITK Software Guide, p. 40) and defining the origin to lie in the "lower-left(-back)" corner of the pixel with index 0/0(/0) or fixing the implementation of the respective methods (IndexToPhysicalPoint, PhysicalPointToIndex, etc.) and defining the origin to lie in the center of this pixel. So far, only Maarten and I were discussing about this, with him favoring to fix the docs and me favoring to fix the implementation. Another argument I found for my preference is that the origin would not have to change when downsampling an image. I think that the personal preference for one of the two options we have basically depends on whether one is more interested in the overall dimensions of a dataset or whether one has to do voxel-wise operations depending on the physical coordinate. --> Therefore, I strongly ask other ITK users and developers to take part in this discussion so that we can make a decision. This problem is really of high importance since it is related to the core of the lib (namely the ImageBase class) and it has a big influence on reconstruction problems. As soon as we have come to a conclusion, I would file a bug report with the proposed solution. Thank you, Andreas. --------------------------------------------------------------- Hello Andreas, I think you're right: the docs are correct but the code is buggy. On Tue, Jan 08, 2008 at 10:37:32AM +0100, Andreas Keil wrote: > As mentioned in my earlier post (see below), the documentation and > implementation differ in this point. The two proposed solutions are either > fixing the documentation (ITK Software Guide, p. 40) and defining the > origin to lie in the "lower-left(-back)" corner of the pixel with index > 0/0(/0) or fixing the implementation of the respective methods > (IndexToPhysicalPoint, PhysicalPointToIndex, etc.) and defining the origin > to lie in the center of this pixel. Right. I find the centre-based coordinate convention to be much more natural; e.g. when writing out formulas for interpolation. If you're taking votes, put me down for the centre. I think the centre-based coordinate convention is more common with image processing folk, whereas the corner-based convention is more common in graphics circles. For what it's worth, VTK's image data is said to use the centre-based coordinate system [1]. On the other hand, VTK uses corner convention for screen pixel coordinates, and I suspect this confusion underlies the problems in VTK's coordinate conversion routines [2]. [1] http://public.kitware.com/pipermail/vtk-developers/2005-November/003825.html [^] [2] http://www.vtk.org/Bug/view.php?id=5111 [^] [Message by Steve M. Robbins] --------------------------------------------------------------- Hi, Independent of using center-based or corner-based data location, the actual implementation of PhysicalPoint To Index uses TRUNCATION as a rounding mode, and this is plain wrong (it is implementing neither of the solutions). If you allow a negative Origin (e.g., (-0.4, -0.4)), then you could have one pixel with coordinate at -0.4 mapped to 0.0, and then the next pixel with coordinate at 0.6 mapped to 0.0 again. I suggest using Floor (corner-based approach) or proper Rounding (center-based approach). Whatever solution is chosen, I think it should also be reflected in itk::OrientedImage. Whatever solution is chosen, the data location can be changed from center to corner and vice versa through a shift of the Origin (by Spacing/2 for itk::Image or by Direction*Spacing*(0.5,0.5,0.5) for itk::OrientedImage); because of this, I would suggest to take the approach that breaks less code. [Message by Edson Tadeu] --------------------------------------------------------------- Hi Andreas, I agree with you that this issue is of very high importance! -- quote from your previous post -- I think that the personal preference for one of the two options we have basically depends on whether one is more interested in the overall dimensions of a dataset or whether one has to do voxel-wise operations depending on the physical coordinate. -- end quote -- Can you explain why you think - for doing voxel-wise operations - it would be better if the image origin co-incides with the center of a pixel? Best regards, Maarten --------------------------------------------------------------- Hello Maarten and Andreas, and it-users I would vote to better change the documentation than the code. I don't know for sure, but I suppose there are some fitlers that already assume the origin to be set in the lower-left-back (llb) corner in the image. Eliana --------------------------------------------------------------- Dear all, let me elaborate why I am voting for a center-based coordinate system: Let's consider the simple example of resampling an image. The resample filter does the following for every output pixel: 1) Calculate the physical coordinate for the given output index. 2) Transform the physical coordinate by the given transform. 3) Calculate the continuous index for the transformed physical point. 4) Linearly interpolate the input value at the continuous index and write it to the output. Now, think about this process with corner-based coordinated: 1) Would work fine. 2) Transforms are there for converting physical coordinates. Giving them corner coordinates would, of course, work, too. However, the interpolation in step 4 is done based on a single point representing the whole pixel. In general, we don't have an idea on how the box of a pixel is transformed. We can just pass a single coordinate through through to the interpolator. Keep this in mind for now. 3) Works fine. 4) Now we have a problem with a corner-based physical point having been transformed: The interpolator has to decide, which closest pixels to take into account for interpolation (and how to weight them). This would be a problem even for a the linear interpolator. How should it know, which 4 pixels (in the 2D case) to take? The problem is, that the interpolator has to estimate the location of the backward warped input pixel. This is never really possible due to the unknown transformation. But the guess of a center-based rectangle is better than guessing a corner-based rectangle (where you don't know, which of the corners is given). A numerical example (sorry, I was too lazy to paint): Let's resample a 2D image with an input and output spacing of 1mm x 1mm. We want to interpolate the output pixel at (0mm..1mm,0mm..1mm) which has the corner coordinates (0mm,0mm). A) For a translation of (0.1mm,0.2mm), we get an input coordinate at (0.1mm,0.2mm) and now have to decide, which image range of 2x2 pixels to use for interpolation. Since we translated a bit in positive x and y direction, we should use the pixels at (0mm..2mm,0mm..2mm). Alright. So the rule should be to round the physical coordinate and this yields the lower left corner of our 2x2 pixels interpolation region. B) Let's try a different transformation: A 180 deg. rotation around (0mm,0mm) and a subsequent translation of (0.1mm,0.2mm). We again compute (0.1mm,0.2mm) as input coordinate. So let's follow the rule and use again (0mm..2mm,0mm..2mm) as interpolation region. Ups! We should have used (-1mm..1mm,-1mm..1mm) instead! (You can see this by also transforming the "upper-right" corner output pixel which is (1mm,1mm) giving (-0.9mm,-0.8mm) as input corner. Therfore, the output pixel lies at (-0.9mm..0.1mm,-0.8mm..0.2mm). This input pixel overlaps the 4 input pixels in the region (-1mm..1mm,-1mm..1mm) as stated above.) Conclusion: The transformed corner coordinate in reality is no longer a "lower-left" corner but how should the interpolater have guessed that? The only remedy would be that every class using a transformation would not only transform one single coordinate per pixel but all 4 (in 2D) or 8 (in 3D) corners. Nobody wants this. Guessing an input region after having backward warped a pixel's center is much easier and faster. (Although I would opt for taking circles instead of rectangles here, but that's another issue.) Hopefully, I made my point clear that a pixel's center coordinate is the more useful representation for it than its corner coordinate. I am pretty sure, the original developers or writer of the docs had this point in mind when the wrote the Software Guide. And since the implementation is flawed anyways, and since a lot of classes could not be adopted to corner-based coordinates, I still strongly vote for center-based ones. This "physical point of view" is also more in the style of ITK than the "computer science point of view". ITK developers should not think in pixels but rather in millimeters. Thanks for reading. Waiting for your replies, Andreas. --------------------------------------------------------------- Hi Andreas, This is an important issue, particularly for anyone attempting to do subpixel accuracy registration. I also agree that the coordinate of a pixel should be the center of that pixel. This is because I tend to think of images as sampled signals - ie functions convolved with PSF and then a comb function - so they dont really have width as such. If the coordinate is of the corner, for many reasons that you have pointed out, it could lead to strange contradictions or shifts in the effective image position. I got very curious (afraid?) of what the ramifications of this might be... did a little looking. The sticking point is only the TransformPhysicalPointToIndex function as far as i can see. Just to see what kind of horrible problems it would cause if that was changed, i did a quick grep of the ITK 3.4 source code.... This method is really not used much at all - see the bottom of this email. It would probably be possible to change it to conform to the definition. I took a look to see what the NearestNeighborInterpolator does - it uses the "ConvertContinuousIndexToNearestIndex" function, which, you guessed it, rounds. Here it is (from itkImageFunction.h): /** Convert continuous index to nearest index. */ void ConvertContinuousIndexToNearestIndex( const ContinuousIndexType & cindex, IndexType & index ) const { typedef typename IndexType::IndexValueType ValueType; for ( unsigned int j = 0; j < ImageDimension; j++ ) { index[j] = static_cast<ValueType>( vnl_math_rnd( cindex[j] ) ); } } Its also interesting to note that TransformPhysicalPointToIndex is the slowest of the World to Image coordinate conversions, at least on Intel processors, because truncation is remarkably slower than rounding on those machines. (See this article for discussion http://www.mega-nerd.com/FPcast/ [^]). But, this is probably starting to digress from the original topic. Cheers, Rupert B. Heres the list of files that contain references to TransformPhysicalPointToIndex sutton:/home/scratch/rbrook/InsightToolkit-CVS/src/Insight/Code> grep -Rl 'TransformPhysicalPointToIndex' . ./Algorithms/itkBioCellularAggregate.txx ./Algorithms/itkEuclideanDistancePointMetric.txx ./BasicFilters/itkBloxBoundaryPointImageToBloxBoundaryProfileImageFilter.txx ./BasicFilters/itkBloxBoundaryPointToCoreAtomImageFilter.txx ./BasicFilters/itkBloxBoundaryProfileImageToBloxCoreAtomImageFilter.txx ./BasicFilters/itkGradientImageToBloxBoundaryPointImageFilter.txx ./BasicFilters/itkPointSetToImageFilter.txx ./BasicFilters/itkPolylineMask2DImageFilter.txx ./BasicFilters/itkPolylineMaskImageFilter.txx ./BasicFilters/itkWarpMeshFilter.txx ./Common/itkImage.h ./Common/itkImageAdaptor.h ./Common/itkImageTransformHelper.h ./Common/itkOrientedImage.h ./Common/itkPhasedArray3DSpecialCoordinatesImage.h ./Common/itkSpecialCoordinatesImage.h ./Common/itkVectorImage.h ./Numerics/FEM/itkFEMSolver.cxx ./Numerics/Statistics/itkJointDomainImageToListAdaptor.h --------------------------------------------------------------- I completely agree.. the "pixel" (or voxel) do not have even to be rectangular... or the same size of the Spacing. They could be tiny circles... or gaussians... or even tiny dots (dirac delta). E.g., in visualization, when you consider the common linear interpolation, they have a width of twice the Spacing (overlapping each other); considering bi-cubic or other kinds of interpolation (Lanczos, etc.), they are even larger. I vote for the center-based location approach (rounding mode), but an easy way to switch to vertex-based should be available (maybe through a flag bit and a shift in the Origin), because there may be some applications where vertex-based information is more natural (finite elements, PDE, etc.). As a note, there should always be an unambiguous (non-overlapping) pixel domain [e.g., equivalent to the Voronoi diagram]. Even in the center-based location, there are still an issue to be resolved: the domain of the boundary pixels. For example, for a 3x3 image, origin (0.0, 0.0), spacing (1.0, 1.0), the domain of each pixel it would be something like this: Pix [0,0]: [-Inf, -Inf] <= x < [0.5, 0.5] Pix [1,0]: [-Inf, 0.5] <= x < [0.5, 1.5] Pix [2,0]: [-Inf, 1.5] <= x < [0.5, Inf] Pix [0,1]: [0.5, -Inf] <= x < [1.5, 0.5] Pix [1,1]: [0.5, 0.5] <= x < [1.5, 1.5] Pix [2,1]: [0.5, 1.5] <= x < [1.5, Inf] Pix [0,2]: [1.5, -Inf] <= x < [Inf, 0.5] Pix [1,2]: [1.5, 0.5] <= x < [Inf, 1.5] Pix [2,2]: [1.5, 1.5] <= x < [Inf, Inf] Note that there are three options to the domain of the boundary pixels: 1) Extend them to infinity (as I did) 2) Extend them so that they have the same "size" of the inner pixels. In this case, the "image domain" would be (-0.5,-0.5) <= x < (2.5, 2.5) 3) Extend them to half (or 1/4) the size of the inner pixels, towards them. In this case, the "image domain" would be (0.0, 0.0) <= x < (2.0, 2.0), but the boundary pixels would be at the *vertices* of their domains. Here is a fixed-width font diagram exemplifying it: | | | | (-0.5,2.5) | | (2.5,2.5) +.......+.......+.......+ . | | . . [0,2].|.[1,2].|.[2,2] . . . | | . . -----+-------+-------+-------+----- . . | | . . . [0,1] | [1,1] | [2,1] . . . | | . . -----+-------+-------+-------+----- . . | | . . . [0,0].|.[1,0].|.[2,0] . . | | . +.......+.......+.......+ (-0.5,-0.5) | | (2.5,-0.5) | | | | Options 1 seems more natural to me, and it is explicit that this "image domain" (Infinity) does not correspond to the real "image metrics" (0.0, 0.0) to (3.0, 3.0). Option 2 seems natural too, but note that *many* people will assume that the "image domain" corresponds to the "image metrics", i.e., the image domain to start at the Origin: (0.0, 0.0) to (3.0, 3.0) in this case. A solution would be to shift the Origin by (-0.5, -0.5), but then, again, we would be moving the information location from the center to the vertices ;). Edson --------------------------------------------------------------- I think it is best to use the center of the voxel to be consistent with DICOM. In DICOM files, the Image Position (Patient) tag, which is frequently used to define the origin when reading DICOM files into ITK, gives the location of the center of the first voxel. C.7.6.2.1.1 Image Position And Image Orientation. The Image Position (0020,0032) specifies the x, y, and z coordinates of the upper left hand corner of the image; it is the center of the first voxel transmitted. [Message by Simon Warfield] --------------------------------------------------------------- | ||||||||
Tags | No tags attached. | ||||||||
Resolution Date | |||||||||
Sprint | |||||||||
Sprint Status | backlog | ||||||||
Attached Files | itk-bug6558.patch [^] (8,647 bytes) 2008-11-27 10:54 [Show Content] [Hide Content]? toto.txt Index: CMakeLists.txt =================================================================== RCS file: /cvsroot/Insight/Insight/CMakeLists.txt,v retrieving revision 1.324 diff -u -r1.324 CMakeLists.txt --- CMakeLists.txt 21 Nov 2008 16:23:48 -0000 1.324 +++ CMakeLists.txt 25 Nov 2008 13:56:29 -0000 @@ -240,6 +240,13 @@ OPTION(ITK_USE_ORIENTED_IMAGE_DIRECTION "Turn on correct use of oriented images direction in gradient computation and image registration." ON) MARK_AS_ADVANCED(ITK_USE_ORIENTED_IMAGE_DIRECTION) + +#----------------------------------------------------------------------------- +# ITK turn on the correct usage of centered-pixel coordinates. +OPTION(ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY "Turn on correct usage of centered-pixel coordinates." ON) +MARK_AS_ADVANCED(ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY) + + #----------------------------------------------------------------------------- # ITK turn on the use of Template Meta Programming techniques for unrolling loops of array-like operations OPTION(ITK_USE_TEMPLATE_META_PROGRAMMING_LOOP_UNROLLING "Turn on the use of Template Meta-Programming techniques for unrolling for-loops at compile time." ON) Index: itkConfigure.h.in =================================================================== RCS file: /cvsroot/Insight/Insight/itkConfigure.h.in,v retrieving revision 1.29 diff -u -r1.29 itkConfigure.h.in --- itkConfigure.h.in 13 Sep 2008 14:23:58 -0000 1.29 +++ itkConfigure.h.in 25 Nov 2008 13:56:29 -0000 @@ -83,6 +83,7 @@ #cmakedefine ITK_USE_TRANSFORM_IO_FACTORIES #cmakedefine ITK_USE_ORIENTED_IMAGE_DIRECTION #cmakedefine ITK_IMAGE_BEHAVES_AS_ORIENTED_IMAGE +#cmakedefine ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY #cmakedefine ITK_USE_TEMPLATE_META_PROGRAMMING_LOOP_UNROLLING #cmakedefine ITK_USE_DEPRECATED_LEVELSET_INTERPOLATION #cmakedefine ITK_USE_REVIEW Index: Code/Common/itkImageBase.h =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkImageBase.h,v retrieving revision 1.75 diff -u -r1.75 itkImageBase.h --- Code/Common/itkImageBase.h 1 Nov 2008 15:28:00 -0000 1.75 +++ Code/Common/itkImageBase.h 25 Nov 2008 13:56:31 -0000 @@ -344,8 +344,10 @@ virtual void SetSpacing (const float spacing[VImageDimension]); - /** Get the index (discrete) from a physical point. - * Floating point index results are truncated to integers. + /** Get the index (discrete) of a voxel from a physical point. + * Floating point index results are rounded to integers + * if ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY is on + * and truncated otherwise. * Returns true if the resulting index is within the image, false otherwise * \sa Transform */ #ifdef ITK_USE_TEMPLATE_META_PROGRAMMING_LOOP_UNROLLING @@ -374,7 +376,11 @@ { sum += this->m_PhysicalPointToIndex[i][j] * (point[j] - this->m_Origin[j]); } +#ifdef ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY + index[i] = static_cast< IndexValueType>( vnl_math_round(sum) ); +#else index[i] = static_cast< IndexValueType>( sum ); +#endif } // Now, check to see if the index is within allowed bounds Index: Code/Common/itkImageFunction.h =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkImageFunction.h,v retrieving revision 1.47 diff -u -r1.47 itkImageFunction.h --- Code/Common/itkImageFunction.h 17 Oct 2008 13:35:26 -0000 1.47 +++ Code/Common/itkImageFunction.h 25 Nov 2008 13:56:31 -0000 @@ -127,6 +127,10 @@ const ContinuousIndexType & index ) const = 0; /** Check if an index is inside the image buffer. + * If ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY is on, + * we take into account the fact that each voxel has its + * center at the integer coordinate and extends half way + * to the next integer coordinate. * \warning For efficiency, no validity checking of * the input image is done. */ virtual bool IsInsideBuffer( const IndexType & index ) const Index: Code/Common/itkImageFunction.txx =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkImageFunction.txx,v retrieving revision 1.17 diff -u -r1.17 itkImageFunction.txx --- Code/Common/itkImageFunction.txx 17 Oct 2008 13:35:26 -0000 1.17 +++ Code/Common/itkImageFunction.txx 25 Nov 2008 13:56:31 -0000 @@ -77,8 +77,13 @@ for ( unsigned int j = 0; j < ImageDimension; j++ ) { m_EndIndex[j] = m_StartIndex[j] + static_cast<IndexValueType>( size[j] ) - 1; +#ifdef ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY + m_StartContinuousIndex[j] = static_cast<CoordRepType>( m_StartIndex[j] - 0.5 ); + m_EndContinuousIndex[j] = static_cast<CoordRepType>( m_EndIndex[j] + 0.5 ); +#else m_StartContinuousIndex[j] = static_cast<CoordRepType>( m_StartIndex[j] ); m_EndContinuousIndex[j] = static_cast<CoordRepType>( m_EndIndex[j] ); +#endif } } Index: Code/Common/itkImageRegion.h =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkImageRegion.h,v retrieving revision 1.30 diff -u -r1.30 itkImageRegion.h --- Code/Common/itkImageRegion.h 18 Oct 2008 21:13:25 -0000 1.30 +++ Code/Common/itkImageRegion.h 25 Nov 2008 13:56:31 -0000 @@ -25,6 +25,7 @@ #include "itkIndex.h" #include "itkSize.h" #include "itkContinuousIndex.h" +#include "vnl/vnl_math.h" namespace itk { @@ -176,7 +177,7 @@ { return false; } - if( index[i] >= m_Index[i] + static_cast<long>(m_Size[i]) ) + if( index[i] >= (m_Index[i] + static_cast<long>(m_Size[i])) ) { return false; } @@ -184,20 +185,34 @@ return true; } - /** Test if an index is inside */ + /** Test if a continuous index is inside the region. + * If ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY is on, + * we take into account the fact that each voxel has its + * center at the integer coordinate and extends half way + * to the next integer coordinate. + */ template <typename TCoordRepType> bool IsInside(const ContinuousIndex<TCoordRepType,VImageDimension> &index) const { for(unsigned int i=0; i<ImageDimension; i++) { +#ifdef ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY + if( vnl_math_rnd(index[i]) < static_cast<int>( m_Index[i] ) ) +#else if( index[i] < static_cast<TCoordRepType>( m_Index[i] ) ) +#endif { return false; } // bound is the last valid pixel location +#ifdef ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY const TCoordRepType bound = static_cast<TCoordRepType>( - m_Index[i] + static_cast<long>(m_Size[i]) - 1); + m_Index[i] + m_Size[i] - 0.5); +#else + const TCoordRepType bound = static_cast<TCoordRepType>( + m_Index[i] + static_cast<long>(m_Size[i]) - 1); +#endif if( index[i] > bound ) { @@ -208,7 +223,7 @@ } - /** Test if a region (the argument) is completly inside of this region */ + /** Test if a region (the argument) is completely inside of this region */ bool IsInside(const Self ®ion) const { Index: Code/Common/itkImageTransformHelper.h =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkImageTransformHelper.h,v retrieving revision 1.10 diff -u -r1.10 itkImageTransformHelper.h --- Code/Common/itkImageTransformHelper.h 13 Sep 2008 20:13:05 -0000 1.10 +++ Code/Common/itkImageTransformHelper.h 25 Nov 2008 13:56:31 -0000 @@ -20,6 +20,7 @@ #include "itkConceptChecking.h" #include "itkPoint.h" #include "itkMatrix.h" +#include "vnl/vnl_math.h" namespace itk { @@ -173,7 +174,12 @@ const DoublePoint &, DoublePoint &rindex, IndexType &index, const UniqueTypeBoolTrue& ) { +#ifdef ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY + index[R] = static_cast<typename IndexType::IndexValueType>( + vnl_math_rnd(rindex[R]) ); +#else index[R] = static_cast<typename IndexType::IndexValueType>(rindex[R]); +#endif } // @@ -308,7 +314,12 @@ const FloatPoint &, FloatPoint &rindex, IndexType &index, const UniqueTypeBoolTrue& ) { +#ifdef ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY + index[R] = static_cast<typename IndexType::IndexValueType>( + vnl_math_rnd(rindex[R]) ); +#else index[R] = static_cast<typename IndexType::IndexValueType>(rindex[R]); +#endif } }; CenteredPixelCoordinatesMay-5-2009.patch [^] (24,119 bytes) 2009-05-05 16:26 [Show Content] [Hide Content] ? CenteredPixelCoordinatesMay-5-2009.patch Index: CMakeLists.txt =================================================================== RCS file: /cvsroot/Insight/Insight/CMakeLists.txt,v retrieving revision 1.334 diff -u -p -r1.334 CMakeLists.txt --- CMakeLists.txt 2 May 2009 05:43:54 -0000 1.334 +++ CMakeLists.txt 5 May 2009 20:25:03 -0000 @@ -257,6 +257,13 @@ ENDIF(ITK_USE_TRANSFORM_IO_FACTORIES) OPTION(ITK_USE_ORIENTED_IMAGE_DIRECTION "Turn on correct use of oriented images direction in gradient computation and image registration." ON) MARK_AS_ADVANCED(ITK_USE_ORIENTED_IMAGE_DIRECTION) + +#----------------------------------------------------------------------------- +# ITK turn on the correct usage of centered-pixel coordinates. +OPTION(ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY "Turn on correct usage of centered-pixel coordinates." ON) +MARK_AS_ADVANCED(ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY) + + #----------------------------------------------------------------------------- # ITK turn on the use of Template Meta Programming techniques for unrolling loops of array-like operations OPTION(ITK_USE_TEMPLATE_META_PROGRAMMING_LOOP_UNROLLING "Turn on the use of Template Meta-Programming techniques for unrolling for-loops at compile time." ON) Index: itkConfigure.h.in =================================================================== RCS file: /cvsroot/Insight/Insight/itkConfigure.h.in,v retrieving revision 1.30 diff -u -p -r1.30 itkConfigure.h.in --- itkConfigure.h.in 2 May 2009 05:43:54 -0000 1.30 +++ itkConfigure.h.in 5 May 2009 20:25:03 -0000 @@ -84,6 +84,7 @@ #cmakedefine ITK_USE_TRANSFORM_IO_FACTORIES #cmakedefine ITK_USE_ORIENTED_IMAGE_DIRECTION #cmakedefine ITK_IMAGE_BEHAVES_AS_ORIENTED_IMAGE +#cmakedefine ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY #cmakedefine ITK_USE_TEMPLATE_META_PROGRAMMING_LOOP_UNROLLING #cmakedefine ITK_USE_DEPRECATED_LEVELSET_INTERPOLATION #cmakedefine ITK_USE_REVIEW Index: Code/BasicFilters/itkBloxBoundaryPointImageToBloxBoundaryProfileImageFilter.txx =================================================================== RCS file: /cvsroot/Insight/Insight/Code/BasicFilters/itkBloxBoundaryPointImageToBloxBoundaryProfileImageFilter.txx,v retrieving revision 1.43 diff -u -p -r1.43 itkBloxBoundaryPointImageToBloxBoundaryProfileImageFilter.txx --- Code/BasicFilters/itkBloxBoundaryPointImageToBloxBoundaryProfileImageFilter.txx 6 Apr 2009 16:49:27 -0000 1.43 +++ Code/BasicFilters/itkBloxBoundaryPointImageToBloxBoundaryProfileImageFilter.txx 5 May 2009 20:25:03 -0000 @@ -26,11 +26,6 @@ #include "itkCumulativeGaussianOptimizer.h" #include "itkCumulativeGaussianCostFunction.h" -typedef vnl_matrix<double> MatrixType; -typedef vnl_vector<double> VectorType; - -const double INV_SQRT_TWO_PI = 0.398942280401; // 1/vcl_sqrt(2*pi) -const double SQUARE_ROOT_OF_TWO = 1.41421356237; // vcl_sqrt(2) namespace itk { @@ -89,10 +84,10 @@ BloxBoundaryPointImageToBloxBoundaryProf { m_Accumulator[binNumber] += weight * sourcePixelValue; m_Normalizer[binNumber] += weight; - return(1); + return 1; } - else - return(0); + + return 0; } template< typename TSourceImage > @@ -109,7 +104,9 @@ BloxBoundaryPointImageToBloxBoundaryProf for(unsigned int j = 0; j < m_NumberOfBins; ++j) { if(temp >= maximum) + { maximum = temp; + } } } return maximum; @@ -128,7 +125,9 @@ BloxBoundaryPointImageToBloxBoundaryProf for(unsigned int j = 0; j < m_NumberOfBins; ++j) { if(temp <= minimum) + { minimum = temp; + } } } return minimum; @@ -231,8 +230,12 @@ BloxBoundaryPointImageToBloxBoundaryProf = dynamic_cast<SourceImageType*>(ProcessObject::GetInput(1)); OutputImagePointer outputPtr = this->GetOutput(0); + typedef typename TSourceImage::RegionType RegionType; + + const RegionType bufferedRegion = outputPtr->GetRequestedRegion(); + // Allocate the output - outputPtr->SetBufferedRegion( outputPtr->GetRequestedRegion() ); + outputPtr->SetBufferedRegion( bufferedRegion ); outputPtr->Allocate(); // Create an iterator to walk the boundary point image @@ -243,10 +246,9 @@ BloxBoundaryPointImageToBloxBoundaryProf // Count number of iterated boundary points unsigned int bpCount = 0; -//////////////////////////////////////////////// -//////////OPTIMIZER INITIALIZATION////////////// -//////////////////////////////////////////////// - + //////////////////////////////////////////////// + //////////OPTIMIZER INITIALIZATION////////////// + //////////////////////////////////////////////// // Iterate through the bp image (all pixels) and look for boundary profiles for ( bpIt.GoToBegin(); !bpIt.IsAtEnd(); ++bpIt) @@ -351,10 +353,10 @@ BloxBoundaryPointImageToBloxBoundaryProf int binNumber = (int) (vectorRatio * m_NumberOfBins); double binJitter = (vectorRatio * m_NumberOfBins) - binNumber; - typename TSourceImage::PixelType sourcePixelValue; + typedef typename TSourceImage::PixelType SourcePixelType; // Get the value of the pixel - sourcePixelValue = sourcePtr->GetPixel(sfi.GetIndex()); + const SourcePixelType sourcePixelValue = sfi.Get(); // Gaussian Splat - Project Gaussian weighted pixel intensities along major axis of ellipsoid (sampling region) if(m_SplatMethod == 0) @@ -416,7 +418,9 @@ BloxBoundaryPointImageToBloxBoundaryProf PositionType optimalBoundaryLocation; for(unsigned int i = 0; i < NDimensions; i++) + { optimalBoundaryLocation[i] = boundaryProfile->GetOptimalBoundaryLocation()[i]; + } // Figure out the data space coordinates of the optimal boundary location IndexType boundaryProfilePosition; @@ -424,10 +428,13 @@ BloxBoundaryPointImageToBloxBoundaryProf // Transform optimal boundary location to an index outputPtr->TransformPhysicalPointToIndex(optimalBoundaryLocation, boundaryProfilePosition); - // Store the new boundary profile in the correct spot in output image - outputPtr->GetPixel(boundaryProfilePosition).push_back(boundaryProfile); + if( bufferedRegion.IsInside( boundaryProfilePosition ) ) + { + // Store the new boundary profile in the correct spot in output image + outputPtr->GetPixel(boundaryProfilePosition).push_back(boundaryProfile); + m_NumBoundaryProfiles++; + } - m_NumBoundaryProfiles++; } bpCount++; } Index: Code/BasicFilters/itkGradientImageToBloxBoundaryPointImageFilter.txx =================================================================== RCS file: /cvsroot/Insight/Insight/Code/BasicFilters/itkGradientImageToBloxBoundaryPointImageFilter.txx,v retrieving revision 1.12 diff -u -p -r1.12 itkGradientImageToBloxBoundaryPointImageFilter.txx --- Code/BasicFilters/itkGradientImageToBloxBoundaryPointImageFilter.txx 19 Jan 2008 19:50:01 -0000 1.12 +++ Code/BasicFilters/itkGradientImageToBloxBoundaryPointImageFilter.txx 5 May 2009 20:25:03 -0000 @@ -154,12 +154,9 @@ GradientImageToBloxBoundaryPointImageFil // we need to compute the output spacing, the output image size, and the // output image start index - const typename TInputImage::SpacingType& - inputSpacing = inputPtr->GetSpacing(); - const typename TInputImage::SizeType& inputSize - = inputPtr->GetLargestPossibleRegion().GetSize(); - const typename TInputImage::IndexType& inputStartIndex - = inputPtr->GetLargestPossibleRegion().GetIndex(); + const typename TInputImage::SpacingType& inputSpacing = inputPtr->GetSpacing(); + const typename TInputImage::SizeType& inputSize = inputPtr->GetLargestPossibleRegion().GetSize(); + const typename TInputImage::IndexType& inputStartIndex = inputPtr->GetLargestPossibleRegion().GetIndex(); typename TOutputImage::SpacingType outputSpacing; typedef typename SizeType::SizeValueType SizeValueType; @@ -205,11 +202,14 @@ GradientImageToBloxBoundaryPointImageFil OutputImagePointer outputPtr = this->GetOutput(0); // Allocate the output - outputPtr->SetBufferedRegion( outputPtr->GetRequestedRegion() ); + typename TOutputImage::RegionType outputRequestedRegion = outputPtr->GetRequestedRegion(); + outputPtr->SetBufferedRegion( outputRequestedRegion ); outputPtr->Allocate(); + typename TInputImage::RegionType inputRequestedRegion = inputPtr->GetRequestedRegion(); + // Create a progress reporter - ProgressReporter progress(this, 0, inputPtr->GetRequestedRegion().GetNumberOfPixels()); + ProgressReporter progress(this, 0, inputRequestedRegion.GetNumberOfPixels()); // Position to figure out pixel location TPositionType inputPosition; @@ -217,15 +217,13 @@ GradientImageToBloxBoundaryPointImageFil // Create an iterator to walk the input image typedef ImageRegionConstIterator<TInputImage> TInputIterator; - TInputIterator inputIt = TInputIterator(inputPtr, - inputPtr->GetRequestedRegion() ); + TInputIterator inputIt = TInputIterator(inputPtr, inputRequestedRegion ); // Keep track of how many boundary points we found (for debugging) unsigned long int numBP = 0; unsigned long int numBPadded = 0; // Get the index of the pixel - typename TInputImage::IndexType inputIndex; IndexType bloxIndex; for ( inputIt.GoToBegin(); !inputIt.IsAtEnd(); ++inputIt) @@ -235,7 +233,8 @@ GradientImageToBloxBoundaryPointImageFil for(unsigned int i = 0; i < NDimensions; i++) { - mag += inputIt.Get()[i] * inputIt.Get()[i]; + const double component = inputIt.Get()[i]; + mag += component * component; } mag = vcl_sqrt(mag); @@ -246,7 +245,7 @@ GradientImageToBloxBoundaryPointImageFil numBP++; // Get the index of the boundary pixel - inputIndex = inputIt.GetIndex(); + const typename TInputImage::IndexType & inputIndex = inputIt.GetIndex(); // Convert the index of the input pixel to the physical location of the // boundary point in the input image @@ -255,12 +254,17 @@ GradientImageToBloxBoundaryPointImageFil // Transform the physical location to a blox index outputPtr->TransformPhysicalPointToIndex(inputPosition, bloxIndex); - // Create a new boundary point item and set its parameters - BloxBoundaryPointItem<NDimensions>* pItem = new BloxBoundaryPointItem<NDimensions>; - pItem->SetPhysicalPosition(inputPosition); - pItem->SetGradient( inputIt.Get() ); + // check if it is inside of the output image. + if( outputRequestedRegion.IsInside( bloxIndex ) ) + { + // Create a new boundary point item and set its parameters + BloxBoundaryPointItem<NDimensions>* pItem = new BloxBoundaryPointItem<NDimensions>; + pItem->SetPhysicalPosition(inputPosition); + pItem->SetGradient( inputIt.Get() ); + + outputPtr->GetPixel(bloxIndex).push_back(pItem); + } - outputPtr->GetPixel(bloxIndex).push_back(pItem); numBPadded++; } Index: Code/Common/itkBSplineDeformableTransform.txx =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkBSplineDeformableTransform.txx,v retrieving revision 1.42 diff -u -p -r1.42 itkBSplineDeformableTransform.txx --- Code/Common/itkBSplineDeformableTransform.txx 7 Nov 2008 19:39:44 -0000 1.42 +++ Code/Common/itkBSplineDeformableTransform.txx 5 May 2009 20:25:03 -0000 @@ -198,7 +198,7 @@ BSplineDeformableTransform<TScalarType, index[j] += static_cast< typename RegionType::IndexValueType >( m_Offset ); size[j] -= - static_cast< typename RegionType::SizeValueType> ( 2 * m_Offset ); + static_cast< typename RegionType::SizeValueType> ( SplineOrder ); m_ValidRegionLast[j] = index[j] + static_cast< typename RegionType::IndexValueType >( size[j] ) - 1; } @@ -664,12 +664,12 @@ BSplineDeformableTransform<TScalarType, { bool inside = true; - if ( !m_ValidRegion.IsInside( index ) ) + if ( !m_ValidRegion.IsStrictlyInside( index ) ) { inside = false; } - if ( inside && m_SplineOrderOdd ) + if ( inside && m_SplineOrderOdd ) // FIXME: This shouldn't be necessary. { typedef typename ContinuousIndexType::ValueType ValueType; for( unsigned int j = 0; j < SpaceDimension; j++ ) Index: Code/Common/itkImageBase.h =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkImageBase.h,v retrieving revision 1.79 diff -u -p -r1.79 itkImageBase.h --- Code/Common/itkImageBase.h 12 Mar 2009 01:11:08 -0000 1.79 +++ Code/Common/itkImageBase.h 5 May 2009 20:25:03 -0000 @@ -352,8 +352,10 @@ public: virtual void SetSpacing (const float spacing[VImageDimension]); - /** Get the index (discrete) from a physical point. - * Floating point index results are truncated to integers. + /** Get the index (discrete) of a voxel from a physical point. + * Floating point index results are rounded to integers + * if ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY is on + * and truncated otherwise. * Returns true if the resulting index is within the image, false otherwise * \sa Transform */ #ifdef ITK_USE_TEMPLATE_META_PROGRAMMING_LOOP_UNROLLING @@ -382,7 +384,11 @@ public: { sum += this->m_PhysicalPointToIndex[i][j] * (point[j] - this->m_Origin[j]); } +#ifdef ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY + index[i] = static_cast< IndexValueType>( vnl_math_round(sum) ); +#else index[i] = static_cast< IndexValueType>( sum ); +#endif } // Now, check to see if the index is within allowed bounds Index: Code/Common/itkImageConstIterator.h =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkImageConstIterator.h,v retrieving revision 1.23 diff -u -p -r1.23 itkImageConstIterator.h --- Code/Common/itkImageConstIterator.h 17 Oct 2008 01:41:59 -0000 1.23 +++ Code/Common/itkImageConstIterator.h 5 May 2009 20:25:03 -0000 @@ -173,6 +173,14 @@ public: m_Buffer = m_Image->GetBufferPointer(); m_Region = region; + const RegionType & bufferedRegion = m_Image->GetBufferedRegion(); + + if( ! bufferedRegion.IsInside( m_Region ) ) + { + itkGenericExceptionMacro("Region " << m_Region + << " is outside of buffered region " << bufferedRegion ); + } + // Compute the start offset m_Offset = m_Image->ComputeOffset( m_Region.GetIndex() ); m_BeginOffset = m_Offset; Index: Code/Common/itkImageConstIteratorWithIndex.txx =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkImageConstIteratorWithIndex.txx,v retrieving revision 1.27 diff -u -p -r1.27 itkImageConstIteratorWithIndex.txx --- Code/Common/itkImageConstIteratorWithIndex.txx 5 Apr 2009 10:56:39 -0000 1.27 +++ Code/Common/itkImageConstIteratorWithIndex.txx 5 May 2009 20:25:03 -0000 @@ -82,6 +82,14 @@ ImageConstIteratorWithIndex<TImage> m_PositionIndex = m_BeginIndex; m_Region = region; + const RegionType & bufferedRegion = m_Image->GetBufferedRegion(); + + if( ! bufferedRegion.IsInside( m_Region ) ) + { + itkGenericExceptionMacro("Region " << m_Region + << " is outside of buffered region " << bufferedRegion ); + } + memcpy(m_OffsetTable, m_Image->GetOffsetTable(), (ImageDimension+1)*sizeof(unsigned long)); Index: Code/Common/itkImageFunction.h =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkImageFunction.h,v retrieving revision 1.47 diff -u -p -r1.47 itkImageFunction.h --- Code/Common/itkImageFunction.h 17 Oct 2008 13:35:26 -0000 1.47 +++ Code/Common/itkImageFunction.h 5 May 2009 20:25:03 -0000 @@ -127,6 +127,10 @@ public: const ContinuousIndexType & index ) const = 0; /** Check if an index is inside the image buffer. + * If ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY is on, + * we take into account the fact that each voxel has its + * center at the integer coordinate and extends half way + * to the next integer coordinate. * \warning For efficiency, no validity checking of * the input image is done. */ virtual bool IsInsideBuffer( const IndexType & index ) const @@ -234,7 +238,8 @@ private: }; -} // end namespace itk +}// end namespace itk + // Define instantiation macro for this template. #define ITK_TEMPLATE_ImageFunction(_, EXPORT, x, y) namespace itk { \ Index: Code/Common/itkImageFunction.txx =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkImageFunction.txx,v retrieving revision 1.17 diff -u -p -r1.17 itkImageFunction.txx --- Code/Common/itkImageFunction.txx 17 Oct 2008 13:35:26 -0000 1.17 +++ Code/Common/itkImageFunction.txx 5 May 2009 20:25:03 -0000 @@ -77,10 +77,14 @@ ImageFunction<TInputImage, TOutput, TCoo for ( unsigned int j = 0; j < ImageDimension; j++ ) { m_EndIndex[j] = m_StartIndex[j] + static_cast<IndexValueType>( size[j] ) - 1; +#ifdef ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY + m_StartContinuousIndex[j] = static_cast<CoordRepType>( m_StartIndex[j] - 0.5 ); + m_EndContinuousIndex[j] = static_cast<CoordRepType>( m_EndIndex[j] + 0.5 ); +#else m_StartContinuousIndex[j] = static_cast<CoordRepType>( m_StartIndex[j] ); m_EndContinuousIndex[j] = static_cast<CoordRepType>( m_EndIndex[j] ); +#endif } - } } Index: Code/Common/itkImageRegion.h =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkImageRegion.h,v retrieving revision 1.30 diff -u -p -r1.30 itkImageRegion.h --- Code/Common/itkImageRegion.h 18 Oct 2008 21:13:25 -0000 1.30 +++ Code/Common/itkImageRegion.h 5 May 2009 20:25:03 -0000 @@ -25,6 +25,7 @@ #include "itkIndex.h" #include "itkSize.h" #include "itkContinuousIndex.h" +#include "vnl/vnl_math.h" namespace itk { @@ -176,7 +177,7 @@ public: { return false; } - if( index[i] >= m_Index[i] + static_cast<long>(m_Size[i]) ) + if( index[i] >= (m_Index[i] + static_cast<long>(m_Size[i])) ) { return false; } @@ -184,20 +185,33 @@ public: return true; } - /** Test if an index is inside */ + /** Test if a continuous index is inside the region. + * If ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY is on, + * we take into account the fact that each voxel has its + * center at the integer coordinate and extends half way + * to the next integer coordinate. */ template <typename TCoordRepType> bool IsInside(const ContinuousIndex<TCoordRepType,VImageDimension> &index) const { for(unsigned int i=0; i<ImageDimension; i++) { +#ifdef ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY + if( vnl_math_rnd(index[i]) < static_cast<int>( m_Index[i] ) ) +#else if( index[i] < static_cast<TCoordRepType>( m_Index[i] ) ) +#endif { return false; } // bound is the last valid pixel location +#ifdef ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY + const TCoordRepType bound = static_cast<TCoordRepType>( + m_Index[i] + m_Size[i] - 0.5); +#else const TCoordRepType bound = static_cast<TCoordRepType>( - m_Index[i] + static_cast<long>(m_Size[i]) - 1); + m_Index[i] + static_cast<long>(m_Size[i]) - 1); +#endif if( index[i] > bound ) { @@ -207,8 +221,33 @@ public: return true; } + /** Test if a continuous index is strictly inside the region. + * This means that no half-pixel border around the image is + * allowed as tolerance. + */ + template <typename TCoordRepType> + bool + IsStrictlyInside(const ContinuousIndex<TCoordRepType,VImageDimension> &index) const + { + for(unsigned int i=0; i<ImageDimension; i++) + { + if( index[i] < static_cast<TCoordRepType>( m_Index[i] ) ) + { + return false; + } + // bound is the last valid pixel location + const TCoordRepType bound = static_cast<TCoordRepType>( + m_Index[i] + static_cast<long>(m_Size[i]) - 1); + + if( index[i] > bound ) + { + return false; + } + } + return true; + } - /** Test if a region (the argument) is completly inside of this region */ + /** Test if a region (the argument) is completely inside of this region */ bool IsInside(const Self ®ion) const { Index: Code/Common/itkImageTransformHelper.h =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkImageTransformHelper.h,v retrieving revision 1.11 diff -u -p -r1.11 itkImageTransformHelper.h --- Code/Common/itkImageTransformHelper.h 5 Feb 2009 19:04:57 -0000 1.11 +++ Code/Common/itkImageTransformHelper.h 5 May 2009 20:25:03 -0000 @@ -20,6 +20,7 @@ #include "itkConceptChecking.h" #include "itkPoint.h" #include "itkMatrix.h" +#include "vnl/vnl_math.h" namespace itk { @@ -173,7 +174,11 @@ public: const DoublePoint &, DoublePoint &rindex, IndexType &index, const UniqueTypeBoolTrue& ) { - index[R] = static_cast<typename IndexType::IndexValueType>(rindex[R]); +#ifdef ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY + index[R] = static_cast<typename IndexType::IndexValueType>( vnl_math_rnd( rindex[R] ) ); +#else + index[R] = static_cast<typename IndexType::IndexValueType>(rindex[R]); +#endif } // @@ -308,7 +313,12 @@ public: const FloatPoint &, FloatPoint &rindex, IndexType &index, const UniqueTypeBoolTrue& ) { +#ifdef ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY + index[R] = static_cast<typename IndexType::IndexValueType>( + vnl_math_rnd(rindex[R]) ); +#else index[R] = static_cast<typename IndexType::IndexValueType>(rindex[R]); +#endif } }; Index: Code/Common/itkLinearInterpolateImageFunction.txx =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkLinearInterpolateImageFunction.txx,v retrieving revision 1.41 diff -u -p -r1.41 itkLinearInterpolateImageFunction.txx --- Code/Common/itkLinearInterpolateImageFunction.txx 20 Mar 2009 10:25:35 -0000 1.41 +++ Code/Common/itkLinearInterpolateImageFunction.txx 5 May 2009 20:25:03 -0000 @@ -132,11 +132,23 @@ LinearInterpolateImageFunction< TInputIm if ( upper & 1 ) { neighIndex[dim] = baseIndex[dim] + 1; + // Take care of the case where the pixel is just + // in the outer upper boundary of the image grid. + if( neighIndex[dim] > this->m_EndIndex[dim] ) + { + neighIndex[dim] = this->m_EndIndex[dim]; + } overlap *= distance[dim]; } else { neighIndex[dim] = baseIndex[dim]; + // Take care of the case where the pixel is just + // in the outer lower boundary of the image grid. + if( neighIndex[dim] < this->m_StartIndex[dim] ) + { + neighIndex[dim] = this->m_StartIndex[dim]; + } overlap *= 1.0 - distance[dim]; } @@ -147,8 +159,11 @@ LinearInterpolateImageFunction< TInputIm // get neighbor value only if overlap is not zero if( overlap ) { - value += static_cast<RealType>( this->GetInputImage()->GetPixel( neighIndex ) ) * overlap; - totalOverlap += overlap; +// if( this->IsInsideBuffer( neighIndex ) ) + { + value += static_cast<RealType>( this->GetInputImage()->GetPixel( neighIndex ) ) * overlap; + totalOverlap += overlap; + } } if( totalOverlap == 1.0 ) CenteredPixelCoordinatesMay-5-2009-B.patch [^] (27,387 bytes) 2009-05-05 17:57 [Show Content] [Hide Content] Index: CMakeLists.txt =================================================================== RCS file: /cvsroot/Insight/Insight/CMakeLists.txt,v retrieving revision 1.334 diff -u -p -r1.334 CMakeLists.txt --- CMakeLists.txt 2 May 2009 05:43:54 -0000 1.334 +++ CMakeLists.txt 5 May 2009 21:56:25 -0000 @@ -257,6 +257,13 @@ ENDIF(ITK_USE_TRANSFORM_IO_FACTORIES) OPTION(ITK_USE_ORIENTED_IMAGE_DIRECTION "Turn on correct use of oriented images direction in gradient computation and image registration." ON) MARK_AS_ADVANCED(ITK_USE_ORIENTED_IMAGE_DIRECTION) + +#----------------------------------------------------------------------------- +# ITK turn on the correct usage of centered-pixel coordinates. +OPTION(ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY "Turn on correct usage of centered-pixel coordinates." ON) +MARK_AS_ADVANCED(ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY) + + #----------------------------------------------------------------------------- # ITK turn on the use of Template Meta Programming techniques for unrolling loops of array-like operations OPTION(ITK_USE_TEMPLATE_META_PROGRAMMING_LOOP_UNROLLING "Turn on the use of Template Meta-Programming techniques for unrolling for-loops at compile time." ON) Index: itkConfigure.h.in =================================================================== RCS file: /cvsroot/Insight/Insight/itkConfigure.h.in,v retrieving revision 1.30 diff -u -p -r1.30 itkConfigure.h.in --- itkConfigure.h.in 2 May 2009 05:43:54 -0000 1.30 +++ itkConfigure.h.in 5 May 2009 21:56:25 -0000 @@ -84,6 +84,7 @@ #cmakedefine ITK_USE_TRANSFORM_IO_FACTORIES #cmakedefine ITK_USE_ORIENTED_IMAGE_DIRECTION #cmakedefine ITK_IMAGE_BEHAVES_AS_ORIENTED_IMAGE +#cmakedefine ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY #cmakedefine ITK_USE_TEMPLATE_META_PROGRAMMING_LOOP_UNROLLING #cmakedefine ITK_USE_DEPRECATED_LEVELSET_INTERPOLATION #cmakedefine ITK_USE_REVIEW Index: Code/BasicFilters/itkBloxBoundaryPointImageToBloxBoundaryProfileImageFilter.txx =================================================================== RCS file: /cvsroot/Insight/Insight/Code/BasicFilters/itkBloxBoundaryPointImageToBloxBoundaryProfileImageFilter.txx,v retrieving revision 1.43 diff -u -p -r1.43 itkBloxBoundaryPointImageToBloxBoundaryProfileImageFilter.txx --- Code/BasicFilters/itkBloxBoundaryPointImageToBloxBoundaryProfileImageFilter.txx 6 Apr 2009 16:49:27 -0000 1.43 +++ Code/BasicFilters/itkBloxBoundaryPointImageToBloxBoundaryProfileImageFilter.txx 5 May 2009 21:56:25 -0000 @@ -26,11 +26,6 @@ #include "itkCumulativeGaussianOptimizer.h" #include "itkCumulativeGaussianCostFunction.h" -typedef vnl_matrix<double> MatrixType; -typedef vnl_vector<double> VectorType; - -const double INV_SQRT_TWO_PI = 0.398942280401; // 1/vcl_sqrt(2*pi) -const double SQUARE_ROOT_OF_TWO = 1.41421356237; // vcl_sqrt(2) namespace itk { @@ -89,10 +84,10 @@ BloxBoundaryPointImageToBloxBoundaryProf { m_Accumulator[binNumber] += weight * sourcePixelValue; m_Normalizer[binNumber] += weight; - return(1); + return 1; } - else - return(0); + + return 0; } template< typename TSourceImage > @@ -109,7 +104,9 @@ BloxBoundaryPointImageToBloxBoundaryProf for(unsigned int j = 0; j < m_NumberOfBins; ++j) { if(temp >= maximum) + { maximum = temp; + } } } return maximum; @@ -128,7 +125,9 @@ BloxBoundaryPointImageToBloxBoundaryProf for(unsigned int j = 0; j < m_NumberOfBins; ++j) { if(temp <= minimum) + { minimum = temp; + } } } return minimum; @@ -231,8 +230,12 @@ BloxBoundaryPointImageToBloxBoundaryProf = dynamic_cast<SourceImageType*>(ProcessObject::GetInput(1)); OutputImagePointer outputPtr = this->GetOutput(0); + typedef typename TSourceImage::RegionType RegionType; + + const RegionType bufferedRegion = outputPtr->GetRequestedRegion(); + // Allocate the output - outputPtr->SetBufferedRegion( outputPtr->GetRequestedRegion() ); + outputPtr->SetBufferedRegion( bufferedRegion ); outputPtr->Allocate(); // Create an iterator to walk the boundary point image @@ -243,10 +246,9 @@ BloxBoundaryPointImageToBloxBoundaryProf // Count number of iterated boundary points unsigned int bpCount = 0; -//////////////////////////////////////////////// -//////////OPTIMIZER INITIALIZATION////////////// -//////////////////////////////////////////////// - + //////////////////////////////////////////////// + //////////OPTIMIZER INITIALIZATION////////////// + //////////////////////////////////////////////// // Iterate through the bp image (all pixels) and look for boundary profiles for ( bpIt.GoToBegin(); !bpIt.IsAtEnd(); ++bpIt) @@ -351,10 +353,10 @@ BloxBoundaryPointImageToBloxBoundaryProf int binNumber = (int) (vectorRatio * m_NumberOfBins); double binJitter = (vectorRatio * m_NumberOfBins) - binNumber; - typename TSourceImage::PixelType sourcePixelValue; + typedef typename TSourceImage::PixelType SourcePixelType; // Get the value of the pixel - sourcePixelValue = sourcePtr->GetPixel(sfi.GetIndex()); + const SourcePixelType sourcePixelValue = sfi.Get(); // Gaussian Splat - Project Gaussian weighted pixel intensities along major axis of ellipsoid (sampling region) if(m_SplatMethod == 0) @@ -416,7 +418,9 @@ BloxBoundaryPointImageToBloxBoundaryProf PositionType optimalBoundaryLocation; for(unsigned int i = 0; i < NDimensions; i++) + { optimalBoundaryLocation[i] = boundaryProfile->GetOptimalBoundaryLocation()[i]; + } // Figure out the data space coordinates of the optimal boundary location IndexType boundaryProfilePosition; @@ -424,10 +428,13 @@ BloxBoundaryPointImageToBloxBoundaryProf // Transform optimal boundary location to an index outputPtr->TransformPhysicalPointToIndex(optimalBoundaryLocation, boundaryProfilePosition); - // Store the new boundary profile in the correct spot in output image - outputPtr->GetPixel(boundaryProfilePosition).push_back(boundaryProfile); + if( bufferedRegion.IsInside( boundaryProfilePosition ) ) + { + // Store the new boundary profile in the correct spot in output image + outputPtr->GetPixel(boundaryProfilePosition).push_back(boundaryProfile); + m_NumBoundaryProfiles++; + } - m_NumBoundaryProfiles++; } bpCount++; } Index: Code/BasicFilters/itkGradientImageToBloxBoundaryPointImageFilter.txx =================================================================== RCS file: /cvsroot/Insight/Insight/Code/BasicFilters/itkGradientImageToBloxBoundaryPointImageFilter.txx,v retrieving revision 1.12 diff -u -p -r1.12 itkGradientImageToBloxBoundaryPointImageFilter.txx --- Code/BasicFilters/itkGradientImageToBloxBoundaryPointImageFilter.txx 19 Jan 2008 19:50:01 -0000 1.12 +++ Code/BasicFilters/itkGradientImageToBloxBoundaryPointImageFilter.txx 5 May 2009 21:56:25 -0000 @@ -154,12 +154,9 @@ GradientImageToBloxBoundaryPointImageFil // we need to compute the output spacing, the output image size, and the // output image start index - const typename TInputImage::SpacingType& - inputSpacing = inputPtr->GetSpacing(); - const typename TInputImage::SizeType& inputSize - = inputPtr->GetLargestPossibleRegion().GetSize(); - const typename TInputImage::IndexType& inputStartIndex - = inputPtr->GetLargestPossibleRegion().GetIndex(); + const typename TInputImage::SpacingType& inputSpacing = inputPtr->GetSpacing(); + const typename TInputImage::SizeType& inputSize = inputPtr->GetLargestPossibleRegion().GetSize(); + const typename TInputImage::IndexType& inputStartIndex = inputPtr->GetLargestPossibleRegion().GetIndex(); typename TOutputImage::SpacingType outputSpacing; typedef typename SizeType::SizeValueType SizeValueType; @@ -170,11 +167,11 @@ GradientImageToBloxBoundaryPointImageFil for (unsigned int i = 0; i < TOutputImage::ImageDimension; i++) { - outputSpacing[i] = inputSpacing[i] * m_BloxResolution[i]; outputSize[i] = static_cast<SizeValueType>( vcl_floor(static_cast<float>( inputSize[i] )/ m_BloxResolution[i])); + if( outputSize[i] < 1 ) { outputSize[i] = 1; @@ -186,6 +183,25 @@ GradientImageToBloxBoundaryPointImageFil outputPtr->SetSpacing( outputSpacing ); + // compute origin offset + // The physical center's of the input and output should be the same + ContinuousIndex<double, TOutputImage::ImageDimension> inputCenterIndex; + ContinuousIndex<double, TOutputImage::ImageDimension> outputCenterIndex; + for( unsigned int j = 0; j < TOutputImage::ImageDimension; j++ ) + { + inputCenterIndex[j] = inputStartIndex[j] + (inputSize[j] - 1) / 2.0; + outputCenterIndex[j] = outputStartIndex[j] + (outputSize[j] - 1) / 2.0; + } + + typename TOutputImage::PointType inputCenterPoint; + typename TOutputImage::PointType outputCenterPoint; + inputPtr->TransformContinuousIndexToPhysicalPoint(inputCenterIndex, inputCenterPoint); + outputPtr->TransformContinuousIndexToPhysicalPoint(outputCenterIndex, outputCenterPoint); + + typename TOutputImage::PointType outputOrigin = outputPtr->GetOrigin(); + outputOrigin = outputOrigin + (inputCenterPoint - outputCenterPoint); + outputPtr->SetOrigin(outputOrigin); + typename TOutputImage::RegionType outputLargestPossibleRegion; outputLargestPossibleRegion.SetSize( outputSize ); outputLargestPossibleRegion.SetIndex( outputStartIndex ); @@ -205,11 +221,14 @@ GradientImageToBloxBoundaryPointImageFil OutputImagePointer outputPtr = this->GetOutput(0); // Allocate the output - outputPtr->SetBufferedRegion( outputPtr->GetRequestedRegion() ); + typename TOutputImage::RegionType outputRequestedRegion = outputPtr->GetRequestedRegion(); + outputPtr->SetBufferedRegion( outputRequestedRegion ); outputPtr->Allocate(); + typename TInputImage::RegionType inputRequestedRegion = inputPtr->GetRequestedRegion(); + // Create a progress reporter - ProgressReporter progress(this, 0, inputPtr->GetRequestedRegion().GetNumberOfPixels()); + ProgressReporter progress(this, 0, inputRequestedRegion.GetNumberOfPixels()); // Position to figure out pixel location TPositionType inputPosition; @@ -217,15 +236,13 @@ GradientImageToBloxBoundaryPointImageFil // Create an iterator to walk the input image typedef ImageRegionConstIterator<TInputImage> TInputIterator; - TInputIterator inputIt = TInputIterator(inputPtr, - inputPtr->GetRequestedRegion() ); + TInputIterator inputIt = TInputIterator(inputPtr, inputRequestedRegion ); // Keep track of how many boundary points we found (for debugging) unsigned long int numBP = 0; unsigned long int numBPadded = 0; // Get the index of the pixel - typename TInputImage::IndexType inputIndex; IndexType bloxIndex; for ( inputIt.GoToBegin(); !inputIt.IsAtEnd(); ++inputIt) @@ -235,7 +252,8 @@ GradientImageToBloxBoundaryPointImageFil for(unsigned int i = 0; i < NDimensions; i++) { - mag += inputIt.Get()[i] * inputIt.Get()[i]; + const double component = inputIt.Get()[i]; + mag += component * component; } mag = vcl_sqrt(mag); @@ -246,7 +264,7 @@ GradientImageToBloxBoundaryPointImageFil numBP++; // Get the index of the boundary pixel - inputIndex = inputIt.GetIndex(); + const typename TInputImage::IndexType & inputIndex = inputIt.GetIndex(); // Convert the index of the input pixel to the physical location of the // boundary point in the input image @@ -255,12 +273,17 @@ GradientImageToBloxBoundaryPointImageFil // Transform the physical location to a blox index outputPtr->TransformPhysicalPointToIndex(inputPosition, bloxIndex); - // Create a new boundary point item and set its parameters - BloxBoundaryPointItem<NDimensions>* pItem = new BloxBoundaryPointItem<NDimensions>; - pItem->SetPhysicalPosition(inputPosition); - pItem->SetGradient( inputIt.Get() ); + // check if it is inside of the output image. + if( outputRequestedRegion.IsInside( bloxIndex ) ) + { + // Create a new boundary point item and set its parameters + BloxBoundaryPointItem<NDimensions>* pItem = new BloxBoundaryPointItem<NDimensions>; + pItem->SetPhysicalPosition(inputPosition); + pItem->SetGradient( inputIt.Get() ); + + outputPtr->GetPixel(bloxIndex).push_back(pItem); + } - outputPtr->GetPixel(bloxIndex).push_back(pItem); numBPadded++; } Index: Code/Common/itkBSplineDeformableTransform.txx =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkBSplineDeformableTransform.txx,v retrieving revision 1.42 diff -u -p -r1.42 itkBSplineDeformableTransform.txx --- Code/Common/itkBSplineDeformableTransform.txx 7 Nov 2008 19:39:44 -0000 1.42 +++ Code/Common/itkBSplineDeformableTransform.txx 5 May 2009 21:56:25 -0000 @@ -198,7 +198,7 @@ BSplineDeformableTransform<TScalarType, index[j] += static_cast< typename RegionType::IndexValueType >( m_Offset ); size[j] -= - static_cast< typename RegionType::SizeValueType> ( 2 * m_Offset ); + static_cast< typename RegionType::SizeValueType> ( SplineOrder ); m_ValidRegionLast[j] = index[j] + static_cast< typename RegionType::IndexValueType >( size[j] ) - 1; } @@ -664,12 +664,12 @@ BSplineDeformableTransform<TScalarType, { bool inside = true; - if ( !m_ValidRegion.IsInside( index ) ) + if ( !m_ValidRegion.IsStrictlyInside( index ) ) { inside = false; } - if ( inside && m_SplineOrderOdd ) + if ( inside && m_SplineOrderOdd ) // FIXME: This shouldn't be necessary. { typedef typename ContinuousIndexType::ValueType ValueType; for( unsigned int j = 0; j < SpaceDimension; j++ ) Index: Code/Common/itkImageBase.h =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkImageBase.h,v retrieving revision 1.79 diff -u -p -r1.79 itkImageBase.h --- Code/Common/itkImageBase.h 12 Mar 2009 01:11:08 -0000 1.79 +++ Code/Common/itkImageBase.h 5 May 2009 21:56:25 -0000 @@ -352,8 +352,10 @@ public: virtual void SetSpacing (const float spacing[VImageDimension]); - /** Get the index (discrete) from a physical point. - * Floating point index results are truncated to integers. + /** Get the index (discrete) of a voxel from a physical point. + * Floating point index results are rounded to integers + * if ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY is on + * and truncated otherwise. * Returns true if the resulting index is within the image, false otherwise * \sa Transform */ #ifdef ITK_USE_TEMPLATE_META_PROGRAMMING_LOOP_UNROLLING @@ -382,7 +384,11 @@ public: { sum += this->m_PhysicalPointToIndex[i][j] * (point[j] - this->m_Origin[j]); } +#ifdef ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY + index[i] = static_cast< IndexValueType>( vnl_math_round(sum) ); +#else index[i] = static_cast< IndexValueType>( sum ); +#endif } // Now, check to see if the index is within allowed bounds Index: Code/Common/itkImageConstIterator.h =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkImageConstIterator.h,v retrieving revision 1.23 diff -u -p -r1.23 itkImageConstIterator.h --- Code/Common/itkImageConstIterator.h 17 Oct 2008 01:41:59 -0000 1.23 +++ Code/Common/itkImageConstIterator.h 5 May 2009 21:56:25 -0000 @@ -173,6 +173,14 @@ public: m_Buffer = m_Image->GetBufferPointer(); m_Region = region; + const RegionType & bufferedRegion = m_Image->GetBufferedRegion(); + + if( ! bufferedRegion.IsInside( m_Region ) ) + { + itkGenericExceptionMacro("Region " << m_Region + << " is outside of buffered region " << bufferedRegion ); + } + // Compute the start offset m_Offset = m_Image->ComputeOffset( m_Region.GetIndex() ); m_BeginOffset = m_Offset; Index: Code/Common/itkImageConstIteratorWithIndex.txx =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkImageConstIteratorWithIndex.txx,v retrieving revision 1.27 diff -u -p -r1.27 itkImageConstIteratorWithIndex.txx --- Code/Common/itkImageConstIteratorWithIndex.txx 5 Apr 2009 10:56:39 -0000 1.27 +++ Code/Common/itkImageConstIteratorWithIndex.txx 5 May 2009 21:56:25 -0000 @@ -82,6 +82,14 @@ ImageConstIteratorWithIndex<TImage> m_PositionIndex = m_BeginIndex; m_Region = region; + const RegionType & bufferedRegion = m_Image->GetBufferedRegion(); + + if( ! bufferedRegion.IsInside( m_Region ) ) + { + itkGenericExceptionMacro("Region " << m_Region + << " is outside of buffered region " << bufferedRegion ); + } + memcpy(m_OffsetTable, m_Image->GetOffsetTable(), (ImageDimension+1)*sizeof(unsigned long)); Index: Code/Common/itkImageFunction.h =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkImageFunction.h,v retrieving revision 1.47 diff -u -p -r1.47 itkImageFunction.h --- Code/Common/itkImageFunction.h 17 Oct 2008 13:35:26 -0000 1.47 +++ Code/Common/itkImageFunction.h 5 May 2009 21:56:25 -0000 @@ -127,6 +127,10 @@ public: const ContinuousIndexType & index ) const = 0; /** Check if an index is inside the image buffer. + * If ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY is on, + * we take into account the fact that each voxel has its + * center at the integer coordinate and extends half way + * to the next integer coordinate. * \warning For efficiency, no validity checking of * the input image is done. */ virtual bool IsInsideBuffer( const IndexType & index ) const @@ -234,7 +238,8 @@ private: }; -} // end namespace itk +}// end namespace itk + // Define instantiation macro for this template. #define ITK_TEMPLATE_ImageFunction(_, EXPORT, x, y) namespace itk { \ Index: Code/Common/itkImageFunction.txx =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkImageFunction.txx,v retrieving revision 1.17 diff -u -p -r1.17 itkImageFunction.txx --- Code/Common/itkImageFunction.txx 17 Oct 2008 13:35:26 -0000 1.17 +++ Code/Common/itkImageFunction.txx 5 May 2009 21:56:25 -0000 @@ -77,10 +77,14 @@ ImageFunction<TInputImage, TOutput, TCoo for ( unsigned int j = 0; j < ImageDimension; j++ ) { m_EndIndex[j] = m_StartIndex[j] + static_cast<IndexValueType>( size[j] ) - 1; +#ifdef ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY + m_StartContinuousIndex[j] = static_cast<CoordRepType>( m_StartIndex[j] - 0.5 ); + m_EndContinuousIndex[j] = static_cast<CoordRepType>( m_EndIndex[j] + 0.5 ); +#else m_StartContinuousIndex[j] = static_cast<CoordRepType>( m_StartIndex[j] ); m_EndContinuousIndex[j] = static_cast<CoordRepType>( m_EndIndex[j] ); +#endif } - } } Index: Code/Common/itkImageRegion.h =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkImageRegion.h,v retrieving revision 1.30 diff -u -p -r1.30 itkImageRegion.h --- Code/Common/itkImageRegion.h 18 Oct 2008 21:13:25 -0000 1.30 +++ Code/Common/itkImageRegion.h 5 May 2009 21:56:25 -0000 @@ -25,6 +25,7 @@ #include "itkIndex.h" #include "itkSize.h" #include "itkContinuousIndex.h" +#include "vnl/vnl_math.h" namespace itk { @@ -176,7 +177,7 @@ public: { return false; } - if( index[i] >= m_Index[i] + static_cast<long>(m_Size[i]) ) + if( index[i] >= (m_Index[i] + static_cast<long>(m_Size[i])) ) { return false; } @@ -184,20 +185,33 @@ public: return true; } - /** Test if an index is inside */ + /** Test if a continuous index is inside the region. + * If ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY is on, + * we take into account the fact that each voxel has its + * center at the integer coordinate and extends half way + * to the next integer coordinate. */ template <typename TCoordRepType> bool IsInside(const ContinuousIndex<TCoordRepType,VImageDimension> &index) const { for(unsigned int i=0; i<ImageDimension; i++) { +#ifdef ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY + if( vnl_math_rnd(index[i]) < static_cast<int>( m_Index[i] ) ) +#else if( index[i] < static_cast<TCoordRepType>( m_Index[i] ) ) +#endif { return false; } // bound is the last valid pixel location +#ifdef ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY + const TCoordRepType bound = static_cast<TCoordRepType>( + m_Index[i] + m_Size[i] - 0.5); +#else const TCoordRepType bound = static_cast<TCoordRepType>( - m_Index[i] + static_cast<long>(m_Size[i]) - 1); + m_Index[i] + static_cast<long>(m_Size[i]) - 1); +#endif if( index[i] > bound ) { @@ -207,8 +221,33 @@ public: return true; } + /** Test if a continuous index is strictly inside the region. + * This means that no half-pixel border around the image is + * allowed as tolerance. + */ + template <typename TCoordRepType> + bool + IsStrictlyInside(const ContinuousIndex<TCoordRepType,VImageDimension> &index) const + { + for(unsigned int i=0; i<ImageDimension; i++) + { + if( index[i] < static_cast<TCoordRepType>( m_Index[i] ) ) + { + return false; + } + // bound is the last valid pixel location + const TCoordRepType bound = static_cast<TCoordRepType>( + m_Index[i] + static_cast<long>(m_Size[i]) - 1); + + if( index[i] > bound ) + { + return false; + } + } + return true; + } - /** Test if a region (the argument) is completly inside of this region */ + /** Test if a region (the argument) is completely inside of this region */ bool IsInside(const Self ®ion) const { Index: Code/Common/itkImageTransformHelper.h =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkImageTransformHelper.h,v retrieving revision 1.11 diff -u -p -r1.11 itkImageTransformHelper.h --- Code/Common/itkImageTransformHelper.h 5 Feb 2009 19:04:57 -0000 1.11 +++ Code/Common/itkImageTransformHelper.h 5 May 2009 21:56:25 -0000 @@ -20,6 +20,7 @@ #include "itkConceptChecking.h" #include "itkPoint.h" #include "itkMatrix.h" +#include "vnl/vnl_math.h" namespace itk { @@ -173,7 +174,11 @@ public: const DoublePoint &, DoublePoint &rindex, IndexType &index, const UniqueTypeBoolTrue& ) { - index[R] = static_cast<typename IndexType::IndexValueType>(rindex[R]); +#ifdef ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY + index[R] = static_cast<typename IndexType::IndexValueType>( vnl_math_rnd( rindex[R] ) ); +#else + index[R] = static_cast<typename IndexType::IndexValueType>(rindex[R]); +#endif } // @@ -308,7 +313,12 @@ public: const FloatPoint &, FloatPoint &rindex, IndexType &index, const UniqueTypeBoolTrue& ) { +#ifdef ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY + index[R] = static_cast<typename IndexType::IndexValueType>( + vnl_math_rnd(rindex[R]) ); +#else index[R] = static_cast<typename IndexType::IndexValueType>(rindex[R]); +#endif } }; Index: Code/Common/itkLinearInterpolateImageFunction.txx =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkLinearInterpolateImageFunction.txx,v retrieving revision 1.41 diff -u -p -r1.41 itkLinearInterpolateImageFunction.txx --- Code/Common/itkLinearInterpolateImageFunction.txx 20 Mar 2009 10:25:35 -0000 1.41 +++ Code/Common/itkLinearInterpolateImageFunction.txx 5 May 2009 21:56:25 -0000 @@ -132,11 +132,23 @@ LinearInterpolateImageFunction< TInputIm if ( upper & 1 ) { neighIndex[dim] = baseIndex[dim] + 1; + // Take care of the case where the pixel is just + // in the outer upper boundary of the image grid. + if( neighIndex[dim] > this->m_EndIndex[dim] ) + { + neighIndex[dim] = this->m_EndIndex[dim]; + } overlap *= distance[dim]; } else { neighIndex[dim] = baseIndex[dim]; + // Take care of the case where the pixel is just + // in the outer lower boundary of the image grid. + if( neighIndex[dim] < this->m_StartIndex[dim] ) + { + neighIndex[dim] = this->m_StartIndex[dim]; + } overlap *= 1.0 - distance[dim]; } @@ -147,8 +159,11 @@ LinearInterpolateImageFunction< TInputIm // get neighbor value only if overlap is not zero if( overlap ) { - value += static_cast<RealType>( this->GetInputImage()->GetPixel( neighIndex ) ) * overlap; - totalOverlap += overlap; +// if( this->IsInsideBuffer( neighIndex ) ) + { + value += static_cast<RealType>( this->GetInputImage()->GetPixel( neighIndex ) ) * overlap; + totalOverlap += overlap; + } } if( totalOverlap == 1.0 ) Index: Testing/Code/Common/itkMedialNodeCorrespondencesTest.cxx =================================================================== RCS file: /cvsroot/Insight/Insight/Testing/Code/Common/itkMedialNodeCorrespondencesTest.cxx,v retrieving revision 1.8 diff -u -p -r1.8 itkMedialNodeCorrespondencesTest.cxx --- Testing/Code/Common/itkMedialNodeCorrespondencesTest.cxx 5 Apr 2009 23:09:35 -0000 1.8 +++ Testing/Code/Common/itkMedialNodeCorrespondencesTest.cxx 5 May 2009 21:56:25 -0000 @@ -180,9 +180,13 @@ int itkMedialNodeCorrespondencesTest(int // Set filter parameters binfilter->SetInput(sourceImage); if(i == 0) + { binfilter->SetRepetitions(4); + } else + { binfilter->SetRepetitions(3); + } // Set up the output of the filter ImageType::Pointer blurredImage = binfilter->GetOutput(); @@ -216,10 +220,15 @@ int itkMedialNodeCorrespondencesTest(int caFilter->SetInput(bloxBoundaryPointImage); caFilter->SetDistanceMin(8.0); caFilter->SetDistanceMax(12.0); + if(i == 0) + { caFilter->SetEpsilon(0.05); + } else + { caFilter->SetEpsilon(0.05); + } caFilter->SetPolarity(0); @@ -244,9 +253,13 @@ int itkMedialNodeCorrespondencesTest(int bloxCoreAtomImage->DoCoreAtomVoting(); if(i == 0) - {bloxCoreAtomImage1 = bloxCoreAtomImage;} + { + bloxCoreAtomImage1 = bloxCoreAtomImage; + } else - {bloxCoreAtomImage2 = bloxCoreAtomImage;} + { + bloxCoreAtomImage2 = bloxCoreAtomImage; + } } int numberNodes1 = bloxCoreAtomImage1->GetMedialNodeCount(); PortableRound-May-11-2009.patch [^] (40,668 bytes) 2009-05-11 18:41 [Show Content] [Hide Content] Index: Code/Common/itkMacro.h =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkMacro.h,v retrieving revision 1.91 diff -u -p -r1.91 itkMacro.h --- Code/Common/itkMacro.h 11 May 2009 21:48:29 -0000 1.91 +++ Code/Common/itkMacro.h 11 May 2009 22:39:21 -0000 @@ -974,194 +974,14 @@ private: namespace itk { - namespace Math { - -#ifdef ITK_USE_PORTABLE_ROUND -// RoundHalfIntegerUp -- round towards nearest integer -// halfway cases are rounded upward, e.g. -// RoundHalfIntegerUp( 1.5) == 2 -// RoundHalfIntegerUp(-1.5) == -1 -// RoundHalfIntegerUp( 2.5) == 3 -// -// Be careful: argument absolute value must be less than INT_MAX/2 -// for RoundHalfIntegerUp to be guaranteed to work. -// We also assume that the rounding mode is not changed from the default -// one (or at least that it is always restored to the default one). - -#if VNL_CONFIG_ENABLE_SSE2_ROUNDING || GCC_USE_FAST_IMPL || VC_USE_FAST_IMPL - -inline int RoundHalfIntegerUp(float x) { return RoundHalfIntegerToEven(2*x+0.5f)>>1; } -inline int RoundHalfIntegerUp(double x) { return RoundHalfIntegerToEven(2*x+0.5)>>1; } - -#else // Vanilla implementation - -inline int RoundHalfIntegerUp(float x) -{ - x += 0.5f; - return static_cast<int>(x>=0.f?x:(x==static_cast<int>(x)?x:x-1.f)); -} -inline int RoundHalfIntegerUp(double x) -{ - x += 0.5; - return static_cast<int>(x>=0.?x:(x==static_cast<int>(x)?x:x-1.)); -} - -#endif - - -// Round -- round towards nearest integer -// halfway cases such as 0.5 may be rounded either up or down -// so as to maximize the efficiency, e.g. -// RoundHalfIntegerToEven( 1.5) == 1 or 2 -// RoundHalfIntegerToEven(-1.5) == -2 or -1 -// RoundHalfIntegerToEven( 2.5) == 2 or 3 -// RoundHalfIntegerToEven( 3.5) == 3 or 4 -// -// We assume that the rounding mode is not changed from the default -// one (or at least that it is always restored to the default one). - -#if VNL_CONFIG_ENABLE_SSE2_ROUNDING || GCC_USE_FAST_IMPL || VC_USE_FAST_IMPL - -inline int Round(float x) { return RoundHalfIntegerToEven(x); } +inline int RoundHalfIntegerUp(float x) { return vnl_math_rnd_halfintup(x); } +inline int RoundHalfIntegerUp(double x) { return vnl_math_rnd_halfintup(x); } +inline int RoundHalfIntegerToEven(float x) { return vnl_math_rnd_halfinttoeven(x); } +inline int RoundHalfIntegerToEven(double x) { return vnl_math_rnd_halfinttoeven(x); } +inline int Round(float x) { return RoundHalfIntegerToEven(x); } inline int Round(double x) { return RoundHalfIntegerToEven(x); } - -#else // Vanilla implementation - -inline int Round(float x) { return x>=0.f?static_cast<int>(x+.5f):static_cast<int>(x-.5f); } -inline int Round(double x) { return x>=0.0?static_cast<int>(x+0.5):static_cast<int>(x-0.5); } - - -#endif - - -// RoundHalfIntegerToEven -- round towards nearest integer -// halfway cases are rounded towards the nearest even integer, e.g. -// RoundHalfIntegerToEven( 1.5) == 2 -// RoundHalfIntegerToEven(-1.5) == -2 -// RoundHalfIntegerToEven( 2.5) == 2 -// RoundHalfIntegerToEven( 3.5) == 4 -// -// We assume that the rounding mode is not changed from the default -// one (or at least that it is always restored to the default one). - -#if VNL_CONFIG_ENABLE_SSE2_ROUNDING // Fast sse2 implementation - -inline int RoundHalfIntegerToEven(float x) -{ -# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) - assert( fegetround() == FE_TONEAREST ); -# endif - return _mm_cvtss_si32(_mm_set_ss(x)); -} -inline int RoundHalfIntegerToEven(double x) -{ -# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) - assert( fegetround() == FE_TONEAREST ); -# endif - return _mm_cvtsd_si32(_mm_set_sd(x)); -} - -#elif GCC_USE_FAST_IMPL // Fast gcc asm implementation - -inline int RoundHalfIntegerToEven(float x) - { -# ifdef VNL_CHECK_FPU_ROUNDING_MODE - assert( fegetround() == FE_TONEAREST ); -# endif - int r; - __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); - return r; - } - -inline int RoundHalfIntegerToEven(double x) - { -# ifdef VNL_CHECK_FPU_ROUNDING_MODE - assert( fegetround() == FE_TONEAREST ); -# endif - int r; - __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); - return r; - } - -#elif VC_USE_FAST_IMPL // Fast msvc asm implementation - -inline int RoundHalfIntegerToEven(float x) - { - int r; - __asm { -@@ -218,10 +228,7 @@ - } - return r; - } - -inline int RoundHalfIntegerToEven(double x) - { - int r; - __asm { -@@ -230,59 +237,156 @@ - } - return r; - } - -#else // Vanilla implementation - -inline int RoundHalfIntegerToEven(float x) -{ - if (x>=0.f) - { - x += 0.5f; - const int r = static_cast<int>(x); - if ( x != static_cast<float>(r) ) - { - return r; - } - return 2*(r/2); - } - else - { - x -= 0.5f; - const int r = static_cast<int>(x); - if ( x != static_cast<float>(r) ) - { - return r; - } - return 2*(r/2); - } -} - -inline int RoundHalfIntegerToEven(double x) -{ - if (x >= 0.0) - { - x += 0.5; - const int r = static_cast<int>(x); - if ( x != static_cast<double>(r) ) - { - return r; - } - return 2*(r/2); - } - else - { - x -= 0.5; - const int r = static_cast<int>(x); - if ( x != static_cast<double>(r) ) - { - return r; - } - return 2*(r/2); - } -} - -#endif - -#else - // Resort to the previous vnl_math_rnd() - inline int Round(float x) { return vnl_math_rnd(x); } - inline int Round(double x) { return vnl_math_rnd(x); } -#endif } // end namespace Math } // end namespace itk Index: Utilities/vxl/core/vnl/CMakeLists.txt =================================================================== RCS file: /cvsroot/Insight/Insight/Utilities/vxl/core/vnl/CMakeLists.txt,v retrieving revision 1.15 diff -u -p -r1.15 CMakeLists.txt --- Utilities/vxl/core/vnl/CMakeLists.txt 21 Nov 2007 20:24:34 -0000 1.15 +++ Utilities/vxl/core/vnl/CMakeLists.txt 11 May 2009 22:39:21 -0000 @@ -8,19 +8,35 @@ OPTION(VNL_CONFIG_LEGACY_METHODS OPTION(VNL_CONFIG_THREAD_SAFE "Whether thread-safe vnl implementations are used." ON) - + #IF( VXL_HAS_EMMINTRIN_H AND VXL_HAS_SSE2_HARDWARE_SUPPORT ) # OPTION(VNL_CONFIG_ENABLE_SSE2 # "Enable Streaming SIMD Extensions 2 optimisations (hardware dependant)." ON) #ELSE ( VXL_HAS_EMMINTRIN_H AND VXL_HAS_SSE2_HARDWARE_SUPPORT ) OPTION(VNL_CONFIG_ENABLE_SSE2 - "Enable Streaming SIMD Extensions 2 optimisations (hardware dependant)." OFF) + "Enable Streaming SIMD Extensions 2 optimisations (hardware dependant). Currently broken. For use by VNL developers only." OFF) #ENDIF( VXL_HAS_EMMINTRIN_H AND VXL_HAS_SSE2_HARDWARE_SUPPORT ) +OPTION(VNL_CONFIG_ENABLE_SSE2_ROUNDING + "Enable Streaming SIMD Extensions 2 implementation of rounding (hardware dependant)." + ${VXL_HAS_SSE2_HARDWARE_SUPPORT} ) +IF( VNL_CONFIG_ENABLE_SSE2_ROUNDING ) + IF( NOT VXL_HAS_SSE2_HARDWARE_SUPPORT ) + IF( VXL_SSE2_HARDWARE_SUPPORT_POSSIBLE ) + MESSAGE( ${VXL_SSE2_HARDWARE_SUPPORT_POSSIBLE_HELP} ) + ENDIF( VXL_SSE2_HARDWARE_SUPPORT_POSSIBLE ) + MESSAGE( SEND_ERROR "Cannot have VNL_CONFIG_ENABLE_SSE2_ROUNDING because" + " there is no SSE2 hardware support" ) + SET(VNL_CONFIG_ENABLE_SSE2_ROUNDING 0) + ENDIF( NOT VXL_HAS_SSE2_HARDWARE_SUPPORT ) +ENDIF( VNL_CONFIG_ENABLE_SSE2_ROUNDING ) + + MARK_AS_ADVANCED( VNL_CONFIG_CHECK_BOUNDS VNL_CONFIG_LEGACY_METHODS VNL_CONFIG_THREAD_SAFE + VNL_CONFIG_ENABLE_SSE2_ROUNDING VNL_CONFIG_ENABLE_SSE2 ) # Need to enforce 1/0 values for configuration. @@ -39,11 +55,16 @@ IF(VNL_CONFIG_THREAD_SAFE) ELSE(VNL_CONFIG_THREAD_SAFE) SET(VNL_CONFIG_THREAD_SAFE 0) ENDIF(VNL_CONFIG_THREAD_SAFE) -IF(VNL_CONFIG_ENABLE_SSE2) +IF(VNL_CONFIG_ENABLE_SSE2) SET(VNL_CONFIG_ENABLE_SSE2 1) ELSE(VNL_CONFIG_ENABLE_SSE2) SET(VNL_CONFIG_ENABLE_SSE2 0) ENDIF(VNL_CONFIG_ENABLE_SSE2) +IF(VNL_CONFIG_ENABLE_SSE2_ROUNDING) + SET(VNL_CONFIG_ENABLE_SSE2_ROUNDING 1) +ELSE(VNL_CONFIG_ENABLE_SSE2_ROUNDING) + SET(VNL_CONFIG_ENABLE_SSE2_ROUNDING 0) +ENDIF(VNL_CONFIG_ENABLE_SSE2_ROUNDING) CONFIGURE_FILE(${vxl_SOURCE_DIR}/core/vnl/vnl_config.h.in ${vxl_BINARY_DIR}/core/vnl/vnl_config.h @ONLY IMMEDIATE) @@ -214,6 +235,9 @@ IF(CMAKE_COMPILER_IS_GNUCXX) IF(VNL_CONFIG_ENABLE_SSE2) ADD_DEFINITIONS( -msse2 ) ENDIF(VNL_CONFIG_ENABLE_SSE2) + IF(VNL_CONFIG_ENABLE_SSE2_ROUNDING) + ADD_DEFINITIONS( -msse2 ) + ENDIF(VNL_CONFIG_ENABLE_SSE2_ROUNDING) ENDIF(CMAKE_COMPILER_IS_GNUCXX) ADD_LIBRARY(itkvnl ${vnl_sources}) Index: Utilities/vxl/core/vnl/vnl_config.h.in =================================================================== RCS file: /cvsroot/Insight/Insight/Utilities/vxl/core/vnl/vnl_config.h.in,v retrieving revision 1.3 diff -u -p -r1.3 vnl_config.h.in --- Utilities/vxl/core/vnl/vnl_config.h.in 13 Nov 2007 14:56:52 -0000 1.3 +++ Utilities/vxl/core/vnl/vnl_config.h.in 11 May 2009 22:39:21 -0000 @@ -19,4 +19,7 @@ //: Set to 0 if you don't have SSE2 support on your target platform #define VNL_CONFIG_ENABLE_SSE2 @VNL_CONFIG_ENABLE_SSE2@ +//: Set to 0 if you don't want to use SSE2 instructions to implement rounding, floor, and ceil functions. +#define VNL_CONFIG_ENABLE_SSE2_ROUNDING @VNL_CONFIG_ENABLE_SSE2_ROUNDING@ + #endif Index: Utilities/vxl/core/vnl/vnl_math.h =================================================================== RCS file: /cvsroot/Insight/Insight/Utilities/vxl/core/vnl/vnl_math.h,v retrieving revision 1.7 diff -u -p -r1.7 vnl_math.h --- Utilities/vxl/core/vnl/vnl_math.h 22 Aug 2007 17:47:43 -0000 1.7 +++ Utilities/vxl/core/vnl/vnl_math.h 11 May 2009 22:39:21 -0000 @@ -5,39 +5,66 @@ #pragma interface #endif //: -// \file -// \brief Namespace with standard math functions +// \file +// \brief Namespace with standard math functions // -// The vnl_math namespace provides a standard set of the simple mathematical -// functions (min, max, sqr, sgn, rnd, abs), and some predefined constants -// such as pi and e, which are not defined by the ANSI C++ standard. +// The vnl_math namespace provides a standard set of the simple mathematical +// functions (min, max, sqr, sgn, rnd, abs), and some predefined constants +// such as pi and e, which are not defined by the ANSI C++ standard. // -// There are complex versions defined in vnl_complex.h +// There are complex versions defined in vnl_complex.h // -// That's right, M_PI is nonstandard! +// That's right, M_PI is nonstandard! // -// Aside from e, pi and their associates the class also defines eps, -// the IEEE double machine precision. This is the smallest number -// eps such that 1+eps != 1. +// Aside from e, pi and their associates the class also defines eps, +// the IEEE double machine precision. This is the smallest number +// eps such that 1+eps != 1. // -// The operations are overloaded for int, float and double arguments, -// which in combination with inlining can make them more efficient than -// their counterparts in the standard C library. +// The operations are overloaded for int, float and double arguments, +// which in combination with inlining can make them more efficient than +// their counterparts in the standard C library. // -// \author Andrew W. Fitzgibbon, Oxford RRG -// \date July 13, 1996 +// \author Andrew W. Fitzgibbon, Oxford RRG +// \date July 13, 1996 // // \verbatim // Modifications -// 210598 AWF Removed conditional VCL_IMPLEMENT_STATIC_CONSTS, sometimes gcc needs them. -// LSB (Modifications) 23/1/01 Documentation tidied -// Peter Vanroose - 7 Sept. 2002 - maxdouble etc. replaced by vnl_numeric_traits<T>::maxval +// 21 May 1998 AWF Removed conditional VCL_IMPLEMENT_STATIC_CONSTS, sometimes gcc needs them. +// LSB (Modifications) 23 Jan 2001 Documentation tidied +// Peter Vanroose - 7 Sep 2002 - maxdouble etc. replaced by vnl_numeric_traits<T>::maxval // Amitha Perera - 13 Sep 2002 - make constant initialization standards compliant. // \endverbatim #include <vcl_cmath.h> #include "dll.h" -#include <vxl_config.h> // for VXL_C_MATH_HAS_LROUND +#include <vxl_config.h> +#include <vnl/vnl_config.h> // for VNL_CONFIG_ENABLE_SSE2_ROUNDING +#ifdef VNL_CHECK_FPU_ROUNDING_MODE +# include <vcl_cassert.h> +#endif + +// Figure out when the fast implementation can be used +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING +# if !VXL_HAS_EMMINTRIN_H +# error "Required file emmintrin.h for SSE2 not found" +# else +# include <emmintrin.h> // sse 2 intrinsics +# endif +#endif +// Turn on fast impl when using GCC on Intel-based machines with the following exception: +// PPC with Mac OS X +#if defined(__GNUC__) && (!defined(__APPLE__) || !defined(__ppc__) ) +# define GCC_USE_FAST_IMPL 1 +#else +# define GCC_USE_FAST_IMPL 0 +#endif +// Turn on fast impl when using msvc on 32 bits windows +#if defined(VCL_VC) && !defined(_WIN64) +# define VC_USE_FAST_IMPL 1 +#else +# define VC_USE_FAST_IMPL 0 +#endif + //: Type-accessible infinities for use in templates. template <class T> T vnl_huge_val(T); @@ -53,19 +80,20 @@ class vnl_math { public: //: pi, e and all that - static VNL_DLL_DATA const double e VCL_STATIC_CONST_INIT_FLOAT_DECL(2.7182818284590452354); - static VNL_DLL_DATA const double log2e VCL_STATIC_CONST_INIT_FLOAT_DECL(1.4426950408889634074); - static VNL_DLL_DATA const double log10e VCL_STATIC_CONST_INIT_FLOAT_DECL(0.43429448190325182765); - static VNL_DLL_DATA const double ln2 VCL_STATIC_CONST_INIT_FLOAT_DECL(0.69314718055994530942); - static VNL_DLL_DATA const double ln10 VCL_STATIC_CONST_INIT_FLOAT_DECL(2.30258509299404568402); - static VNL_DLL_DATA const double pi VCL_STATIC_CONST_INIT_FLOAT_DECL(3.14159265358979323846); - static VNL_DLL_DATA const double pi_over_2 VCL_STATIC_CONST_INIT_FLOAT_DECL(1.57079632679489661923); - static VNL_DLL_DATA const double pi_over_4 VCL_STATIC_CONST_INIT_FLOAT_DECL(0.78539816339744830962); - static VNL_DLL_DATA const double one_over_pi VCL_STATIC_CONST_INIT_FLOAT_DECL(0.31830988618379067154); - static VNL_DLL_DATA const double two_over_pi VCL_STATIC_CONST_INIT_FLOAT_DECL(0.63661977236758134308); - static VNL_DLL_DATA const double two_over_sqrtpi VCL_STATIC_CONST_INIT_FLOAT_DECL(1.12837916709551257390); - static VNL_DLL_DATA const double sqrt2 VCL_STATIC_CONST_INIT_FLOAT_DECL(1.41421356237309504880); - static VNL_DLL_DATA const double sqrt1_2 VCL_STATIC_CONST_INIT_FLOAT_DECL(0.70710678118654752440); + static VNL_DLL_DATA const double e VCL_STATIC_CONST_INIT_FLOAT_DECL(2.7182818284590452354); + static VNL_DLL_DATA const double log2e VCL_STATIC_CONST_INIT_FLOAT_DECL(1.4426950408889634074); + static VNL_DLL_DATA const double log10e VCL_STATIC_CONST_INIT_FLOAT_DECL(0.43429448190325182765); + static VNL_DLL_DATA const double ln2 VCL_STATIC_CONST_INIT_FLOAT_DECL(0.69314718055994530942); + static VNL_DLL_DATA const double ln10 VCL_STATIC_CONST_INIT_FLOAT_DECL(2.30258509299404568402); + static VNL_DLL_DATA const double pi VCL_STATIC_CONST_INIT_FLOAT_DECL(3.14159265358979323846); + static VNL_DLL_DATA const double pi_over_2 VCL_STATIC_CONST_INIT_FLOAT_DECL(1.57079632679489661923); + static VNL_DLL_DATA const double pi_over_4 VCL_STATIC_CONST_INIT_FLOAT_DECL(0.78539816339744830962); + static VNL_DLL_DATA const double one_over_pi VCL_STATIC_CONST_INIT_FLOAT_DECL(0.31830988618379067154); + static VNL_DLL_DATA const double two_over_pi VCL_STATIC_CONST_INIT_FLOAT_DECL(0.63661977236758134308); + static VNL_DLL_DATA const double two_over_sqrtpi VCL_STATIC_CONST_INIT_FLOAT_DECL(1.12837916709551257390); + static VNL_DLL_DATA const double one_over_sqrt2pi VCL_STATIC_CONST_INIT_FLOAT_DECL(0.39894228040143267794); + static VNL_DLL_DATA const double sqrt2 VCL_STATIC_CONST_INIT_FLOAT_DECL(1.41421356237309504880); + static VNL_DLL_DATA const double sqrt1_2 VCL_STATIC_CONST_INIT_FLOAT_DECL(0.70710678118654752440); //: IEEE double machine precision static VNL_DLL_DATA const double eps VCL_STATIC_CONST_INIT_FLOAT_DECL(2.2204460492503131e-16); @@ -140,50 +168,353 @@ bool vnl_math_isfinite(long double); template <class T> bool vnl_math_isfinite(T); #endif -// rnd (rounding; 0.5 rounds up) -#if VXL_C_MATH_HAS_LROUND -// Use C99 functions, which GCC implements as an intrinsic -// Or in simpler terms - is at least 3 times faster. -inline int vnl_math_rnd(float x) { return static_cast<int>(lroundf(x)); } -inline int vnl_math_rnd(double x) { return static_cast<int>(lround(x)); } -#elif defined (VCL_VC) && !defined(__GCCXML__) && !defined(_WIN64) -// Use assembly inline function from -// http://mega-nerd.com/FPcast/ -// - - // Win32 doesn't seem to have these functions. - // Therefore implement inline versions of these functions here. -// NB But Win64 does not support the non-standard _asm - __inline int - vnl_math_rnd (double flt) - { int intgr; - _asm - { fld flt - fistp intgr - } ; - return intgr ; - } - - __inline int - vnl_math_rnd (float flt) - { int intgr; - _asm - { fld flt - fistp intgr - } ; - return intgr; - } -#else -inline int vnl_math_rnd(float x) { return (x>=0.0)?(int)(x + 0.5):(int)(x - 0.5); } -inline int vnl_math_rnd(double x) { return (x>=0.0)?(int)(x + 0.5):(int)(x - 0.5); } + + +// vnl_math_rnd_halfinttoeven -- round towards nearest integer +// halfway cases are rounded towards the nearest even integer, e.g. +// vnl_math_rnd_halfinttoeven( 1.5) == 2 +// vnl_math_rnd_halfinttoeven(-1.5) == -2 +// vnl_math_rnd_halfinttoeven( 2.5) == 2 +// vnl_math_rnd_halfinttoeven( 3.5) == 4 +// +// We assume that the rounding mode is not changed from the default +// one (or at least that it is always restored to the default one). + +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING // Fast sse2 implementation + +inline int vnl_math_rnd_halfinttoeven(float x) +{ +# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) + assert(fegetround()==FE_TONEAREST); +# endif + return _mm_cvtss_si32(_mm_set_ss(x)); +} +inline int vnl_math_rnd_halfinttoeven(double x) +{ +# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) + assert(fegetround()==FE_TONEAREST); +# endif + return _mm_cvtsd_si32(_mm_set_sd(x)); +} + +#elif GCC_USE_FAST_IMPL // Fast gcc asm implementation + +inline int vnl_math_rnd_halfinttoeven(float x) +{ +# ifdef VNL_CHECK_FPU_ROUNDING_MODE + assert(fegetround()==FE_TONEAREST); +# endif + int r; + __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); + return r; +} +inline int vnl_math_rnd_halfinttoeven(double x) +{ +# ifdef VNL_CHECK_FPU_ROUNDING_MODE + assert(fegetround()==FE_TONEAREST); +# endif + int r; + __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); + return r; +} + +#elif VC_USE_FAST_IMPL // Fast msvc asm implementation + +inline int vnl_math_rnd_halfinttoeven(float x) +{ + int r; + __asm { + fld x + fistp r + } + return r; +} +inline int vnl_math_rnd_halfinttoeven(double x) +{ + int r; + __asm { + fld x + fistp r + } + return r; +} + +#else // Vanilla implementation + +inline int vnl_math_rnd_halfinttoeven(float x) +{ + if (x>=0.f) + { + x+=0.5f; + const int r = static_cast<int>(x); + if ( x != static_cast<float>(r) ) return r; + return 2*(r/2); + } + else + { + x-=0.5f; + const int r = static_cast<int>(x); + if ( x != static_cast<float>(r) ) return r; + return 2*(r/2); + } +} +inline int vnl_math_rnd_halfinttoeven(double x) +{ + if (x>=0.) + { + x+=0.5; + const int r = static_cast<int>(x); + if ( x != static_cast<double>(r) ) return r; + return 2*(r/2); + } + else + { + x-=0.5; + const int r = static_cast<int>(x); + if ( x != static_cast<double>(r) ) return r; + return 2*(r/2); + } +} + +#endif + + + +// vnl_math_rnd_halfintup -- round towards nearest integer +// halfway cases are rounded upward, e.g. +// vnl_math_rnd_halfintup( 1.5) == 2 +// vnl_math_rnd_halfintup(-1.5) == -1 +// vnl_math_rnd_halfintup( 2.5) == 3 +// +// Be careful: argument absolute value must be less than INT_MAX/2 +// for vnl_math_rnd_halfintup to be guaranteed to work. +// We also assume that the rounding mode is not changed from the default +// one (or at least that it is always restored to the default one). + +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING || GCC_USE_FAST_IMPL || VC_USE_FAST_IMPL + +inline int vnl_math_rnd_halfintup(float x) { return vnl_math_rnd_halfinttoeven(2*x+0.5f)>>1; } +inline int vnl_math_rnd_halfintup(double x) { return vnl_math_rnd_halfinttoeven(2*x+0.5)>>1; } + +#else // Vanilla implementation + +inline int vnl_math_rnd_halfintup(float x) +{ + x+=0.5f; + return static_cast<int>(x>=0.f?x:(x==static_cast<int>(x)?x:x-1.f)); +} +inline int vnl_math_rnd_halfintup(double x) +{ + x+=0.5; + return static_cast<int>(x>=0.?x:(x==static_cast<int>(x)?x:x-1.)); +} + +#endif + + + +// vnl_math_rnd -- round towards nearest integer +// halfway cases such as 0.5 may be rounded either up or down +// so as to maximize the efficiency, e.g. +// vnl_math_rnd_halfinttoeven( 1.5) == 1 or 2 +// vnl_math_rnd_halfinttoeven(-1.5) == -2 or -1 +// vnl_math_rnd_halfinttoeven( 2.5) == 2 or 3 +// vnl_math_rnd_halfinttoeven( 3.5) == 3 or 4 +// +// We assume that the rounding mode is not changed from the default +// one (or at least that it is always restored to the default one). + +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING || GCC_USE_FAST_IMPL || VC_USE_FAST_IMPL + +inline int vnl_math_rnd(float x) { return vnl_math_rnd_halfinttoeven(x); } +inline int vnl_math_rnd(double x) { return vnl_math_rnd_halfinttoeven(x); } + +#else // Vanilla implementation + +inline int vnl_math_rnd(float x) { return x>=0.f?static_cast<int>(x+.5f):static_cast<int>(x-.5f); } +inline int vnl_math_rnd(double x) { return x>=0.0?static_cast<int>(x+0.5):static_cast<int>(x-0.5); } + + +#endif + + + +// vnl_math_floor -- round towards minus infinity +// +// Be careful: argument absolute value must be less than INT_MAX/2 +// for vnl_math_floor to be guaranteed to work. +// We also assume that the rounding mode is not changed from the default +// one (or at least that it is always restored to the default one). + +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING // Fast sse2 implementation + +inline int vnl_math_floor(float x) +{ +# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) + assert(fegetround()==FE_TONEAREST); +# endif + return _mm_cvtss_si32(_mm_set_ss(2*x-.5f))>>1; +} +inline int vnl_math_floor(double x) +{ +# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) + assert(fegetround()==FE_TONEAREST); +# endif + return _mm_cvtsd_si32(_mm_set_sd(2*x-.5))>>1; +} + +#elif GCC_USE_FAST_IMPL // Fast gcc asm implementation + +inline int vnl_math_floor(float x) +{ +# ifdef VNL_CHECK_FPU_ROUNDING_MODE + assert(fegetround()==FE_TONEAREST); +# endif + int r; + x = 2*x-.5f; + __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); + return r>>1; +} +inline int vnl_math_floor(double x) +{ +# ifdef VNL_CHECK_FPU_ROUNDING_MODE + assert(fegetround()==FE_TONEAREST); +# endif + int r; + x = 2*x-.5; + __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); + return r>>1; +} + +#elif VC_USE_FAST_IMPL // Fast msvc asm implementation + +inline int vnl_math_floor(float x) +{ + int r; + x = 2*x-.5f; + __asm { + fld x + fistp r + } + return r>>1; +} +inline int vnl_math_floor(double x) +{ + int r; + x = 2*x-.5; + __asm { + fld x + fistp r + } + return r>>1; +} + +#else // Vanilla implementation + +inline int vnl_math_floor(float x) +{ + return static_cast<int>(x>=0.f?x:(x==static_cast<int>(x)?x:x-1.f)); +} +inline int vnl_math_floor(double x) +{ + return static_cast<int>(x>=0.0?x:(x==static_cast<int>(x)?x:x-1.0)); +} + #endif + + +// vnl_math_ceil -- round towards plus infinity +// +// Be careful: argument absolute value must be less than INT_MAX/2 +// for vnl_math_ceil to be guaranteed to work. +// We also assume that the rounding mode is not changed from the default +// one (or at least that it is always restored to the default one). + +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING // Fast sse2 implementation + +inline int vnl_math_ceil(float x) +{ +# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) + assert(fegetround()==FE_TONEAREST); +# endif + return -(_mm_cvtss_si32(_mm_set_ss(-.5f-2*x))>>1); +} +inline int vnl_math_ceil(double x) +{ +# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) + assert(fegetround()==FE_TONEAREST); +# endif + return -(_mm_cvtsd_si32(_mm_set_sd(-.5-2*x))>>1); +} + +#elif GCC_USE_FAST_IMPL // Fast gcc asm implementation + +inline int vnl_math_ceil(float x) +{ +# ifdef VNL_CHECK_FPU_ROUNDING_MODE + assert(fegetround()==FE_TONEAREST); +# endif + int r; + x = -.5f-2*x; + __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); + return -(r>>1); +} +inline int vnl_math_ceil(double x) +{ +# ifdef VNL_CHECK_FPU_ROUNDING_MODE + assert(fegetround()==FE_TONEAREST); +# endif + int r; + x = -.5-2*x; + __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); + return -(r>>1); +} + +#elif VC_USE_FAST_IMPL // Fast msvc asm implementation + +inline int vnl_math_ceil(float x) +{ + int r; + x = -.5f-2*x; + __asm { + fld x + fistp r + } + return -(r>>1); +} +inline int vnl_math_ceil(double x) +{ + int r; + x = -.5-2*x; + __asm { + fld x + fistp r + } + return -(r>>1); +} + +#else // Vanilla implementation + +inline int vnl_math_ceil(float x) +{ + return static_cast<int>(x<0.f?x:(x==static_cast<int>(x)?x:x+1.f)); +} +inline int vnl_math_ceil(double x) +{ + return static_cast<int>(x<0.0?x:(x==static_cast<int>(x)?x:x+1.0)); +} + +#endif + + + // abs inline bool vnl_math_abs(bool x) { return x; } inline unsigned char vnl_math_abs(unsigned char x) { return x; } -inline unsigned char vnl_math_abs(signed char x) { return x < 0 ? -x : x; } -inline unsigned char vnl_math_abs(char x) { return (unsigned char)x; } -inline unsigned short vnl_math_abs(short x) { return x < 0 ? -x : x; } +inline unsigned char vnl_math_abs(signed char x) { return x < 0 ? static_cast<unsigned char>(-x) : x; } +inline unsigned char vnl_math_abs(char x) { return static_cast<unsigned char>(x); } +inline unsigned short vnl_math_abs(short x) { return x < 0 ? static_cast<unsigned short>(-x) : x; } inline unsigned short vnl_math_abs(unsigned short x){ return x; } inline unsigned int vnl_math_abs(int x) { return x < 0 ? -x : x; } inline unsigned int vnl_math_abs(unsigned int x) { return x; } Index: Utilities/vxl/core/vnl/tests/test_math.cxx =================================================================== RCS file: /cvsroot/Insight/Insight/Utilities/vxl/core/vnl/tests/test_math.cxx,v retrieving revision 1.10 diff -u -p -r1.10 test_math.cxx --- Utilities/vxl/core/vnl/tests/test_math.cxx 20 Apr 2009 20:01:37 -0000 1.10 +++ Utilities/vxl/core/vnl/tests/test_math.cxx 11 May 2009 22:39:21 -0000 @@ -68,22 +68,135 @@ void test_math() testlib_test_assert_near("exp(d*i) ~= -1", vnl_math_abs(e_ipi+1.0), 0); vcl_cout << vcl_endl; - testlib_test_assert("rnd(-8.4999) == -8", vnl_math_rnd(-8.4999) == -8); - testlib_test_assert("rnd(-8.4999f) == -8", vnl_math_rnd(-8.4999f) == -8); - vcl_cout << "vnl_math_rnd(-8.50) == " << vnl_math_rnd(-8.50) << vcl_endl; - testlib_test_assert("rnd(-8.50) == -8/9", vnl_math_rnd(-8.50)/2 == -4); - testlib_test_assert("rnd(-8.50f) == -8/9", vnl_math_rnd(-8.50f)/2 == -4); - vcl_cout << "vnl_math_rnd(-8.5001) == " << vnl_math_rnd(-8.5001) << vcl_endl; - testlib_test_assert("rnd(-8.5001) == -9", vnl_math_rnd(-8.5001) == -9); - testlib_test_assert("rnd(-8.5001f) == -9", vnl_math_rnd(-8.5001f) == -9); - testlib_test_assert("rnd(8.4999) == 8", vnl_math_rnd(8.4999) == 8); - testlib_test_assert("rnd(8.4999f) == 8", vnl_math_rnd(8.4999f) == 8); - testlib_test_assert("rnd(8.50) == 8/9", vnl_math_rnd(8.50)/2 == 4); - vcl_cout << "vnl_math_rnd(8.50) == " << vnl_math_rnd(8.50) << vcl_endl; - testlib_test_assert("rnd(8.50f) == 8/9", vnl_math_rnd(8.50f)/2 == 4); - vcl_cout << "vnl_math_rnd(8.5001) == " << vnl_math_rnd(8.5001) << vcl_endl; - testlib_test_assert("rnd(8.5001) == 9", vnl_math_rnd(8.5001) == 9); - testlib_test_assert("rnd(8.5001f) == 9", vnl_math_rnd(8.5001f) == 9); + testlib_test_assert("rnd(-8.4999) == -8 ", vnl_math_rnd(-8.4999) == -8); + testlib_test_assert("rnd(-8.4999f) == -8 ", vnl_math_rnd(-8.4999f) == -8); + testlib_test_assert("rnd(-8.50) == -8/9", vnl_math_rnd(-8.50)/2 == -4); + testlib_test_assert("rnd(-8.50f) == -8/9", vnl_math_rnd(-8.50f)/2 == -4); + testlib_test_assert("rnd(-8.5001) == -9 ", vnl_math_rnd(-8.5001) == -9); + testlib_test_assert("rnd(-8.5001f) == -9 ", vnl_math_rnd(-8.5001f) == -9); + testlib_test_assert("rnd(8.4999) == 8 ", vnl_math_rnd(8.4999) == 8); + testlib_test_assert("rnd(8.4999f) == 8 ", vnl_math_rnd(8.4999f) == 8); + testlib_test_assert("rnd(8.50) == 8/9", vnl_math_rnd(8.50)/2 == 4); + testlib_test_assert("rnd(8.50f) == 8/9", vnl_math_rnd(8.50f)/2 == 4); + testlib_test_assert("rnd(8.5001) == 9 ", vnl_math_rnd(8.5001) == 9); + testlib_test_assert("rnd(8.5001f) == 9 ", vnl_math_rnd(8.5001f) == 9); + + testlib_test_assert("rnd(-9.4999) == -9 ", vnl_math_rnd(-9.4999) == -9); + testlib_test_assert("rnd(-9.4999f) == -9 ", vnl_math_rnd(-9.4999f) == -9); + testlib_test_assert("rnd(-9.50) == -9/10", (vnl_math_rnd(-9.50)+1)/2 == -4); + testlib_test_assert("rnd(-9.50f) == -9/10", (vnl_math_rnd(-9.50f)+1)/2 == -4); + testlib_test_assert("rnd(-9.5001) == -10 ", vnl_math_rnd(-9.5001) == -10); + testlib_test_assert("rnd(-9.5001f) == -10 ", vnl_math_rnd(-9.5001f) == -10); + testlib_test_assert("rnd(9.4999) == 9 ", vnl_math_rnd(9.4999) == 9); + testlib_test_assert("rnd(9.4999f) == 9 ", vnl_math_rnd(9.4999f) == 9); + testlib_test_assert("rnd(9.50) == 9/10", (vnl_math_rnd(9.50)-1)/2 == 4); + testlib_test_assert("rnd(9.50f) == 9/10", (vnl_math_rnd(9.50f)-1)/2 == 4); + testlib_test_assert("rnd(9.5001) == 10 ", vnl_math_rnd(9.5001) == 10); + testlib_test_assert("rnd(9.5001f) == 10 ", vnl_math_rnd(9.5001f) == 10); + + testlib_test_assert("rnd_halfinttoeven(-8.4999) == -8", vnl_math_rnd_halfinttoeven(-8.4999) == -8); + testlib_test_assert("rnd_halfinttoeven(-8.4999f) == -8", vnl_math_rnd_halfinttoeven(-8.4999f)== -8); + testlib_test_assert("rnd_halfinttoeven(-8.50) == -8", vnl_math_rnd_halfinttoeven(-8.50) == -8); + testlib_test_assert("rnd_halfinttoeven(-8.50f) == -8", vnl_math_rnd_halfinttoeven(-8.50f) == -8); + testlib_test_assert("rnd_halfinttoeven(-8.5001) == -9", vnl_math_rnd_halfinttoeven(-8.5001) == -9); + testlib_test_assert("rnd_halfinttoeven(-8.5001f) == -9", vnl_math_rnd_halfinttoeven(-8.5001f)== -9); + testlib_test_assert("rnd_halfinttoeven(8.4999) == 8", vnl_math_rnd_halfinttoeven(8.4999) == 8); + testlib_test_assert("rnd_halfinttoeven(8.4999f) == 8", vnl_math_rnd_halfinttoeven(8.4999f)== 8); + testlib_test_assert("rnd_halfinttoeven(8.50) == 9", vnl_math_rnd_halfinttoeven(8.50) == 8); + testlib_test_assert("rnd_halfinttoeven(8.50f) == 9", vnl_math_rnd_halfinttoeven(8.50f) == 8); + testlib_test_assert("rnd_halfinttoeven(8.5001) == 9", vnl_math_rnd_halfinttoeven(8.5001) == 9); + testlib_test_assert("rnd_halfinttoeven(8.5001f) == 9", vnl_math_rnd_halfinttoeven(8.5001f)== 9); + + testlib_test_assert("rnd_halfinttoeven(-9.4999) == -9 ", vnl_math_rnd_halfinttoeven(-9.4999) == -9); + testlib_test_assert("rnd_halfinttoeven(-9.4999f) == -9 ", vnl_math_rnd_halfinttoeven(-9.4999f)== -9); + testlib_test_assert("rnd_halfinttoeven(-9.50) == -9 ", vnl_math_rnd_halfinttoeven(-9.50) == -10); + testlib_test_assert("rnd_halfinttoeven(-9.50f) == -9 ", vnl_math_rnd_halfinttoeven(-9.50f) == -10); + testlib_test_assert("rnd_halfinttoeven(-9.5001) == -10", vnl_math_rnd_halfinttoeven(-9.5001) == -10); + testlib_test_assert("rnd_halfinttoeven(-9.5001f) == -10", vnl_math_rnd_halfinttoeven(-9.5001f)== -10); + testlib_test_assert("rnd_halfinttoeven(9.4999) == 9 ", vnl_math_rnd_halfinttoeven(9.4999) == 9); + testlib_test_assert("rnd_halfinttoeven(9.4999f) == 9 ", vnl_math_rnd_halfinttoeven(9.4999f)== 9); + testlib_test_assert("rnd_halfinttoeven(9.50) == 10", vnl_math_rnd_halfinttoeven(9.50) == 10); + testlib_test_assert("rnd_halfinttoeven(9.50f) == 10", vnl_math_rnd_halfinttoeven(9.50f) == 10); + testlib_test_assert("rnd_halfinttoeven(9.5001) == 10", vnl_math_rnd_halfinttoeven(9.5001) == 10); + testlib_test_assert("rnd_halfinttoeven(9.5001f) == 10", vnl_math_rnd_halfinttoeven(9.5001f)== 10); + + testlib_test_assert("rnd_halfintup(-8.4999) == -8", vnl_math_rnd_halfintup(-8.4999) == -8); + testlib_test_assert("rnd_halfintup(-8.4999f) == -8", vnl_math_rnd_halfintup(-8.4999f)== -8); + testlib_test_assert("rnd_halfintup(-8.50) == -8", vnl_math_rnd_halfintup(-8.50) == -8); + testlib_test_assert("rnd_halfintup(-8.50f) == -8", vnl_math_rnd_halfintup(-8.50f) == -8); + testlib_test_assert("rnd_halfintup(-8.5001) == -9", vnl_math_rnd_halfintup(-8.5001) == -9); + testlib_test_assert("rnd_halfintup(-8.5001f) == -9", vnl_math_rnd_halfintup(-8.5001f)== -9); + testlib_test_assert("rnd_halfintup(8.4999) == 8", vnl_math_rnd_halfintup(8.4999) == 8); + testlib_test_assert("rnd_halfintup(8.4999f) == 8", vnl_math_rnd_halfintup(8.4999f)== 8); + testlib_test_assert("rnd_halfintup(8.50) == 9", vnl_math_rnd_halfintup(8.50) == 9); + testlib_test_assert("rnd_halfintup(8.50f) == 9", vnl_math_rnd_halfintup(8.50f) == 9); + testlib_test_assert("rnd_halfintup(8.5001) == 9", vnl_math_rnd_halfintup(8.5001) == 9); + testlib_test_assert("rnd_halfintup(8.5001f) == 9", vnl_math_rnd_halfintup(8.5001f)== 9); + + testlib_test_assert("rnd_halfintup(-9.4999) == -9 ", vnl_math_rnd_halfintup(-9.4999) == -9); + testlib_test_assert("rnd_halfintup(-9.4999f) == -9 ", vnl_math_rnd_halfintup(-9.4999f)== -9); + testlib_test_assert("rnd_halfintup(-9.50) == -9 ", vnl_math_rnd_halfintup(-9.50) == -9); + testlib_test_assert("rnd_halfintup(-9.50f) == -9 ", vnl_math_rnd_halfintup(-9.50f) == -9); + testlib_test_assert("rnd_halfintup(-9.5001) == -10", vnl_math_rnd_halfintup(-9.5001) == -10); + testlib_test_assert("rnd_halfintup(-9.5001f) == -10", vnl_math_rnd_halfintup(-9.5001f)== -10); + testlib_test_assert("rnd_halfintup(9.4999) == 9 ", vnl_math_rnd_halfintup(9.4999) == 9); + testlib_test_assert("rnd_halfintup(9.4999f) == 9 ", vnl_math_rnd_halfintup(9.4999f)== 9); + testlib_test_assert("rnd_halfintup(9.50) == 10", vnl_math_rnd_halfintup(9.50) == 10); + testlib_test_assert("rnd_halfintup(9.50f) == 10", vnl_math_rnd_halfintup(9.50f) == 10); + testlib_test_assert("rnd_halfintup(9.5001) == 10", vnl_math_rnd_halfintup(9.5001) == 10); + testlib_test_assert("rnd_halfintup(9.5001f) == 10", vnl_math_rnd_halfintup(9.5001f)== 10); + + testlib_test_assert("floor(8.0) == 8", vnl_math_floor(8.0) == 8); + testlib_test_assert("floor(8.0f) == 8", vnl_math_floor(8.0f) == 8); + testlib_test_assert("floor(8.9999) == 8", vnl_math_floor(8.9999) == 8); + testlib_test_assert("floor(8.9999f) == 8", vnl_math_floor(8.9999f) == 8); + testlib_test_assert("floor(8.0001) == 8", vnl_math_floor(8.0001) == 8); + testlib_test_assert("floor(8.0001f) == 8", vnl_math_floor(8.0001f) == 8); + testlib_test_assert("floor(-8.0) == -8", vnl_math_floor(-8.0) == -8); + testlib_test_assert("floor(-8.0f) == -8", vnl_math_floor(-8.0f) == -8); + testlib_test_assert("floor(-8.9999) == -9", vnl_math_floor(-8.9999) == -9); + testlib_test_assert("floor(-8.9999f) == -9", vnl_math_floor(-8.9999f) == -9); + testlib_test_assert("floor(-8.0001) == -9", vnl_math_floor(-8.0001) == -9); + testlib_test_assert("floor(-8.0001f) == -9", vnl_math_floor(-8.0001f) == -9); + + testlib_test_assert("floor(9.0) == 9", vnl_math_floor(9.0) == 9); + testlib_test_assert("floor(9.0f) == 9", vnl_math_floor(9.0f) == 9); + testlib_test_assert("floor(9.9999) == 9", vnl_math_floor(9.9999) == 9); + testlib_test_assert("floor(9.9999f) == 9", vnl_math_floor(9.9999f) == 9); + testlib_test_assert("floor(9.0001) == 9", vnl_math_floor(9.0001) == 9); + testlib_test_assert("floor(9.0001f) == 9", vnl_math_floor(9.0001f) == 9); + testlib_test_assert("floor(-9.0) == -9", vnl_math_floor(-9.0) == -9); + testlib_test_assert("floor(-9.0f) == -9", vnl_math_floor(-9.0f) == -9); + testlib_test_assert("floor(-9.9999) == -10", vnl_math_floor(-9.9999) == -10); + testlib_test_assert("floor(-9.9999f) == -10", vnl_math_floor(-9.9999f) == -10); + testlib_test_assert("floor(-9.0001) == -10", vnl_math_floor(-9.0001) == -10); + testlib_test_assert("floor(-9.0001f) == -10", vnl_math_floor(-9.0001f) == -10); + + testlib_test_assert("ceil(8.0) == 8", vnl_math_ceil(8.0) == 8); + testlib_test_assert("ceil(8.0f) == 8", vnl_math_ceil(8.0f) == 8); + testlib_test_assert("ceil(8.9999) == 9", vnl_math_ceil(8.9999) == 9); + testlib_test_assert("ceil(8.9999f) == 9", vnl_math_ceil(8.9999f) == 9); + testlib_test_assert("ceil(8.0001) == 9", vnl_math_ceil(8.0001) == 9); + testlib_test_assert("ceil(8.0001f) == 9", vnl_math_ceil(8.0001f) == 9); + testlib_test_assert("ceil(-8.0) == -8", vnl_math_ceil(-8.0) == -8); + testlib_test_assert("ceil(-8.0f) == -8", vnl_math_ceil(-8.0f) == -8); + testlib_test_assert("ceil(-8.9999) == -8", vnl_math_ceil(-8.9999) == -8); + testlib_test_assert("ceil(-8.9999f) == -8", vnl_math_ceil(-8.9999f) == -8); + testlib_test_assert("ceil(-8.0001) == -8", vnl_math_ceil(-8.0001) == -8); + testlib_test_assert("ceil(-8.0001f) == -8", vnl_math_ceil(-8.0001f) == -8); + + testlib_test_assert("ceil(9.0) == 9", vnl_math_ceil(9.0) == 9); + testlib_test_assert("ceil(9.0f) == 9", vnl_math_ceil(9.0f) == 9); + testlib_test_assert("ceil(9.9999) == 10", vnl_math_ceil(9.9999) == 10); + testlib_test_assert("ceil(9.9999f) == 10", vnl_math_ceil(9.9999f) == 10); + testlib_test_assert("ceil(9.0001) == 10", vnl_math_ceil(9.0001) == 10); + testlib_test_assert("ceil(9.0001f) == 10", vnl_math_ceil(9.0001f) == 10); + testlib_test_assert("ceil(-9.0) == -9", vnl_math_ceil(-9.0) == -9); + testlib_test_assert("ceil(-9.0f) == -9", vnl_math_ceil(-9.0f) == -9); + testlib_test_assert("ceil(-9.9999) == -9", vnl_math_ceil(-9.9999) == -9); + testlib_test_assert("ceil(-9.9999f) == -9", vnl_math_ceil(-9.9999f) == -9); + testlib_test_assert("ceil(-9.0001) == -9", vnl_math_ceil(-9.0001) == -9); + testlib_test_assert("ceil(-9.0001f) == -9", vnl_math_ceil(-9.0001f) == -9); testlib_test_assert(" isfinite(f) ", vnl_math_isfinite(f)); testlib_test_assert(" isfinite(d) ", vnl_math_isfinite(d)); @@ -133,7 +246,7 @@ void test_math() for (int i=1; i*sizeof(unsigned char)<sizeof(p); ++i) \ vcl_cout<<vcl_setfill('0')<<vcl_setw(sizeof(unsigned char))<<(reinterpret_cast<unsigned char*>(&p))[i]; \ vcl_cout<<vcl_dec -#if 0 + vcl_cout << "pinf_f = " << pinf_f << " = " << print_hex(pinf_f) << vcl_endl << "ninf_f = " << ninf_f << " = " << print_hex(ninf_f) << vcl_endl << "pinf_d = " << pinf_d << " = " << print_hex(pinf_d) << vcl_endl @@ -144,8 +257,6 @@ void test_math() << "qnan_d = " << qnan_d << " = " << print_hex(qnan_d) << vcl_endl << "qnan_q = " << qnan_q << " = " << print_hex(qnan_q) << vcl_endl << vcl_endl; -#endif - #undef print_hex #ifndef __alpha__ // on alpha, infinity() == max() @@ -182,8 +293,8 @@ void test_math() testlib_test_assert("!isnan(pinf_q) ", !vnl_math_isnan(pinf_q)); testlib_test_assert("!isnan(ninf_q) ", !vnl_math_isnan(ninf_q)); testlib_test_assert("!isfinite(qnan_q)", !vnl_math_isfinite(qnan_q)); -#if 0 // even more nonstandard ... testlib_test_assert("!isinf(qnan_q) ", !vnl_math_isinf(qnan_q)); +#if 0 // even more nonstandard ... testlib_test_assert(" isnan(qnan_q) ", vnl_math_isnan(qnan_q)); #endif // 0 #endif // __ICC itk-portable-round-2009-05-12.patch [^] (44,535 bytes) 2009-05-12 08:46 [Show Content] [Hide Content] ? Code/Algorithms/itkMultiResolutionPDEDeformableRegistration.txx-old ? Code/Algorithms/itkMultiResolutionPyramidImageFilter.txx-old ? Code/Algorithms/itkNCCRegistrationFunction.h-old ? Code/Algorithms/itkNCCRegistrationFunction.txx-old ? Code/Algorithms/itkRecursiveMultiResolutionPyramidImageFilter.txx-old ? Testing/Code/Algorithms/itkMultiResolutionPyramidImageFilterTest.cxx-old ? Testing/Code/Algorithms/itkRecursiveMultiResolutionPyramidImageFilterTest.cxx-old Index: CMakeLists.txt =================================================================== RCS file: /cvsroot/Insight/Insight/CMakeLists.txt,v retrieving revision 1.336 diff -u -r1.336 CMakeLists.txt --- CMakeLists.txt 7 May 2009 14:03:31 -0000 1.336 +++ CMakeLists.txt 12 May 2009 12:40:33 -0000 @@ -489,6 +489,11 @@ MARK_AS_ADVANCED(ITK_USE_64BITS_APPLE_TRUNCATION_WARNING) ENDIF(APPLE) + + # gcc must have -msse2 option to enable sse2 support + IF(VNL_CONFIG_ENABLE_SSE2 OR VNL_CONFIG_ENABLE_SSE2_ROUNDING) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse2") + ENDIF(VNL_CONFIG_ENABLE_SSE2 OR VNL_CONFIG_ENABLE_SSE2_ROUNDING) ENDIF(CMAKE_COMPILER_IS_GNUCXX) IF(UNIX) Index: Code/Common/itkMacro.h =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkMacro.h,v retrieving revision 1.91 diff -u -r1.91 itkMacro.h --- Code/Common/itkMacro.h 11 May 2009 21:48:29 -0000 1.91 +++ Code/Common/itkMacro.h 12 May 2009 12:40:35 -0000 @@ -974,194 +974,14 @@ namespace itk { - namespace Math { - -#ifdef ITK_USE_PORTABLE_ROUND -// RoundHalfIntegerUp -- round towards nearest integer -// halfway cases are rounded upward, e.g. -// RoundHalfIntegerUp( 1.5) == 2 -// RoundHalfIntegerUp(-1.5) == -1 -// RoundHalfIntegerUp( 2.5) == 3 -// -// Be careful: argument absolute value must be less than INT_MAX/2 -// for RoundHalfIntegerUp to be guaranteed to work. -// We also assume that the rounding mode is not changed from the default -// one (or at least that it is always restored to the default one). - -#if VNL_CONFIG_ENABLE_SSE2_ROUNDING || GCC_USE_FAST_IMPL || VC_USE_FAST_IMPL - -inline int RoundHalfIntegerUp(float x) { return RoundHalfIntegerToEven(2*x+0.5f)>>1; } -inline int RoundHalfIntegerUp(double x) { return RoundHalfIntegerToEven(2*x+0.5)>>1; } - -#else // Vanilla implementation - -inline int RoundHalfIntegerUp(float x) -{ - x += 0.5f; - return static_cast<int>(x>=0.f?x:(x==static_cast<int>(x)?x:x-1.f)); -} -inline int RoundHalfIntegerUp(double x) -{ - x += 0.5; - return static_cast<int>(x>=0.?x:(x==static_cast<int>(x)?x:x-1.)); -} - -#endif - - -// Round -- round towards nearest integer -// halfway cases such as 0.5 may be rounded either up or down -// so as to maximize the efficiency, e.g. -// RoundHalfIntegerToEven( 1.5) == 1 or 2 -// RoundHalfIntegerToEven(-1.5) == -2 or -1 -// RoundHalfIntegerToEven( 2.5) == 2 or 3 -// RoundHalfIntegerToEven( 3.5) == 3 or 4 -// -// We assume that the rounding mode is not changed from the default -// one (or at least that it is always restored to the default one). - -#if VNL_CONFIG_ENABLE_SSE2_ROUNDING || GCC_USE_FAST_IMPL || VC_USE_FAST_IMPL - -inline int Round(float x) { return RoundHalfIntegerToEven(x); } +inline int RoundHalfIntegerUp(float x) { return vnl_math_rnd_halfintup(x); } +inline int RoundHalfIntegerUp(double x) { return vnl_math_rnd_halfintup(x); } +inline int RoundHalfIntegerToEven(float x) { return vnl_math_rnd_halfinttoeven(x); } +inline int RoundHalfIntegerToEven(double x) { return vnl_math_rnd_halfinttoeven(x); } +inline int Round(float x) { return RoundHalfIntegerToEven(x); } inline int Round(double x) { return RoundHalfIntegerToEven(x); } - -#else // Vanilla implementation - -inline int Round(float x) { return x>=0.f?static_cast<int>(x+.5f):static_cast<int>(x-.5f); } -inline int Round(double x) { return x>=0.0?static_cast<int>(x+0.5):static_cast<int>(x-0.5); } - - -#endif - - -// RoundHalfIntegerToEven -- round towards nearest integer -// halfway cases are rounded towards the nearest even integer, e.g. -// RoundHalfIntegerToEven( 1.5) == 2 -// RoundHalfIntegerToEven(-1.5) == -2 -// RoundHalfIntegerToEven( 2.5) == 2 -// RoundHalfIntegerToEven( 3.5) == 4 -// -// We assume that the rounding mode is not changed from the default -// one (or at least that it is always restored to the default one). - -#if VNL_CONFIG_ENABLE_SSE2_ROUNDING // Fast sse2 implementation - -inline int RoundHalfIntegerToEven(float x) -{ -# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) - assert( fegetround() == FE_TONEAREST ); -# endif - return _mm_cvtss_si32(_mm_set_ss(x)); -} -inline int RoundHalfIntegerToEven(double x) -{ -# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) - assert( fegetround() == FE_TONEAREST ); -# endif - return _mm_cvtsd_si32(_mm_set_sd(x)); -} - -#elif GCC_USE_FAST_IMPL // Fast gcc asm implementation - -inline int RoundHalfIntegerToEven(float x) - { -# ifdef VNL_CHECK_FPU_ROUNDING_MODE - assert( fegetround() == FE_TONEAREST ); -# endif - int r; - __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); - return r; - } - -inline int RoundHalfIntegerToEven(double x) - { -# ifdef VNL_CHECK_FPU_ROUNDING_MODE - assert( fegetround() == FE_TONEAREST ); -# endif - int r; - __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); - return r; - } - -#elif VC_USE_FAST_IMPL // Fast msvc asm implementation - -inline int RoundHalfIntegerToEven(float x) - { - int r; - __asm { -@@ -218,10 +228,7 @@ - } - return r; - } - -inline int RoundHalfIntegerToEven(double x) - { - int r; - __asm { -@@ -230,59 +237,156 @@ - } - return r; - } - -#else // Vanilla implementation - -inline int RoundHalfIntegerToEven(float x) -{ - if (x>=0.f) - { - x += 0.5f; - const int r = static_cast<int>(x); - if ( x != static_cast<float>(r) ) - { - return r; - } - return 2*(r/2); - } - else - { - x -= 0.5f; - const int r = static_cast<int>(x); - if ( x != static_cast<float>(r) ) - { - return r; - } - return 2*(r/2); - } -} - -inline int RoundHalfIntegerToEven(double x) -{ - if (x >= 0.0) - { - x += 0.5; - const int r = static_cast<int>(x); - if ( x != static_cast<double>(r) ) - { - return r; - } - return 2*(r/2); - } - else - { - x -= 0.5; - const int r = static_cast<int>(x); - if ( x != static_cast<double>(r) ) - { - return r; - } - return 2*(r/2); - } -} - -#endif - -#else - // Resort to the previous vnl_math_rnd() - inline int Round(float x) { return vnl_math_rnd(x); } - inline int Round(double x) { return vnl_math_rnd(x); } -#endif } // end namespace Math } // end namespace itk Index: Utilities/vxl/config/cmake/config/CMakeLists.txt =================================================================== RCS file: /cvsroot/Insight/Insight/Utilities/vxl/config/cmake/config/CMakeLists.txt,v retrieving revision 1.14 diff -u -r1.14 CMakeLists.txt --- Utilities/vxl/config/cmake/config/CMakeLists.txt 27 Feb 2009 19:51:12 -0000 1.14 +++ Utilities/vxl/config/cmake/config/CMakeLists.txt 12 May 2009 12:40:41 -0000 @@ -186,6 +186,30 @@ PERFORM_CHECK_HEADER(iso646.h VCL_CXX_HAS_HEADER_ISO646_H) PERFORM_CHECK_HEADER(emmintrin.h VXL_HAS_EMMINTRIN_H) +# check for hardware support for sse2 with the current compiler flags +PERFORM_CMAKE_TEST_RUN(vxl_platform_tests.cxx VXL_HAS_SSE2_HARDWARE_SUPPORT) + +# if no support right now, see if the support exists if some flags +# are added. This can be used to give the user some useful info. +IF(NOT VXL_HAS_SSE2_HARDWARE_SUPPORT) + IF(CMAKE_COMPILER_IS_GNUCXX) + SET(VXL_SSE_TEST_FLAG_BACKUP ${CMAKE_REQUIRED_FLAGS}) + SET(CMAKE_REQUIRED_FLAGS " -msse2 ${VXL_SSE_TEST_FLAG_BACKUP} ") + PERFORM_CMAKE_TEST_RUN(vxl_platform_tests.cxx VXL_SSE2_HARDWARE_SUPPORT_POSSIBLE) + SET( VXL_SSE2_HARDWARE_SUPPORT_POSSIBLE_HELP + "The current compiler flags do not allow the SSE2 instructions to be used. " + "It looks like if you add the flag '-msse2' you will be able to use the " + "SSE2 instructions. If you chose to set VNL_CONFIG_ENABLE_SSE or " + "VNL_CONFIG_ENABLE_SSE2_ROUNDING to ON, cmake will put this flag for you. " + "You can also add this flag yourself. If you still see this message, after " + "the flag change, you may need to set VXL_UPDATE_CONFIGURATION to ON and " + "rerun cmake." + CACHE INTERNAL "help string for how to enable SSE2 support" ) + SET(CMAKE_REQUIRED_FLAGS ${VXL_SSE_TEST_FLAG_BACKUP}) + ENDIF(CMAKE_COMPILER_IS_GNUCXX) +ENDIF(NOT VXL_HAS_SSE2_HARDWARE_SUPPORT) + + # # Check for aligned dynamic memory allocation support, useful for sse # @@ -196,16 +220,6 @@ PERFORM_CMAKE_TEST(vxl_platform_tests.cxx VXL_HAS_ALIGNED_MALLOC) PERFORM_CMAKE_TEST(vxl_platform_tests.cxx VXL_HAS_MINGW_ALIGNED_MALLOC) PERFORM_CMAKE_TEST(vxl_platform_tests.cxx VXL_HAS_POSIX_MEMALIGN) - - # check for hardware support for sse2 - IF(CMAKE_COMPILER_IS_GNUCXX) - SET(VXL_SSE_TEST_FLAG_BACKUP ${CMAKE_REQUIRED_FLAGS}) - SET(CMAKE_REQUIRED_FLAGS " -msse2 ${VXL_SSE_TEST_FLAG_BACKUP} ") - PERFORM_CMAKE_TEST_RUN(vxl_platform_tests.cxx VXL_HAS_SSE2_HARDWARE_SUPPORT) - SET(CMAKE_REQUIRED_FLAGS ${VXL_SSE_TEST_FLAG_BACKUP}) - ELSE(CMAKE_COMPILER_IS_GNUCXX) - PERFORM_CMAKE_TEST_RUN(vxl_platform_tests.cxx VXL_HAS_SSE2_HARDWARE_SUPPORT) - ENDIF(CMAKE_COMPILER_IS_GNUCXX) ELSE(VXL_HAS_EMMINTRIN_H) SET( VXL_HAS_MM_MALLOC 0 ) SET( VXL_HAS_ALIGNED_MALLOC 0 ) Index: Utilities/vxl/config/cmake/config/vxl_platform_tests.cxx =================================================================== RCS file: /cvsroot/Insight/Insight/Utilities/vxl/config/cmake/config/vxl_platform_tests.cxx,v retrieving revision 1.9 diff -u -r1.9 vxl_platform_tests.cxx --- Utilities/vxl/config/cmake/config/vxl_platform_tests.cxx 13 Nov 2007 14:56:52 -0000 1.9 +++ Utilities/vxl/config/cmake/config/vxl_platform_tests.cxx 12 May 2009 12:40:41 -0000 @@ -1174,7 +1174,7 @@ //------------------------------------- -#ifdef VXL_HAS_SSE2_HARDWARE_SUPPORT +#if defined(VXL_HAS_SSE2_HARDWARE_SUPPORT) || defined(VXL_SSE2_HARDWARE_SUPPORT_POSSIBLE) #include <emmintrin.h> int main() { @@ -1182,12 +1182,12 @@ double d_a[] = { 6.75, 3.42 }; double d_b[] = { 2.3, 9.2 }; double res[2] = {0.0}; - + __m128d z; z = _mm_mul_pd(_mm_loadu_pd(d_a),_mm_loadu_pd(d_b)); - + _mm_storeu_pd(res,z); - + return 0; } #endif Index: Utilities/vxl/core/vnl/CMakeLists.txt =================================================================== RCS file: /cvsroot/Insight/Insight/Utilities/vxl/core/vnl/CMakeLists.txt,v retrieving revision 1.15 diff -u -r1.15 CMakeLists.txt --- Utilities/vxl/core/vnl/CMakeLists.txt 21 Nov 2007 20:24:34 -0000 1.15 +++ Utilities/vxl/core/vnl/CMakeLists.txt 12 May 2009 12:40:41 -0000 @@ -8,19 +8,40 @@ OPTION(VNL_CONFIG_THREAD_SAFE "Whether thread-safe vnl implementations are used." ON) - + #IF( VXL_HAS_EMMINTRIN_H AND VXL_HAS_SSE2_HARDWARE_SUPPORT ) # OPTION(VNL_CONFIG_ENABLE_SSE2 # "Enable Streaming SIMD Extensions 2 optimisations (hardware dependant)." ON) #ELSE ( VXL_HAS_EMMINTRIN_H AND VXL_HAS_SSE2_HARDWARE_SUPPORT ) OPTION(VNL_CONFIG_ENABLE_SSE2 - "Enable Streaming SIMD Extensions 2 optimisations (hardware dependant)." OFF) + "Enable Streaming SIMD Extensions 2 optimisations (hardware dependant). Currently broken. For use by VNL developers only." OFF) #ENDIF( VXL_HAS_EMMINTRIN_H AND VXL_HAS_SSE2_HARDWARE_SUPPORT ) +OPTION(VNL_CONFIG_ENABLE_SSE2_ROUNDING + "Enable Streaming SIMD Extensions 2 implementation of rounding (hardware dependant)." + ${VXL_HAS_SSE2_HARDWARE_SUPPORT_POSSIBLE} ) +IF( VNL_CONFIG_ENABLE_SSE2_ROUNDING ) + IF( NOT VXL_HAS_SSE2_HARDWARE_SUPPORT ) + IF( VXL_SSE2_HARDWARE_SUPPORT_POSSIBLE ) + MESSAGE( ${VXL_SSE2_HARDWARE_SUPPORT_POSSIBLE_HELP} ) + # Reset the update configuration flag + SET( VXL_UPDATE_CONFIGURATION "ON" CACHE BOOL "Re-run the configuration tests?" FORCE ) + MESSAGE( SEND_ERROR "VXL_UPDATE_CONFIGURATION has been forced to ON. " + "Please rerun the cmake configure step" ) + ELSE( VXL_SSE2_HARDWARE_SUPPORT_POSSIBLE ) + MESSAGE( SEND_ERROR "Cannot have VNL_CONFIG_ENABLE_SSE2_ROUNDING because" + " there is no SSE2 hardware support" ) + SET(VNL_CONFIG_ENABLE_SSE2_ROUNDING 0) + ENDIF( VXL_SSE2_HARDWARE_SUPPORT_POSSIBLE ) + ENDIF( NOT VXL_HAS_SSE2_HARDWARE_SUPPORT ) +ENDIF( VNL_CONFIG_ENABLE_SSE2_ROUNDING ) + + MARK_AS_ADVANCED( VNL_CONFIG_CHECK_BOUNDS VNL_CONFIG_LEGACY_METHODS VNL_CONFIG_THREAD_SAFE + VNL_CONFIG_ENABLE_SSE2_ROUNDING VNL_CONFIG_ENABLE_SSE2 ) # Need to enforce 1/0 values for configuration. @@ -44,6 +65,11 @@ ELSE(VNL_CONFIG_ENABLE_SSE2) SET(VNL_CONFIG_ENABLE_SSE2 0) ENDIF(VNL_CONFIG_ENABLE_SSE2) +IF(VNL_CONFIG_ENABLE_SSE2_ROUNDING) + SET(VNL_CONFIG_ENABLE_SSE2_ROUNDING 1) +ELSE(VNL_CONFIG_ENABLE_SSE2_ROUNDING) + SET(VNL_CONFIG_ENABLE_SSE2_ROUNDING 0) +ENDIF(VNL_CONFIG_ENABLE_SSE2_ROUNDING) CONFIGURE_FILE(${vxl_SOURCE_DIR}/core/vnl/vnl_config.h.in ${vxl_BINARY_DIR}/core/vnl/vnl_config.h @ONLY IMMEDIATE) @@ -210,10 +236,6 @@ SET_SOURCE_FILES_PROPERTIES(Templates/vnl_matrix_fixed+vnl_bignum.3.3-.cxx PROPERTIES COMPILE_FLAGS -O0) SET_SOURCE_FILES_PROPERTIES(Templates/vnl_vector+vnl_rational-.cxx PROPERTIES COMPILE_FLAGS -O0) SET_SOURCE_FILES_PROPERTIES(Templates/vnl_vector_fixed+vnl_rational.3-.cxx PROPERTIES COMPILE_FLAGS -O0) - # gcc must have -msse2 option to enable sse2 support - IF(VNL_CONFIG_ENABLE_SSE2) - ADD_DEFINITIONS( -msse2 ) - ENDIF(VNL_CONFIG_ENABLE_SSE2) ENDIF(CMAKE_COMPILER_IS_GNUCXX) ADD_LIBRARY(itkvnl ${vnl_sources}) Index: Utilities/vxl/core/vnl/vnl_config.h.in =================================================================== RCS file: /cvsroot/Insight/Insight/Utilities/vxl/core/vnl/vnl_config.h.in,v retrieving revision 1.3 diff -u -r1.3 vnl_config.h.in --- Utilities/vxl/core/vnl/vnl_config.h.in 13 Nov 2007 14:56:52 -0000 1.3 +++ Utilities/vxl/core/vnl/vnl_config.h.in 12 May 2009 12:40:41 -0000 @@ -19,4 +19,7 @@ //: Set to 0 if you don't have SSE2 support on your target platform #define VNL_CONFIG_ENABLE_SSE2 @VNL_CONFIG_ENABLE_SSE2@ +//: Set to 0 if you don't want to use SSE2 instructions to implement rounding, floor, and ceil functions. +#define VNL_CONFIG_ENABLE_SSE2_ROUNDING @VNL_CONFIG_ENABLE_SSE2_ROUNDING@ + #endif Index: Utilities/vxl/core/vnl/vnl_math.h =================================================================== RCS file: /cvsroot/Insight/Insight/Utilities/vxl/core/vnl/vnl_math.h,v retrieving revision 1.7 diff -u -r1.7 vnl_math.h --- Utilities/vxl/core/vnl/vnl_math.h 22 Aug 2007 17:47:43 -0000 1.7 +++ Utilities/vxl/core/vnl/vnl_math.h 12 May 2009 12:40:41 -0000 @@ -5,39 +5,66 @@ #pragma interface #endif //: -// \file -// \brief Namespace with standard math functions +// \file +// \brief Namespace with standard math functions // -// The vnl_math namespace provides a standard set of the simple mathematical -// functions (min, max, sqr, sgn, rnd, abs), and some predefined constants -// such as pi and e, which are not defined by the ANSI C++ standard. +// The vnl_math namespace provides a standard set of the simple mathematical +// functions (min, max, sqr, sgn, rnd, abs), and some predefined constants +// such as pi and e, which are not defined by the ANSI C++ standard. // -// There are complex versions defined in vnl_complex.h +// There are complex versions defined in vnl_complex.h // -// That's right, M_PI is nonstandard! +// That's right, M_PI is nonstandard! // -// Aside from e, pi and their associates the class also defines eps, -// the IEEE double machine precision. This is the smallest number -// eps such that 1+eps != 1. +// Aside from e, pi and their associates the class also defines eps, +// the IEEE double machine precision. This is the smallest number +// eps such that 1+eps != 1. // -// The operations are overloaded for int, float and double arguments, -// which in combination with inlining can make them more efficient than -// their counterparts in the standard C library. +// The operations are overloaded for int, float and double arguments, +// which in combination with inlining can make them more efficient than +// their counterparts in the standard C library. // -// \author Andrew W. Fitzgibbon, Oxford RRG -// \date July 13, 1996 +// \author Andrew W. Fitzgibbon, Oxford RRG +// \date July 13, 1996 // // \verbatim // Modifications -// 210598 AWF Removed conditional VCL_IMPLEMENT_STATIC_CONSTS, sometimes gcc needs them. -// LSB (Modifications) 23/1/01 Documentation tidied -// Peter Vanroose - 7 Sept. 2002 - maxdouble etc. replaced by vnl_numeric_traits<T>::maxval +// 21 May 1998 AWF Removed conditional VCL_IMPLEMENT_STATIC_CONSTS, sometimes gcc needs them. +// LSB (Modifications) 23 Jan 2001 Documentation tidied +// Peter Vanroose - 7 Sep 2002 - maxdouble etc. replaced by vnl_numeric_traits<T>::maxval // Amitha Perera - 13 Sep 2002 - make constant initialization standards compliant. // \endverbatim #include <vcl_cmath.h> #include "dll.h" -#include <vxl_config.h> // for VXL_C_MATH_HAS_LROUND +#include <vxl_config.h> +#include <vnl/vnl_config.h> // for VNL_CONFIG_ENABLE_SSE2_ROUNDING +#ifdef VNL_CHECK_FPU_ROUNDING_MODE +# include <vcl_cassert.h> +#endif + +// Figure out when the fast implementation can be used +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING +# if !VXL_HAS_EMMINTRIN_H +# error "Required file emmintrin.h for SSE2 not found" +# else +# include <emmintrin.h> // sse 2 intrinsics +# endif +#endif +// Turn on fast impl when using GCC on Intel-based machines with the following exception: +// PPC with Mac OS X +#if defined(__GNUC__) && (!defined(__APPLE__) || !defined(__ppc__) ) +# define GCC_USE_FAST_IMPL 1 +#else +# define GCC_USE_FAST_IMPL 0 +#endif +// Turn on fast impl when using msvc on 32 bits windows +#if defined(VCL_VC) && !defined(_WIN64) +# define VC_USE_FAST_IMPL 1 +#else +# define VC_USE_FAST_IMPL 0 +#endif + //: Type-accessible infinities for use in templates. template <class T> T vnl_huge_val(T); @@ -53,19 +80,20 @@ { public: //: pi, e and all that - static VNL_DLL_DATA const double e VCL_STATIC_CONST_INIT_FLOAT_DECL(2.7182818284590452354); - static VNL_DLL_DATA const double log2e VCL_STATIC_CONST_INIT_FLOAT_DECL(1.4426950408889634074); - static VNL_DLL_DATA const double log10e VCL_STATIC_CONST_INIT_FLOAT_DECL(0.43429448190325182765); - static VNL_DLL_DATA const double ln2 VCL_STATIC_CONST_INIT_FLOAT_DECL(0.69314718055994530942); - static VNL_DLL_DATA const double ln10 VCL_STATIC_CONST_INIT_FLOAT_DECL(2.30258509299404568402); - static VNL_DLL_DATA const double pi VCL_STATIC_CONST_INIT_FLOAT_DECL(3.14159265358979323846); - static VNL_DLL_DATA const double pi_over_2 VCL_STATIC_CONST_INIT_FLOAT_DECL(1.57079632679489661923); - static VNL_DLL_DATA const double pi_over_4 VCL_STATIC_CONST_INIT_FLOAT_DECL(0.78539816339744830962); - static VNL_DLL_DATA const double one_over_pi VCL_STATIC_CONST_INIT_FLOAT_DECL(0.31830988618379067154); - static VNL_DLL_DATA const double two_over_pi VCL_STATIC_CONST_INIT_FLOAT_DECL(0.63661977236758134308); - static VNL_DLL_DATA const double two_over_sqrtpi VCL_STATIC_CONST_INIT_FLOAT_DECL(1.12837916709551257390); - static VNL_DLL_DATA const double sqrt2 VCL_STATIC_CONST_INIT_FLOAT_DECL(1.41421356237309504880); - static VNL_DLL_DATA const double sqrt1_2 VCL_STATIC_CONST_INIT_FLOAT_DECL(0.70710678118654752440); + static VNL_DLL_DATA const double e VCL_STATIC_CONST_INIT_FLOAT_DECL(2.7182818284590452354); + static VNL_DLL_DATA const double log2e VCL_STATIC_CONST_INIT_FLOAT_DECL(1.4426950408889634074); + static VNL_DLL_DATA const double log10e VCL_STATIC_CONST_INIT_FLOAT_DECL(0.43429448190325182765); + static VNL_DLL_DATA const double ln2 VCL_STATIC_CONST_INIT_FLOAT_DECL(0.69314718055994530942); + static VNL_DLL_DATA const double ln10 VCL_STATIC_CONST_INIT_FLOAT_DECL(2.30258509299404568402); + static VNL_DLL_DATA const double pi VCL_STATIC_CONST_INIT_FLOAT_DECL(3.14159265358979323846); + static VNL_DLL_DATA const double pi_over_2 VCL_STATIC_CONST_INIT_FLOAT_DECL(1.57079632679489661923); + static VNL_DLL_DATA const double pi_over_4 VCL_STATIC_CONST_INIT_FLOAT_DECL(0.78539816339744830962); + static VNL_DLL_DATA const double one_over_pi VCL_STATIC_CONST_INIT_FLOAT_DECL(0.31830988618379067154); + static VNL_DLL_DATA const double two_over_pi VCL_STATIC_CONST_INIT_FLOAT_DECL(0.63661977236758134308); + static VNL_DLL_DATA const double two_over_sqrtpi VCL_STATIC_CONST_INIT_FLOAT_DECL(1.12837916709551257390); + static VNL_DLL_DATA const double one_over_sqrt2pi VCL_STATIC_CONST_INIT_FLOAT_DECL(0.39894228040143267794); + static VNL_DLL_DATA const double sqrt2 VCL_STATIC_CONST_INIT_FLOAT_DECL(1.41421356237309504880); + static VNL_DLL_DATA const double sqrt1_2 VCL_STATIC_CONST_INIT_FLOAT_DECL(0.70710678118654752440); //: IEEE double machine precision static VNL_DLL_DATA const double eps VCL_STATIC_CONST_INIT_FLOAT_DECL(2.2204460492503131e-16); @@ -140,50 +168,353 @@ template <class T> bool vnl_math_isfinite(T); #endif -// rnd (rounding; 0.5 rounds up) -#if VXL_C_MATH_HAS_LROUND -// Use C99 functions, which GCC implements as an intrinsic -// Or in simpler terms - is at least 3 times faster. -inline int vnl_math_rnd(float x) { return static_cast<int>(lroundf(x)); } -inline int vnl_math_rnd(double x) { return static_cast<int>(lround(x)); } -#elif defined (VCL_VC) && !defined(__GCCXML__) && !defined(_WIN64) -// Use assembly inline function from -// http://mega-nerd.com/FPcast/ -// - - // Win32 doesn't seem to have these functions. - // Therefore implement inline versions of these functions here. -// NB But Win64 does not support the non-standard _asm - __inline int - vnl_math_rnd (double flt) - { int intgr; - _asm - { fld flt - fistp intgr - } ; - return intgr ; - } - - __inline int - vnl_math_rnd (float flt) - { int intgr; - _asm - { fld flt - fistp intgr - } ; - return intgr; - } -#else -inline int vnl_math_rnd(float x) { return (x>=0.0)?(int)(x + 0.5):(int)(x - 0.5); } -inline int vnl_math_rnd(double x) { return (x>=0.0)?(int)(x + 0.5):(int)(x - 0.5); } + + +// vnl_math_rnd_halfinttoeven -- round towards nearest integer +// halfway cases are rounded towards the nearest even integer, e.g. +// vnl_math_rnd_halfinttoeven( 1.5) == 2 +// vnl_math_rnd_halfinttoeven(-1.5) == -2 +// vnl_math_rnd_halfinttoeven( 2.5) == 2 +// vnl_math_rnd_halfinttoeven( 3.5) == 4 +// +// We assume that the rounding mode is not changed from the default +// one (or at least that it is always restored to the default one). + +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING // Fast sse2 implementation + +inline int vnl_math_rnd_halfinttoeven(float x) +{ +# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) + assert(fegetround()==FE_TONEAREST); +# endif + return _mm_cvtss_si32(_mm_set_ss(x)); +} +inline int vnl_math_rnd_halfinttoeven(double x) +{ +# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) + assert(fegetround()==FE_TONEAREST); +# endif + return _mm_cvtsd_si32(_mm_set_sd(x)); +} + +#elif GCC_USE_FAST_IMPL // Fast gcc asm implementation + +inline int vnl_math_rnd_halfinttoeven(float x) +{ +# ifdef VNL_CHECK_FPU_ROUNDING_MODE + assert(fegetround()==FE_TONEAREST); +# endif + int r; + __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); + return r; +} +inline int vnl_math_rnd_halfinttoeven(double x) +{ +# ifdef VNL_CHECK_FPU_ROUNDING_MODE + assert(fegetround()==FE_TONEAREST); +# endif + int r; + __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); + return r; +} + +#elif VC_USE_FAST_IMPL // Fast msvc asm implementation + +inline int vnl_math_rnd_halfinttoeven(float x) +{ + int r; + __asm { + fld x + fistp r + } + return r; +} +inline int vnl_math_rnd_halfinttoeven(double x) +{ + int r; + __asm { + fld x + fistp r + } + return r; +} + +#else // Vanilla implementation + +inline int vnl_math_rnd_halfinttoeven(float x) +{ + if (x>=0.f) + { + x+=0.5f; + const int r = static_cast<int>(x); + if ( x != static_cast<float>(r) ) return r; + return 2*(r/2); + } + else + { + x-=0.5f; + const int r = static_cast<int>(x); + if ( x != static_cast<float>(r) ) return r; + return 2*(r/2); + } +} +inline int vnl_math_rnd_halfinttoeven(double x) +{ + if (x>=0.) + { + x+=0.5; + const int r = static_cast<int>(x); + if ( x != static_cast<double>(r) ) return r; + return 2*(r/2); + } + else + { + x-=0.5; + const int r = static_cast<int>(x); + if ( x != static_cast<double>(r) ) return r; + return 2*(r/2); + } +} + +#endif + + + +// vnl_math_rnd_halfintup -- round towards nearest integer +// halfway cases are rounded upward, e.g. +// vnl_math_rnd_halfintup( 1.5) == 2 +// vnl_math_rnd_halfintup(-1.5) == -1 +// vnl_math_rnd_halfintup( 2.5) == 3 +// +// Be careful: argument absolute value must be less than INT_MAX/2 +// for vnl_math_rnd_halfintup to be guaranteed to work. +// We also assume that the rounding mode is not changed from the default +// one (or at least that it is always restored to the default one). + +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING || GCC_USE_FAST_IMPL || VC_USE_FAST_IMPL + +inline int vnl_math_rnd_halfintup(float x) { return vnl_math_rnd_halfinttoeven(2*x+0.5f)>>1; } +inline int vnl_math_rnd_halfintup(double x) { return vnl_math_rnd_halfinttoeven(2*x+0.5)>>1; } + +#else // Vanilla implementation + +inline int vnl_math_rnd_halfintup(float x) +{ + x+=0.5f; + return static_cast<int>(x>=0.f?x:(x==static_cast<int>(x)?x:x-1.f)); +} +inline int vnl_math_rnd_halfintup(double x) +{ + x+=0.5; + return static_cast<int>(x>=0.?x:(x==static_cast<int>(x)?x:x-1.)); +} + +#endif + + + +// vnl_math_rnd -- round towards nearest integer +// halfway cases such as 0.5 may be rounded either up or down +// so as to maximize the efficiency, e.g. +// vnl_math_rnd_halfinttoeven( 1.5) == 1 or 2 +// vnl_math_rnd_halfinttoeven(-1.5) == -2 or -1 +// vnl_math_rnd_halfinttoeven( 2.5) == 2 or 3 +// vnl_math_rnd_halfinttoeven( 3.5) == 3 or 4 +// +// We assume that the rounding mode is not changed from the default +// one (or at least that it is always restored to the default one). + +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING || GCC_USE_FAST_IMPL || VC_USE_FAST_IMPL + +inline int vnl_math_rnd(float x) { return vnl_math_rnd_halfinttoeven(x); } +inline int vnl_math_rnd(double x) { return vnl_math_rnd_halfinttoeven(x); } + +#else // Vanilla implementation + +inline int vnl_math_rnd(float x) { return x>=0.f?static_cast<int>(x+.5f):static_cast<int>(x-.5f); } +inline int vnl_math_rnd(double x) { return x>=0.0?static_cast<int>(x+0.5):static_cast<int>(x-0.5); } + + +#endif + + + +// vnl_math_floor -- round towards minus infinity +// +// Be careful: argument absolute value must be less than INT_MAX/2 +// for vnl_math_floor to be guaranteed to work. +// We also assume that the rounding mode is not changed from the default +// one (or at least that it is always restored to the default one). + +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING // Fast sse2 implementation + +inline int vnl_math_floor(float x) +{ +# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) + assert(fegetround()==FE_TONEAREST); +# endif + return _mm_cvtss_si32(_mm_set_ss(2*x-.5f))>>1; +} +inline int vnl_math_floor(double x) +{ +# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) + assert(fegetround()==FE_TONEAREST); +# endif + return _mm_cvtsd_si32(_mm_set_sd(2*x-.5))>>1; +} + +#elif GCC_USE_FAST_IMPL // Fast gcc asm implementation + +inline int vnl_math_floor(float x) +{ +# ifdef VNL_CHECK_FPU_ROUNDING_MODE + assert(fegetround()==FE_TONEAREST); +# endif + int r; + x = 2*x-.5f; + __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); + return r>>1; +} +inline int vnl_math_floor(double x) +{ +# ifdef VNL_CHECK_FPU_ROUNDING_MODE + assert(fegetround()==FE_TONEAREST); +# endif + int r; + x = 2*x-.5; + __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); + return r>>1; +} + +#elif VC_USE_FAST_IMPL // Fast msvc asm implementation + +inline int vnl_math_floor(float x) +{ + int r; + x = 2*x-.5f; + __asm { + fld x + fistp r + } + return r>>1; +} +inline int vnl_math_floor(double x) +{ + int r; + x = 2*x-.5; + __asm { + fld x + fistp r + } + return r>>1; +} + +#else // Vanilla implementation + +inline int vnl_math_floor(float x) +{ + return static_cast<int>(x>=0.f?x:(x==static_cast<int>(x)?x:x-1.f)); +} +inline int vnl_math_floor(double x) +{ + return static_cast<int>(x>=0.0?x:(x==static_cast<int>(x)?x:x-1.0)); +} + #endif + + +// vnl_math_ceil -- round towards plus infinity +// +// Be careful: argument absolute value must be less than INT_MAX/2 +// for vnl_math_ceil to be guaranteed to work. +// We also assume that the rounding mode is not changed from the default +// one (or at least that it is always restored to the default one). + +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING // Fast sse2 implementation + +inline int vnl_math_ceil(float x) +{ +# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) + assert(fegetround()==FE_TONEAREST); +# endif + return -(_mm_cvtss_si32(_mm_set_ss(-.5f-2*x))>>1); +} +inline int vnl_math_ceil(double x) +{ +# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) + assert(fegetround()==FE_TONEAREST); +# endif + return -(_mm_cvtsd_si32(_mm_set_sd(-.5-2*x))>>1); +} + +#elif GCC_USE_FAST_IMPL // Fast gcc asm implementation + +inline int vnl_math_ceil(float x) +{ +# ifdef VNL_CHECK_FPU_ROUNDING_MODE + assert(fegetround()==FE_TONEAREST); +# endif + int r; + x = -.5f-2*x; + __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); + return -(r>>1); +} +inline int vnl_math_ceil(double x) +{ +# ifdef VNL_CHECK_FPU_ROUNDING_MODE + assert(fegetround()==FE_TONEAREST); +# endif + int r; + x = -.5-2*x; + __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); + return -(r>>1); +} + +#elif VC_USE_FAST_IMPL // Fast msvc asm implementation + +inline int vnl_math_ceil(float x) +{ + int r; + x = -.5f-2*x; + __asm { + fld x + fistp r + } + return -(r>>1); +} +inline int vnl_math_ceil(double x) +{ + int r; + x = -.5-2*x; + __asm { + fld x + fistp r + } + return -(r>>1); +} + +#else // Vanilla implementation + +inline int vnl_math_ceil(float x) +{ + return static_cast<int>(x<0.f?x:(x==static_cast<int>(x)?x:x+1.f)); +} +inline int vnl_math_ceil(double x) +{ + return static_cast<int>(x<0.0?x:(x==static_cast<int>(x)?x:x+1.0)); +} + +#endif + + + // abs inline bool vnl_math_abs(bool x) { return x; } inline unsigned char vnl_math_abs(unsigned char x) { return x; } -inline unsigned char vnl_math_abs(signed char x) { return x < 0 ? -x : x; } -inline unsigned char vnl_math_abs(char x) { return (unsigned char)x; } -inline unsigned short vnl_math_abs(short x) { return x < 0 ? -x : x; } +inline unsigned char vnl_math_abs(signed char x) { return x < 0 ? static_cast<unsigned char>(-x) : x; } +inline unsigned char vnl_math_abs(char x) { return static_cast<unsigned char>(x); } +inline unsigned short vnl_math_abs(short x) { return x < 0 ? static_cast<unsigned short>(-x) : x; } inline unsigned short vnl_math_abs(unsigned short x){ return x; } inline unsigned int vnl_math_abs(int x) { return x < 0 ? -x : x; } inline unsigned int vnl_math_abs(unsigned int x) { return x; } Index: Utilities/vxl/core/vnl/tests/test_math.cxx =================================================================== RCS file: /cvsroot/Insight/Insight/Utilities/vxl/core/vnl/tests/test_math.cxx,v retrieving revision 1.10 diff -u -r1.10 test_math.cxx --- Utilities/vxl/core/vnl/tests/test_math.cxx 20 Apr 2009 20:01:37 -0000 1.10 +++ Utilities/vxl/core/vnl/tests/test_math.cxx 12 May 2009 12:40:42 -0000 @@ -68,22 +68,135 @@ testlib_test_assert_near("exp(d*i) ~= -1", vnl_math_abs(e_ipi+1.0), 0); vcl_cout << vcl_endl; - testlib_test_assert("rnd(-8.4999) == -8", vnl_math_rnd(-8.4999) == -8); - testlib_test_assert("rnd(-8.4999f) == -8", vnl_math_rnd(-8.4999f) == -8); - vcl_cout << "vnl_math_rnd(-8.50) == " << vnl_math_rnd(-8.50) << vcl_endl; - testlib_test_assert("rnd(-8.50) == -8/9", vnl_math_rnd(-8.50)/2 == -4); - testlib_test_assert("rnd(-8.50f) == -8/9", vnl_math_rnd(-8.50f)/2 == -4); - vcl_cout << "vnl_math_rnd(-8.5001) == " << vnl_math_rnd(-8.5001) << vcl_endl; - testlib_test_assert("rnd(-8.5001) == -9", vnl_math_rnd(-8.5001) == -9); - testlib_test_assert("rnd(-8.5001f) == -9", vnl_math_rnd(-8.5001f) == -9); - testlib_test_assert("rnd(8.4999) == 8", vnl_math_rnd(8.4999) == 8); - testlib_test_assert("rnd(8.4999f) == 8", vnl_math_rnd(8.4999f) == 8); - testlib_test_assert("rnd(8.50) == 8/9", vnl_math_rnd(8.50)/2 == 4); - vcl_cout << "vnl_math_rnd(8.50) == " << vnl_math_rnd(8.50) << vcl_endl; - testlib_test_assert("rnd(8.50f) == 8/9", vnl_math_rnd(8.50f)/2 == 4); - vcl_cout << "vnl_math_rnd(8.5001) == " << vnl_math_rnd(8.5001) << vcl_endl; - testlib_test_assert("rnd(8.5001) == 9", vnl_math_rnd(8.5001) == 9); - testlib_test_assert("rnd(8.5001f) == 9", vnl_math_rnd(8.5001f) == 9); + testlib_test_assert("rnd(-8.4999) == -8 ", vnl_math_rnd(-8.4999) == -8); + testlib_test_assert("rnd(-8.4999f) == -8 ", vnl_math_rnd(-8.4999f) == -8); + testlib_test_assert("rnd(-8.50) == -8/9", vnl_math_rnd(-8.50)/2 == -4); + testlib_test_assert("rnd(-8.50f) == -8/9", vnl_math_rnd(-8.50f)/2 == -4); + testlib_test_assert("rnd(-8.5001) == -9 ", vnl_math_rnd(-8.5001) == -9); + testlib_test_assert("rnd(-8.5001f) == -9 ", vnl_math_rnd(-8.5001f) == -9); + testlib_test_assert("rnd(8.4999) == 8 ", vnl_math_rnd(8.4999) == 8); + testlib_test_assert("rnd(8.4999f) == 8 ", vnl_math_rnd(8.4999f) == 8); + testlib_test_assert("rnd(8.50) == 8/9", vnl_math_rnd(8.50)/2 == 4); + testlib_test_assert("rnd(8.50f) == 8/9", vnl_math_rnd(8.50f)/2 == 4); + testlib_test_assert("rnd(8.5001) == 9 ", vnl_math_rnd(8.5001) == 9); + testlib_test_assert("rnd(8.5001f) == 9 ", vnl_math_rnd(8.5001f) == 9); + + testlib_test_assert("rnd(-9.4999) == -9 ", vnl_math_rnd(-9.4999) == -9); + testlib_test_assert("rnd(-9.4999f) == -9 ", vnl_math_rnd(-9.4999f) == -9); + testlib_test_assert("rnd(-9.50) == -9/10", (vnl_math_rnd(-9.50)+1)/2 == -4); + testlib_test_assert("rnd(-9.50f) == -9/10", (vnl_math_rnd(-9.50f)+1)/2 == -4); + testlib_test_assert("rnd(-9.5001) == -10 ", vnl_math_rnd(-9.5001) == -10); + testlib_test_assert("rnd(-9.5001f) == -10 ", vnl_math_rnd(-9.5001f) == -10); + testlib_test_assert("rnd(9.4999) == 9 ", vnl_math_rnd(9.4999) == 9); + testlib_test_assert("rnd(9.4999f) == 9 ", vnl_math_rnd(9.4999f) == 9); + testlib_test_assert("rnd(9.50) == 9/10", (vnl_math_rnd(9.50)-1)/2 == 4); + testlib_test_assert("rnd(9.50f) == 9/10", (vnl_math_rnd(9.50f)-1)/2 == 4); + testlib_test_assert("rnd(9.5001) == 10 ", vnl_math_rnd(9.5001) == 10); + testlib_test_assert("rnd(9.5001f) == 10 ", vnl_math_rnd(9.5001f) == 10); + + testlib_test_assert("rnd_halfinttoeven(-8.4999) == -8", vnl_math_rnd_halfinttoeven(-8.4999) == -8); + testlib_test_assert("rnd_halfinttoeven(-8.4999f) == -8", vnl_math_rnd_halfinttoeven(-8.4999f)== -8); + testlib_test_assert("rnd_halfinttoeven(-8.50) == -8", vnl_math_rnd_halfinttoeven(-8.50) == -8); + testlib_test_assert("rnd_halfinttoeven(-8.50f) == -8", vnl_math_rnd_halfinttoeven(-8.50f) == -8); + testlib_test_assert("rnd_halfinttoeven(-8.5001) == -9", vnl_math_rnd_halfinttoeven(-8.5001) == -9); + testlib_test_assert("rnd_halfinttoeven(-8.5001f) == -9", vnl_math_rnd_halfinttoeven(-8.5001f)== -9); + testlib_test_assert("rnd_halfinttoeven(8.4999) == 8", vnl_math_rnd_halfinttoeven(8.4999) == 8); + testlib_test_assert("rnd_halfinttoeven(8.4999f) == 8", vnl_math_rnd_halfinttoeven(8.4999f)== 8); + testlib_test_assert("rnd_halfinttoeven(8.50) == 9", vnl_math_rnd_halfinttoeven(8.50) == 8); + testlib_test_assert("rnd_halfinttoeven(8.50f) == 9", vnl_math_rnd_halfinttoeven(8.50f) == 8); + testlib_test_assert("rnd_halfinttoeven(8.5001) == 9", vnl_math_rnd_halfinttoeven(8.5001) == 9); + testlib_test_assert("rnd_halfinttoeven(8.5001f) == 9", vnl_math_rnd_halfinttoeven(8.5001f)== 9); + + testlib_test_assert("rnd_halfinttoeven(-9.4999) == -9 ", vnl_math_rnd_halfinttoeven(-9.4999) == -9); + testlib_test_assert("rnd_halfinttoeven(-9.4999f) == -9 ", vnl_math_rnd_halfinttoeven(-9.4999f)== -9); + testlib_test_assert("rnd_halfinttoeven(-9.50) == -9 ", vnl_math_rnd_halfinttoeven(-9.50) == -10); + testlib_test_assert("rnd_halfinttoeven(-9.50f) == -9 ", vnl_math_rnd_halfinttoeven(-9.50f) == -10); + testlib_test_assert("rnd_halfinttoeven(-9.5001) == -10", vnl_math_rnd_halfinttoeven(-9.5001) == -10); + testlib_test_assert("rnd_halfinttoeven(-9.5001f) == -10", vnl_math_rnd_halfinttoeven(-9.5001f)== -10); + testlib_test_assert("rnd_halfinttoeven(9.4999) == 9 ", vnl_math_rnd_halfinttoeven(9.4999) == 9); + testlib_test_assert("rnd_halfinttoeven(9.4999f) == 9 ", vnl_math_rnd_halfinttoeven(9.4999f)== 9); + testlib_test_assert("rnd_halfinttoeven(9.50) == 10", vnl_math_rnd_halfinttoeven(9.50) == 10); + testlib_test_assert("rnd_halfinttoeven(9.50f) == 10", vnl_math_rnd_halfinttoeven(9.50f) == 10); + testlib_test_assert("rnd_halfinttoeven(9.5001) == 10", vnl_math_rnd_halfinttoeven(9.5001) == 10); + testlib_test_assert("rnd_halfinttoeven(9.5001f) == 10", vnl_math_rnd_halfinttoeven(9.5001f)== 10); + + testlib_test_assert("rnd_halfintup(-8.4999) == -8", vnl_math_rnd_halfintup(-8.4999) == -8); + testlib_test_assert("rnd_halfintup(-8.4999f) == -8", vnl_math_rnd_halfintup(-8.4999f)== -8); + testlib_test_assert("rnd_halfintup(-8.50) == -8", vnl_math_rnd_halfintup(-8.50) == -8); + testlib_test_assert("rnd_halfintup(-8.50f) == -8", vnl_math_rnd_halfintup(-8.50f) == -8); + testlib_test_assert("rnd_halfintup(-8.5001) == -9", vnl_math_rnd_halfintup(-8.5001) == -9); + testlib_test_assert("rnd_halfintup(-8.5001f) == -9", vnl_math_rnd_halfintup(-8.5001f)== -9); + testlib_test_assert("rnd_halfintup(8.4999) == 8", vnl_math_rnd_halfintup(8.4999) == 8); + testlib_test_assert("rnd_halfintup(8.4999f) == 8", vnl_math_rnd_halfintup(8.4999f)== 8); + testlib_test_assert("rnd_halfintup(8.50) == 9", vnl_math_rnd_halfintup(8.50) == 9); + testlib_test_assert("rnd_halfintup(8.50f) == 9", vnl_math_rnd_halfintup(8.50f) == 9); + testlib_test_assert("rnd_halfintup(8.5001) == 9", vnl_math_rnd_halfintup(8.5001) == 9); + testlib_test_assert("rnd_halfintup(8.5001f) == 9", vnl_math_rnd_halfintup(8.5001f)== 9); + + testlib_test_assert("rnd_halfintup(-9.4999) == -9 ", vnl_math_rnd_halfintup(-9.4999) == -9); + testlib_test_assert("rnd_halfintup(-9.4999f) == -9 ", vnl_math_rnd_halfintup(-9.4999f)== -9); + testlib_test_assert("rnd_halfintup(-9.50) == -9 ", vnl_math_rnd_halfintup(-9.50) == -9); + testlib_test_assert("rnd_halfintup(-9.50f) == -9 ", vnl_math_rnd_halfintup(-9.50f) == -9); + testlib_test_assert("rnd_halfintup(-9.5001) == -10", vnl_math_rnd_halfintup(-9.5001) == -10); + testlib_test_assert("rnd_halfintup(-9.5001f) == -10", vnl_math_rnd_halfintup(-9.5001f)== -10); + testlib_test_assert("rnd_halfintup(9.4999) == 9 ", vnl_math_rnd_halfintup(9.4999) == 9); + testlib_test_assert("rnd_halfintup(9.4999f) == 9 ", vnl_math_rnd_halfintup(9.4999f)== 9); + testlib_test_assert("rnd_halfintup(9.50) == 10", vnl_math_rnd_halfintup(9.50) == 10); + testlib_test_assert("rnd_halfintup(9.50f) == 10", vnl_math_rnd_halfintup(9.50f) == 10); + testlib_test_assert("rnd_halfintup(9.5001) == 10", vnl_math_rnd_halfintup(9.5001) == 10); + testlib_test_assert("rnd_halfintup(9.5001f) == 10", vnl_math_rnd_halfintup(9.5001f)== 10); + + testlib_test_assert("floor(8.0) == 8", vnl_math_floor(8.0) == 8); + testlib_test_assert("floor(8.0f) == 8", vnl_math_floor(8.0f) == 8); + testlib_test_assert("floor(8.9999) == 8", vnl_math_floor(8.9999) == 8); + testlib_test_assert("floor(8.9999f) == 8", vnl_math_floor(8.9999f) == 8); + testlib_test_assert("floor(8.0001) == 8", vnl_math_floor(8.0001) == 8); + testlib_test_assert("floor(8.0001f) == 8", vnl_math_floor(8.0001f) == 8); + testlib_test_assert("floor(-8.0) == -8", vnl_math_floor(-8.0) == -8); + testlib_test_assert("floor(-8.0f) == -8", vnl_math_floor(-8.0f) == -8); + testlib_test_assert("floor(-8.9999) == -9", vnl_math_floor(-8.9999) == -9); + testlib_test_assert("floor(-8.9999f) == -9", vnl_math_floor(-8.9999f) == -9); + testlib_test_assert("floor(-8.0001) == -9", vnl_math_floor(-8.0001) == -9); + testlib_test_assert("floor(-8.0001f) == -9", vnl_math_floor(-8.0001f) == -9); + + testlib_test_assert("floor(9.0) == 9", vnl_math_floor(9.0) == 9); + testlib_test_assert("floor(9.0f) == 9", vnl_math_floor(9.0f) == 9); + testlib_test_assert("floor(9.9999) == 9", vnl_math_floor(9.9999) == 9); + testlib_test_assert("floor(9.9999f) == 9", vnl_math_floor(9.9999f) == 9); + testlib_test_assert("floor(9.0001) == 9", vnl_math_floor(9.0001) == 9); + testlib_test_assert("floor(9.0001f) == 9", vnl_math_floor(9.0001f) == 9); + testlib_test_assert("floor(-9.0) == -9", vnl_math_floor(-9.0) == -9); + testlib_test_assert("floor(-9.0f) == -9", vnl_math_floor(-9.0f) == -9); + testlib_test_assert("floor(-9.9999) == -10", vnl_math_floor(-9.9999) == -10); + testlib_test_assert("floor(-9.9999f) == -10", vnl_math_floor(-9.9999f) == -10); + testlib_test_assert("floor(-9.0001) == -10", vnl_math_floor(-9.0001) == -10); + testlib_test_assert("floor(-9.0001f) == -10", vnl_math_floor(-9.0001f) == -10); + + testlib_test_assert("ceil(8.0) == 8", vnl_math_ceil(8.0) == 8); + testlib_test_assert("ceil(8.0f) == 8", vnl_math_ceil(8.0f) == 8); + testlib_test_assert("ceil(8.9999) == 9", vnl_math_ceil(8.9999) == 9); + testlib_test_assert("ceil(8.9999f) == 9", vnl_math_ceil(8.9999f) == 9); + testlib_test_assert("ceil(8.0001) == 9", vnl_math_ceil(8.0001) == 9); + testlib_test_assert("ceil(8.0001f) == 9", vnl_math_ceil(8.0001f) == 9); + testlib_test_assert("ceil(-8.0) == -8", vnl_math_ceil(-8.0) == -8); + testlib_test_assert("ceil(-8.0f) == -8", vnl_math_ceil(-8.0f) == -8); + testlib_test_assert("ceil(-8.9999) == -8", vnl_math_ceil(-8.9999) == -8); + testlib_test_assert("ceil(-8.9999f) == -8", vnl_math_ceil(-8.9999f) == -8); + testlib_test_assert("ceil(-8.0001) == -8", vnl_math_ceil(-8.0001) == -8); + testlib_test_assert("ceil(-8.0001f) == -8", vnl_math_ceil(-8.0001f) == -8); + + testlib_test_assert("ceil(9.0) == 9", vnl_math_ceil(9.0) == 9); + testlib_test_assert("ceil(9.0f) == 9", vnl_math_ceil(9.0f) == 9); + testlib_test_assert("ceil(9.9999) == 10", vnl_math_ceil(9.9999) == 10); + testlib_test_assert("ceil(9.9999f) == 10", vnl_math_ceil(9.9999f) == 10); + testlib_test_assert("ceil(9.0001) == 10", vnl_math_ceil(9.0001) == 10); + testlib_test_assert("ceil(9.0001f) == 10", vnl_math_ceil(9.0001f) == 10); + testlib_test_assert("ceil(-9.0) == -9", vnl_math_ceil(-9.0) == -9); + testlib_test_assert("ceil(-9.0f) == -9", vnl_math_ceil(-9.0f) == -9); + testlib_test_assert("ceil(-9.9999) == -9", vnl_math_ceil(-9.9999) == -9); + testlib_test_assert("ceil(-9.9999f) == -9", vnl_math_ceil(-9.9999f) == -9); + testlib_test_assert("ceil(-9.0001) == -9", vnl_math_ceil(-9.0001) == -9); + testlib_test_assert("ceil(-9.0001f) == -9", vnl_math_ceil(-9.0001f) == -9); testlib_test_assert(" isfinite(f) ", vnl_math_isfinite(f)); testlib_test_assert(" isfinite(d) ", vnl_math_isfinite(d)); itk-portable-round-2009-05-15.patch [^] (45,362 bytes) 2009-05-15 12:50 [Show Content] [Hide Content] ? Code/Algorithms/itkMultiResolutionPDEDeformableRegistration.txx-old ? Code/Algorithms/itkMultiResolutionPyramidImageFilter.txx-old ? Code/Algorithms/itkNCCRegistrationFunction.h-old ? Code/Algorithms/itkNCCRegistrationFunction.txx-old ? Code/Algorithms/itkRecursiveMultiResolutionPyramidImageFilter.txx-old ? Testing/Code/Algorithms/itkMultiResolutionPyramidImageFilterTest.cxx-old ? Testing/Code/Algorithms/itkRecursiveMultiResolutionPyramidImageFilterTest.cxx-old Index: CMakeLists.txt =================================================================== RCS file: /cvsroot/Insight/Insight/CMakeLists.txt,v retrieving revision 1.338 diff -u -r1.338 CMakeLists.txt --- CMakeLists.txt 14 May 2009 02:12:55 -0000 1.338 +++ CMakeLists.txt 15 May 2009 16:45:17 -0000 @@ -490,6 +490,11 @@ MARK_AS_ADVANCED(ITK_USE_64BITS_APPLE_TRUNCATION_WARNING) ENDIF(APPLE) + + # gcc must have -msse2 option to enable sse2 support + IF(VNL_CONFIG_ENABLE_SSE2 OR VNL_CONFIG_ENABLE_SSE2_ROUNDING) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse2") + ENDIF(VNL_CONFIG_ENABLE_SSE2 OR VNL_CONFIG_ENABLE_SSE2_ROUNDING) ENDIF(CMAKE_COMPILER_IS_GNUCXX) IF(UNIX) Index: ITKConfig.cmake.in =================================================================== RCS file: /cvsroot/Insight/Insight/ITKConfig.cmake.in,v retrieving revision 1.28 diff -u -r1.28 ITKConfig.cmake.in --- ITKConfig.cmake.in 8 May 2009 14:20:16 -0000 1.28 +++ ITKConfig.cmake.in 15 May 2009 16:45:17 -0000 @@ -68,3 +68,7 @@ # same for gdcm SET(ITK_VXL_DIR "@ITK_VXL_DIR@") SET(ITK_GDCM_DIR "@ITK_GDCM_DIR@") + +# Let's also export VNL_CONFIG_ENABLE_SSE2_ROUNDING as it may be requirred +# to know whether to add a -msse2 compilation flag for gcc +SET(VNL_CONFIG_ENABLE_SSE2_ROUNDING "@VNL_CONFIG_ENABLE_SSE2_ROUNDING@") Index: Code/Common/itkMacro.h =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkMacro.h,v retrieving revision 1.93 diff -u -r1.93 itkMacro.h --- Code/Common/itkMacro.h 12 May 2009 14:41:39 -0000 1.93 +++ Code/Common/itkMacro.h 15 May 2009 16:45:18 -0000 @@ -39,9 +39,7 @@ #include <cassert> #endif -#ifndef ITK_USE_PORTABLE_ROUND #include "vnl/vnl_math.h" -#endif // Determine type of string stream to use. #if !defined(CMAKE_NO_ANSI_STRING_STREAM) @@ -974,194 +972,14 @@ namespace itk { - namespace Math { - -#ifdef ITK_USE_PORTABLE_ROUND -// RoundHalfIntegerUp -- round towards nearest integer -// halfway cases are rounded upward, e.g. -// RoundHalfIntegerUp( 1.5) == 2 -// RoundHalfIntegerUp(-1.5) == -1 -// RoundHalfIntegerUp( 2.5) == 3 -// -// Be careful: argument absolute value must be less than INT_MAX/2 -// for RoundHalfIntegerUp to be guaranteed to work. -// We also assume that the rounding mode is not changed from the default -// one (or at least that it is always restored to the default one). - -#if VNL_CONFIG_ENABLE_SSE2_ROUNDING || GCC_USE_FAST_IMPL || VC_USE_FAST_IMPL - -inline int RoundHalfIntegerUp(float x) { return RoundHalfIntegerToEven(2*x+0.5f)>>1; } -inline int RoundHalfIntegerUp(double x) { return RoundHalfIntegerToEven(2*x+0.5)>>1; } - -#else // Vanilla implementation - -inline int RoundHalfIntegerUp(float x) -{ - x += 0.5f; - return static_cast<int>(x>=0.f?x:(x==static_cast<int>(x)?x:x-1.f)); -} -inline int RoundHalfIntegerUp(double x) -{ - x += 0.5; - return static_cast<int>(x>=0.?x:(x==static_cast<int>(x)?x:x-1.)); -} - -#endif - - -// Round -- round towards nearest integer -// halfway cases such as 0.5 may be rounded either up or down -// so as to maximize the efficiency, e.g. -// RoundHalfIntegerToEven( 1.5) == 1 or 2 -// RoundHalfIntegerToEven(-1.5) == -2 or -1 -// RoundHalfIntegerToEven( 2.5) == 2 or 3 -// RoundHalfIntegerToEven( 3.5) == 3 or 4 -// -// We assume that the rounding mode is not changed from the default -// one (or at least that it is always restored to the default one). - -#if VNL_CONFIG_ENABLE_SSE2_ROUNDING || GCC_USE_FAST_IMPL || VC_USE_FAST_IMPL - -inline int Round(float x) { return RoundHalfIntegerToEven(x); } +inline int RoundHalfIntegerUp(float x) { return vnl_math_rnd_halfintup(x); } +inline int RoundHalfIntegerUp(double x) { return vnl_math_rnd_halfintup(x); } +inline int RoundHalfIntegerToEven(float x) { return vnl_math_rnd_halfinttoeven(x); } +inline int RoundHalfIntegerToEven(double x) { return vnl_math_rnd_halfinttoeven(x); } +inline int Round(float x) { return RoundHalfIntegerToEven(x); } inline int Round(double x) { return RoundHalfIntegerToEven(x); } - -#else // Vanilla implementation - -inline int Round(float x) { return x>=0.f?static_cast<int>(x+.5f):static_cast<int>(x-.5f); } -inline int Round(double x) { return x>=0.0?static_cast<int>(x+0.5):static_cast<int>(x-0.5); } - - -#endif - - -// RoundHalfIntegerToEven -- round towards nearest integer -// halfway cases are rounded towards the nearest even integer, e.g. -// RoundHalfIntegerToEven( 1.5) == 2 -// RoundHalfIntegerToEven(-1.5) == -2 -// RoundHalfIntegerToEven( 2.5) == 2 -// RoundHalfIntegerToEven( 3.5) == 4 -// -// We assume that the rounding mode is not changed from the default -// one (or at least that it is always restored to the default one). - -#if VNL_CONFIG_ENABLE_SSE2_ROUNDING // Fast sse2 implementation - -inline int RoundHalfIntegerToEven(float x) -{ -# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) - assert( fegetround() == FE_TONEAREST ); -# endif - return _mm_cvtss_si32(_mm_set_ss(x)); -} -inline int RoundHalfIntegerToEven(double x) -{ -# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) - assert( fegetround() == FE_TONEAREST ); -# endif - return _mm_cvtsd_si32(_mm_set_sd(x)); -} - -#elif GCC_USE_FAST_IMPL // Fast gcc asm implementation - -inline int RoundHalfIntegerToEven(float x) - { -# ifdef VNL_CHECK_FPU_ROUNDING_MODE - assert( fegetround() == FE_TONEAREST ); -# endif - int r; - __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); - return r; - } - -inline int RoundHalfIntegerToEven(double x) - { -# ifdef VNL_CHECK_FPU_ROUNDING_MODE - assert( fegetround() == FE_TONEAREST ); -# endif - int r; - __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); - return r; - } - -#elif VC_USE_FAST_IMPL // Fast msvc asm implementation - -inline int RoundHalfIntegerToEven(float x) - { - int r; - __asm { -@@ -218,10 +228,7 @@ - } - return r; - } - -inline int RoundHalfIntegerToEven(double x) - { - int r; - __asm { -@@ -230,59 +237,156 @@ - } - return r; - } - -#else // Vanilla implementation - -inline int RoundHalfIntegerToEven(float x) -{ - if (x>=0.f) - { - x += 0.5f; - const int r = static_cast<int>(x); - if ( x != static_cast<float>(r) ) - { - return r; - } - return 2*(r/2); - } - else - { - x -= 0.5f; - const int r = static_cast<int>(x); - if ( x != static_cast<float>(r) ) - { - return r; - } - return 2*(r/2); - } -} - -inline int RoundHalfIntegerToEven(double x) -{ - if (x >= 0.0) - { - x += 0.5; - const int r = static_cast<int>(x); - if ( x != static_cast<double>(r) ) - { - return r; - } - return 2*(r/2); - } - else - { - x -= 0.5; - const int r = static_cast<int>(x); - if ( x != static_cast<double>(r) ) - { - return r; - } - return 2*(r/2); - } -} - -#endif - -#else - // Resort to the previous vnl_math_rnd() - inline int Round(float x) { return vnl_math_rnd(x); } - inline int Round(double x) { return vnl_math_rnd(x); } -#endif } // end namespace Math } // end namespace itk Index: Utilities/vxl/config/cmake/config/CMakeLists.txt =================================================================== RCS file: /cvsroot/Insight/Insight/Utilities/vxl/config/cmake/config/CMakeLists.txt,v retrieving revision 1.14 diff -u -r1.14 CMakeLists.txt --- Utilities/vxl/config/cmake/config/CMakeLists.txt 27 Feb 2009 19:51:12 -0000 1.14 +++ Utilities/vxl/config/cmake/config/CMakeLists.txt 15 May 2009 16:45:23 -0000 @@ -186,6 +186,30 @@ PERFORM_CHECK_HEADER(iso646.h VCL_CXX_HAS_HEADER_ISO646_H) PERFORM_CHECK_HEADER(emmintrin.h VXL_HAS_EMMINTRIN_H) +# check for hardware support for sse2 with the current compiler flags +PERFORM_CMAKE_TEST_RUN(vxl_platform_tests.cxx VXL_HAS_SSE2_HARDWARE_SUPPORT) + +# if no support right now, see if the support exists if some flags +# are added. This can be used to give the user some useful info. +IF(NOT VXL_HAS_SSE2_HARDWARE_SUPPORT) + IF(CMAKE_COMPILER_IS_GNUCXX) + SET(VXL_SSE_TEST_FLAG_BACKUP ${CMAKE_REQUIRED_FLAGS}) + SET(CMAKE_REQUIRED_FLAGS " -msse2 ${VXL_SSE_TEST_FLAG_BACKUP} ") + PERFORM_CMAKE_TEST_RUN(vxl_platform_tests.cxx VXL_SSE2_HARDWARE_SUPPORT_POSSIBLE) + SET( VXL_SSE2_HARDWARE_SUPPORT_POSSIBLE_HELP + "The current compiler flags do not allow the SSE2 instructions to be used. " + "It looks like if you add the flag '-msse2' you will be able to use the " + "SSE2 instructions. If you chose to set VNL_CONFIG_ENABLE_SSE or " + "VNL_CONFIG_ENABLE_SSE2_ROUNDING to ON, cmake will put this flag for you. " + "You can also add this flag yourself. If you still see this message, after " + "the flag change, you may need to set VXL_UPDATE_CONFIGURATION to ON and " + "rerun cmake." + CACHE INTERNAL "help string for how to enable SSE2 support" ) + SET(CMAKE_REQUIRED_FLAGS ${VXL_SSE_TEST_FLAG_BACKUP}) + ENDIF(CMAKE_COMPILER_IS_GNUCXX) +ENDIF(NOT VXL_HAS_SSE2_HARDWARE_SUPPORT) + + # # Check for aligned dynamic memory allocation support, useful for sse # @@ -196,16 +220,6 @@ PERFORM_CMAKE_TEST(vxl_platform_tests.cxx VXL_HAS_ALIGNED_MALLOC) PERFORM_CMAKE_TEST(vxl_platform_tests.cxx VXL_HAS_MINGW_ALIGNED_MALLOC) PERFORM_CMAKE_TEST(vxl_platform_tests.cxx VXL_HAS_POSIX_MEMALIGN) - - # check for hardware support for sse2 - IF(CMAKE_COMPILER_IS_GNUCXX) - SET(VXL_SSE_TEST_FLAG_BACKUP ${CMAKE_REQUIRED_FLAGS}) - SET(CMAKE_REQUIRED_FLAGS " -msse2 ${VXL_SSE_TEST_FLAG_BACKUP} ") - PERFORM_CMAKE_TEST_RUN(vxl_platform_tests.cxx VXL_HAS_SSE2_HARDWARE_SUPPORT) - SET(CMAKE_REQUIRED_FLAGS ${VXL_SSE_TEST_FLAG_BACKUP}) - ELSE(CMAKE_COMPILER_IS_GNUCXX) - PERFORM_CMAKE_TEST_RUN(vxl_platform_tests.cxx VXL_HAS_SSE2_HARDWARE_SUPPORT) - ENDIF(CMAKE_COMPILER_IS_GNUCXX) ELSE(VXL_HAS_EMMINTRIN_H) SET( VXL_HAS_MM_MALLOC 0 ) SET( VXL_HAS_ALIGNED_MALLOC 0 ) Index: Utilities/vxl/config/cmake/config/vxl_platform_tests.cxx =================================================================== RCS file: /cvsroot/Insight/Insight/Utilities/vxl/config/cmake/config/vxl_platform_tests.cxx,v retrieving revision 1.9 diff -u -r1.9 vxl_platform_tests.cxx --- Utilities/vxl/config/cmake/config/vxl_platform_tests.cxx 13 Nov 2007 14:56:52 -0000 1.9 +++ Utilities/vxl/config/cmake/config/vxl_platform_tests.cxx 15 May 2009 16:45:24 -0000 @@ -1174,7 +1174,7 @@ //------------------------------------- -#ifdef VXL_HAS_SSE2_HARDWARE_SUPPORT +#if defined(VXL_HAS_SSE2_HARDWARE_SUPPORT) || defined(VXL_SSE2_HARDWARE_SUPPORT_POSSIBLE) #include <emmintrin.h> int main() { @@ -1182,12 +1182,12 @@ double d_a[] = { 6.75, 3.42 }; double d_b[] = { 2.3, 9.2 }; double res[2] = {0.0}; - + __m128d z; z = _mm_mul_pd(_mm_loadu_pd(d_a),_mm_loadu_pd(d_b)); - + _mm_storeu_pd(res,z); - + return 0; } #endif Index: Utilities/vxl/core/vnl/CMakeLists.txt =================================================================== RCS file: /cvsroot/Insight/Insight/Utilities/vxl/core/vnl/CMakeLists.txt,v retrieving revision 1.15 diff -u -r1.15 CMakeLists.txt --- Utilities/vxl/core/vnl/CMakeLists.txt 21 Nov 2007 20:24:34 -0000 1.15 +++ Utilities/vxl/core/vnl/CMakeLists.txt 15 May 2009 16:45:24 -0000 @@ -8,19 +8,40 @@ OPTION(VNL_CONFIG_THREAD_SAFE "Whether thread-safe vnl implementations are used." ON) - + #IF( VXL_HAS_EMMINTRIN_H AND VXL_HAS_SSE2_HARDWARE_SUPPORT ) # OPTION(VNL_CONFIG_ENABLE_SSE2 # "Enable Streaming SIMD Extensions 2 optimisations (hardware dependant)." ON) #ELSE ( VXL_HAS_EMMINTRIN_H AND VXL_HAS_SSE2_HARDWARE_SUPPORT ) OPTION(VNL_CONFIG_ENABLE_SSE2 - "Enable Streaming SIMD Extensions 2 optimisations (hardware dependant)." OFF) + "Enable Streaming SIMD Extensions 2 optimisations (hardware dependant). Currently broken. For use by VNL developers only." OFF) #ENDIF( VXL_HAS_EMMINTRIN_H AND VXL_HAS_SSE2_HARDWARE_SUPPORT ) +OPTION(VNL_CONFIG_ENABLE_SSE2_ROUNDING + "Enable Streaming SIMD Extensions 2 implementation of rounding (hardware dependant)." + ${VXL_HAS_SSE2_HARDWARE_SUPPORT} ) +IF( VNL_CONFIG_ENABLE_SSE2_ROUNDING ) + IF( NOT VXL_HAS_SSE2_HARDWARE_SUPPORT ) + IF( VXL_SSE2_HARDWARE_SUPPORT_POSSIBLE ) + MESSAGE( ${VXL_SSE2_HARDWARE_SUPPORT_POSSIBLE_HELP} ) + # Reset the update configuration flag + SET( VXL_UPDATE_CONFIGURATION "ON" CACHE BOOL "Re-run the configuration tests?" FORCE ) + MESSAGE( SEND_ERROR "VXL_UPDATE_CONFIGURATION has been forced to ON. " + "Please rerun the cmake configure step" ) + ELSE( VXL_SSE2_HARDWARE_SUPPORT_POSSIBLE ) + MESSAGE( SEND_ERROR "Cannot have VNL_CONFIG_ENABLE_SSE2_ROUNDING because" + " there is no SSE2 hardware support" ) + SET(VNL_CONFIG_ENABLE_SSE2_ROUNDING 0) + ENDIF( VXL_SSE2_HARDWARE_SUPPORT_POSSIBLE ) + ENDIF( NOT VXL_HAS_SSE2_HARDWARE_SUPPORT ) +ENDIF( VNL_CONFIG_ENABLE_SSE2_ROUNDING ) + + MARK_AS_ADVANCED( VNL_CONFIG_CHECK_BOUNDS VNL_CONFIG_LEGACY_METHODS VNL_CONFIG_THREAD_SAFE + VNL_CONFIG_ENABLE_SSE2_ROUNDING VNL_CONFIG_ENABLE_SSE2 ) # Need to enforce 1/0 values for configuration. @@ -44,6 +65,11 @@ ELSE(VNL_CONFIG_ENABLE_SSE2) SET(VNL_CONFIG_ENABLE_SSE2 0) ENDIF(VNL_CONFIG_ENABLE_SSE2) +IF(VNL_CONFIG_ENABLE_SSE2_ROUNDING) + SET(VNL_CONFIG_ENABLE_SSE2_ROUNDING 1) +ELSE(VNL_CONFIG_ENABLE_SSE2_ROUNDING) + SET(VNL_CONFIG_ENABLE_SSE2_ROUNDING 0) +ENDIF(VNL_CONFIG_ENABLE_SSE2_ROUNDING) CONFIGURE_FILE(${vxl_SOURCE_DIR}/core/vnl/vnl_config.h.in ${vxl_BINARY_DIR}/core/vnl/vnl_config.h @ONLY IMMEDIATE) @@ -210,10 +236,6 @@ SET_SOURCE_FILES_PROPERTIES(Templates/vnl_matrix_fixed+vnl_bignum.3.3-.cxx PROPERTIES COMPILE_FLAGS -O0) SET_SOURCE_FILES_PROPERTIES(Templates/vnl_vector+vnl_rational-.cxx PROPERTIES COMPILE_FLAGS -O0) SET_SOURCE_FILES_PROPERTIES(Templates/vnl_vector_fixed+vnl_rational.3-.cxx PROPERTIES COMPILE_FLAGS -O0) - # gcc must have -msse2 option to enable sse2 support - IF(VNL_CONFIG_ENABLE_SSE2) - ADD_DEFINITIONS( -msse2 ) - ENDIF(VNL_CONFIG_ENABLE_SSE2) ENDIF(CMAKE_COMPILER_IS_GNUCXX) ADD_LIBRARY(itkvnl ${vnl_sources}) Index: Utilities/vxl/core/vnl/vnl_config.h.in =================================================================== RCS file: /cvsroot/Insight/Insight/Utilities/vxl/core/vnl/vnl_config.h.in,v retrieving revision 1.3 diff -u -r1.3 vnl_config.h.in --- Utilities/vxl/core/vnl/vnl_config.h.in 13 Nov 2007 14:56:52 -0000 1.3 +++ Utilities/vxl/core/vnl/vnl_config.h.in 15 May 2009 16:45:24 -0000 @@ -19,4 +19,7 @@ //: Set to 0 if you don't have SSE2 support on your target platform #define VNL_CONFIG_ENABLE_SSE2 @VNL_CONFIG_ENABLE_SSE2@ +//: Set to 0 if you don't want to use SSE2 instructions to implement rounding, floor, and ceil functions. +#define VNL_CONFIG_ENABLE_SSE2_ROUNDING @VNL_CONFIG_ENABLE_SSE2_ROUNDING@ + #endif Index: Utilities/vxl/core/vnl/vnl_math.h =================================================================== RCS file: /cvsroot/Insight/Insight/Utilities/vxl/core/vnl/vnl_math.h,v retrieving revision 1.7 diff -u -r1.7 vnl_math.h --- Utilities/vxl/core/vnl/vnl_math.h 22 Aug 2007 17:47:43 -0000 1.7 +++ Utilities/vxl/core/vnl/vnl_math.h 15 May 2009 16:45:24 -0000 @@ -5,39 +5,66 @@ #pragma interface #endif //: -// \file -// \brief Namespace with standard math functions +// \file +// \brief Namespace with standard math functions // -// The vnl_math namespace provides a standard set of the simple mathematical -// functions (min, max, sqr, sgn, rnd, abs), and some predefined constants -// such as pi and e, which are not defined by the ANSI C++ standard. +// The vnl_math namespace provides a standard set of the simple mathematical +// functions (min, max, sqr, sgn, rnd, abs), and some predefined constants +// such as pi and e, which are not defined by the ANSI C++ standard. // -// There are complex versions defined in vnl_complex.h +// There are complex versions defined in vnl_complex.h // -// That's right, M_PI is nonstandard! +// That's right, M_PI is nonstandard! // -// Aside from e, pi and their associates the class also defines eps, -// the IEEE double machine precision. This is the smallest number -// eps such that 1+eps != 1. +// Aside from e, pi and their associates the class also defines eps, +// the IEEE double machine precision. This is the smallest number +// eps such that 1+eps != 1. // -// The operations are overloaded for int, float and double arguments, -// which in combination with inlining can make them more efficient than -// their counterparts in the standard C library. +// The operations are overloaded for int, float and double arguments, +// which in combination with inlining can make them more efficient than +// their counterparts in the standard C library. // -// \author Andrew W. Fitzgibbon, Oxford RRG -// \date July 13, 1996 +// \author Andrew W. Fitzgibbon, Oxford RRG +// \date July 13, 1996 // // \verbatim // Modifications -// 210598 AWF Removed conditional VCL_IMPLEMENT_STATIC_CONSTS, sometimes gcc needs them. -// LSB (Modifications) 23/1/01 Documentation tidied -// Peter Vanroose - 7 Sept. 2002 - maxdouble etc. replaced by vnl_numeric_traits<T>::maxval +// 21 May 1998 AWF Removed conditional VCL_IMPLEMENT_STATIC_CONSTS, sometimes gcc needs them. +// LSB (Modifications) 23 Jan 2001 Documentation tidied +// Peter Vanroose - 7 Sep 2002 - maxdouble etc. replaced by vnl_numeric_traits<T>::maxval // Amitha Perera - 13 Sep 2002 - make constant initialization standards compliant. // \endverbatim #include <vcl_cmath.h> #include "dll.h" -#include <vxl_config.h> // for VXL_C_MATH_HAS_LROUND +#include <vxl_config.h> +#include <vnl/vnl_config.h> // for VNL_CONFIG_ENABLE_SSE2_ROUNDING +#ifdef VNL_CHECK_FPU_ROUNDING_MODE +# include <vcl_cassert.h> +#endif + +// Figure out when the fast implementation can be used +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING +# if !VXL_HAS_EMMINTRIN_H +# error "Required file emmintrin.h for SSE2 not found" +# else +# include <emmintrin.h> // sse 2 intrinsics +# endif +#endif +// Turn on fast impl when using GCC on Intel-based machines with the following exception: +// PPC with Mac OS X +#if defined(__GNUC__) && (!defined(__APPLE__) || !defined(__ppc__) ) +# define GCC_USE_FAST_IMPL 1 +#else +# define GCC_USE_FAST_IMPL 0 +#endif +// Turn on fast impl when using msvc on 32 bits windows +#if defined(VCL_VC) && !defined(_WIN64) +# define VC_USE_FAST_IMPL 1 +#else +# define VC_USE_FAST_IMPL 0 +#endif + //: Type-accessible infinities for use in templates. template <class T> T vnl_huge_val(T); @@ -53,19 +80,20 @@ { public: //: pi, e and all that - static VNL_DLL_DATA const double e VCL_STATIC_CONST_INIT_FLOAT_DECL(2.7182818284590452354); - static VNL_DLL_DATA const double log2e VCL_STATIC_CONST_INIT_FLOAT_DECL(1.4426950408889634074); - static VNL_DLL_DATA const double log10e VCL_STATIC_CONST_INIT_FLOAT_DECL(0.43429448190325182765); - static VNL_DLL_DATA const double ln2 VCL_STATIC_CONST_INIT_FLOAT_DECL(0.69314718055994530942); - static VNL_DLL_DATA const double ln10 VCL_STATIC_CONST_INIT_FLOAT_DECL(2.30258509299404568402); - static VNL_DLL_DATA const double pi VCL_STATIC_CONST_INIT_FLOAT_DECL(3.14159265358979323846); - static VNL_DLL_DATA const double pi_over_2 VCL_STATIC_CONST_INIT_FLOAT_DECL(1.57079632679489661923); - static VNL_DLL_DATA const double pi_over_4 VCL_STATIC_CONST_INIT_FLOAT_DECL(0.78539816339744830962); - static VNL_DLL_DATA const double one_over_pi VCL_STATIC_CONST_INIT_FLOAT_DECL(0.31830988618379067154); - static VNL_DLL_DATA const double two_over_pi VCL_STATIC_CONST_INIT_FLOAT_DECL(0.63661977236758134308); - static VNL_DLL_DATA const double two_over_sqrtpi VCL_STATIC_CONST_INIT_FLOAT_DECL(1.12837916709551257390); - static VNL_DLL_DATA const double sqrt2 VCL_STATIC_CONST_INIT_FLOAT_DECL(1.41421356237309504880); - static VNL_DLL_DATA const double sqrt1_2 VCL_STATIC_CONST_INIT_FLOAT_DECL(0.70710678118654752440); + static VNL_DLL_DATA const double e VCL_STATIC_CONST_INIT_FLOAT_DECL(2.7182818284590452354); + static VNL_DLL_DATA const double log2e VCL_STATIC_CONST_INIT_FLOAT_DECL(1.4426950408889634074); + static VNL_DLL_DATA const double log10e VCL_STATIC_CONST_INIT_FLOAT_DECL(0.43429448190325182765); + static VNL_DLL_DATA const double ln2 VCL_STATIC_CONST_INIT_FLOAT_DECL(0.69314718055994530942); + static VNL_DLL_DATA const double ln10 VCL_STATIC_CONST_INIT_FLOAT_DECL(2.30258509299404568402); + static VNL_DLL_DATA const double pi VCL_STATIC_CONST_INIT_FLOAT_DECL(3.14159265358979323846); + static VNL_DLL_DATA const double pi_over_2 VCL_STATIC_CONST_INIT_FLOAT_DECL(1.57079632679489661923); + static VNL_DLL_DATA const double pi_over_4 VCL_STATIC_CONST_INIT_FLOAT_DECL(0.78539816339744830962); + static VNL_DLL_DATA const double one_over_pi VCL_STATIC_CONST_INIT_FLOAT_DECL(0.31830988618379067154); + static VNL_DLL_DATA const double two_over_pi VCL_STATIC_CONST_INIT_FLOAT_DECL(0.63661977236758134308); + static VNL_DLL_DATA const double two_over_sqrtpi VCL_STATIC_CONST_INIT_FLOAT_DECL(1.12837916709551257390); + static VNL_DLL_DATA const double one_over_sqrt2pi VCL_STATIC_CONST_INIT_FLOAT_DECL(0.39894228040143267794); + static VNL_DLL_DATA const double sqrt2 VCL_STATIC_CONST_INIT_FLOAT_DECL(1.41421356237309504880); + static VNL_DLL_DATA const double sqrt1_2 VCL_STATIC_CONST_INIT_FLOAT_DECL(0.70710678118654752440); //: IEEE double machine precision static VNL_DLL_DATA const double eps VCL_STATIC_CONST_INIT_FLOAT_DECL(2.2204460492503131e-16); @@ -140,50 +168,353 @@ template <class T> bool vnl_math_isfinite(T); #endif -// rnd (rounding; 0.5 rounds up) -#if VXL_C_MATH_HAS_LROUND -// Use C99 functions, which GCC implements as an intrinsic -// Or in simpler terms - is at least 3 times faster. -inline int vnl_math_rnd(float x) { return static_cast<int>(lroundf(x)); } -inline int vnl_math_rnd(double x) { return static_cast<int>(lround(x)); } -#elif defined (VCL_VC) && !defined(__GCCXML__) && !defined(_WIN64) -// Use assembly inline function from -// http://mega-nerd.com/FPcast/ -// - - // Win32 doesn't seem to have these functions. - // Therefore implement inline versions of these functions here. -// NB But Win64 does not support the non-standard _asm - __inline int - vnl_math_rnd (double flt) - { int intgr; - _asm - { fld flt - fistp intgr - } ; - return intgr ; - } - - __inline int - vnl_math_rnd (float flt) - { int intgr; - _asm - { fld flt - fistp intgr - } ; - return intgr; - } -#else -inline int vnl_math_rnd(float x) { return (x>=0.0)?(int)(x + 0.5):(int)(x - 0.5); } -inline int vnl_math_rnd(double x) { return (x>=0.0)?(int)(x + 0.5):(int)(x - 0.5); } + + +// vnl_math_rnd_halfinttoeven -- round towards nearest integer +// halfway cases are rounded towards the nearest even integer, e.g. +// vnl_math_rnd_halfinttoeven( 1.5) == 2 +// vnl_math_rnd_halfinttoeven(-1.5) == -2 +// vnl_math_rnd_halfinttoeven( 2.5) == 2 +// vnl_math_rnd_halfinttoeven( 3.5) == 4 +// +// We assume that the rounding mode is not changed from the default +// one (or at least that it is always restored to the default one). + +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING // Fast sse2 implementation + +inline int vnl_math_rnd_halfinttoeven(float x) +{ +# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) + assert(fegetround()==FE_TONEAREST); +# endif + return _mm_cvtss_si32(_mm_set_ss(x)); +} +inline int vnl_math_rnd_halfinttoeven(double x) +{ +# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) + assert(fegetround()==FE_TONEAREST); +# endif + return _mm_cvtsd_si32(_mm_set_sd(x)); +} + +#elif GCC_USE_FAST_IMPL // Fast gcc asm implementation + +inline int vnl_math_rnd_halfinttoeven(float x) +{ +# ifdef VNL_CHECK_FPU_ROUNDING_MODE + assert(fegetround()==FE_TONEAREST); +# endif + int r; + __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); + return r; +} +inline int vnl_math_rnd_halfinttoeven(double x) +{ +# ifdef VNL_CHECK_FPU_ROUNDING_MODE + assert(fegetround()==FE_TONEAREST); +# endif + int r; + __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); + return r; +} + +#elif VC_USE_FAST_IMPL // Fast msvc asm implementation + +inline int vnl_math_rnd_halfinttoeven(float x) +{ + int r; + __asm { + fld x + fistp r + } + return r; +} +inline int vnl_math_rnd_halfinttoeven(double x) +{ + int r; + __asm { + fld x + fistp r + } + return r; +} + +#else // Vanilla implementation + +inline int vnl_math_rnd_halfinttoeven(float x) +{ + if (x>=0.f) + { + x+=0.5f; + const int r = static_cast<int>(x); + if ( x != static_cast<float>(r) ) return r; + return 2*(r/2); + } + else + { + x-=0.5f; + const int r = static_cast<int>(x); + if ( x != static_cast<float>(r) ) return r; + return 2*(r/2); + } +} +inline int vnl_math_rnd_halfinttoeven(double x) +{ + if (x>=0.) + { + x+=0.5; + const int r = static_cast<int>(x); + if ( x != static_cast<double>(r) ) return r; + return 2*(r/2); + } + else + { + x-=0.5; + const int r = static_cast<int>(x); + if ( x != static_cast<double>(r) ) return r; + return 2*(r/2); + } +} + +#endif + + + +// vnl_math_rnd_halfintup -- round towards nearest integer +// halfway cases are rounded upward, e.g. +// vnl_math_rnd_halfintup( 1.5) == 2 +// vnl_math_rnd_halfintup(-1.5) == -1 +// vnl_math_rnd_halfintup( 2.5) == 3 +// +// Be careful: argument absolute value must be less than INT_MAX/2 +// for vnl_math_rnd_halfintup to be guaranteed to work. +// We also assume that the rounding mode is not changed from the default +// one (or at least that it is always restored to the default one). + +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING || GCC_USE_FAST_IMPL || VC_USE_FAST_IMPL + +inline int vnl_math_rnd_halfintup(float x) { return vnl_math_rnd_halfinttoeven(2*x+0.5f)>>1; } +inline int vnl_math_rnd_halfintup(double x) { return vnl_math_rnd_halfinttoeven(2*x+0.5)>>1; } + +#else // Vanilla implementation + +inline int vnl_math_rnd_halfintup(float x) +{ + x+=0.5f; + return static_cast<int>(x>=0.f?x:(x==static_cast<int>(x)?x:x-1.f)); +} +inline int vnl_math_rnd_halfintup(double x) +{ + x+=0.5; + return static_cast<int>(x>=0.?x:(x==static_cast<int>(x)?x:x-1.)); +} + +#endif + + + +// vnl_math_rnd -- round towards nearest integer +// halfway cases such as 0.5 may be rounded either up or down +// so as to maximize the efficiency, e.g. +// vnl_math_rnd_halfinttoeven( 1.5) == 1 or 2 +// vnl_math_rnd_halfinttoeven(-1.5) == -2 or -1 +// vnl_math_rnd_halfinttoeven( 2.5) == 2 or 3 +// vnl_math_rnd_halfinttoeven( 3.5) == 3 or 4 +// +// We assume that the rounding mode is not changed from the default +// one (or at least that it is always restored to the default one). + +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING || GCC_USE_FAST_IMPL || VC_USE_FAST_IMPL + +inline int vnl_math_rnd(float x) { return vnl_math_rnd_halfinttoeven(x); } +inline int vnl_math_rnd(double x) { return vnl_math_rnd_halfinttoeven(x); } + +#else // Vanilla implementation + +inline int vnl_math_rnd(float x) { return x>=0.f?static_cast<int>(x+.5f):static_cast<int>(x-.5f); } +inline int vnl_math_rnd(double x) { return x>=0.0?static_cast<int>(x+0.5):static_cast<int>(x-0.5); } + + +#endif + + + +// vnl_math_floor -- round towards minus infinity +// +// Be careful: argument absolute value must be less than INT_MAX/2 +// for vnl_math_floor to be guaranteed to work. +// We also assume that the rounding mode is not changed from the default +// one (or at least that it is always restored to the default one). + +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING // Fast sse2 implementation + +inline int vnl_math_floor(float x) +{ +# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) + assert(fegetround()==FE_TONEAREST); +# endif + return _mm_cvtss_si32(_mm_set_ss(2*x-.5f))>>1; +} +inline int vnl_math_floor(double x) +{ +# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) + assert(fegetround()==FE_TONEAREST); +# endif + return _mm_cvtsd_si32(_mm_set_sd(2*x-.5))>>1; +} + +#elif GCC_USE_FAST_IMPL // Fast gcc asm implementation + +inline int vnl_math_floor(float x) +{ +# ifdef VNL_CHECK_FPU_ROUNDING_MODE + assert(fegetround()==FE_TONEAREST); +# endif + int r; + x = 2*x-.5f; + __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); + return r>>1; +} +inline int vnl_math_floor(double x) +{ +# ifdef VNL_CHECK_FPU_ROUNDING_MODE + assert(fegetround()==FE_TONEAREST); +# endif + int r; + x = 2*x-.5; + __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); + return r>>1; +} + +#elif VC_USE_FAST_IMPL // Fast msvc asm implementation + +inline int vnl_math_floor(float x) +{ + int r; + x = 2*x-.5f; + __asm { + fld x + fistp r + } + return r>>1; +} +inline int vnl_math_floor(double x) +{ + int r; + x = 2*x-.5; + __asm { + fld x + fistp r + } + return r>>1; +} + +#else // Vanilla implementation + +inline int vnl_math_floor(float x) +{ + return static_cast<int>(x>=0.f?x:(x==static_cast<int>(x)?x:x-1.f)); +} +inline int vnl_math_floor(double x) +{ + return static_cast<int>(x>=0.0?x:(x==static_cast<int>(x)?x:x-1.0)); +} + #endif + + +// vnl_math_ceil -- round towards plus infinity +// +// Be careful: argument absolute value must be less than INT_MAX/2 +// for vnl_math_ceil to be guaranteed to work. +// We also assume that the rounding mode is not changed from the default +// one (or at least that it is always restored to the default one). + +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING // Fast sse2 implementation + +inline int vnl_math_ceil(float x) +{ +# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) + assert(fegetround()==FE_TONEAREST); +# endif + return -(_mm_cvtss_si32(_mm_set_ss(-.5f-2*x))>>1); +} +inline int vnl_math_ceil(double x) +{ +# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) + assert(fegetround()==FE_TONEAREST); +# endif + return -(_mm_cvtsd_si32(_mm_set_sd(-.5-2*x))>>1); +} + +#elif GCC_USE_FAST_IMPL // Fast gcc asm implementation + +inline int vnl_math_ceil(float x) +{ +# ifdef VNL_CHECK_FPU_ROUNDING_MODE + assert(fegetround()==FE_TONEAREST); +# endif + int r; + x = -.5f-2*x; + __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); + return -(r>>1); +} +inline int vnl_math_ceil(double x) +{ +# ifdef VNL_CHECK_FPU_ROUNDING_MODE + assert(fegetround()==FE_TONEAREST); +# endif + int r; + x = -.5-2*x; + __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); + return -(r>>1); +} + +#elif VC_USE_FAST_IMPL // Fast msvc asm implementation + +inline int vnl_math_ceil(float x) +{ + int r; + x = -.5f-2*x; + __asm { + fld x + fistp r + } + return -(r>>1); +} +inline int vnl_math_ceil(double x) +{ + int r; + x = -.5-2*x; + __asm { + fld x + fistp r + } + return -(r>>1); +} + +#else // Vanilla implementation + +inline int vnl_math_ceil(float x) +{ + return static_cast<int>(x<0.f?x:(x==static_cast<int>(x)?x:x+1.f)); +} +inline int vnl_math_ceil(double x) +{ + return static_cast<int>(x<0.0?x:(x==static_cast<int>(x)?x:x+1.0)); +} + +#endif + + + // abs inline bool vnl_math_abs(bool x) { return x; } inline unsigned char vnl_math_abs(unsigned char x) { return x; } -inline unsigned char vnl_math_abs(signed char x) { return x < 0 ? -x : x; } -inline unsigned char vnl_math_abs(char x) { return (unsigned char)x; } -inline unsigned short vnl_math_abs(short x) { return x < 0 ? -x : x; } +inline unsigned char vnl_math_abs(signed char x) { return x < 0 ? static_cast<unsigned char>(-x) : x; } +inline unsigned char vnl_math_abs(char x) { return static_cast<unsigned char>(x); } +inline unsigned short vnl_math_abs(short x) { return x < 0 ? static_cast<unsigned short>(-x) : x; } inline unsigned short vnl_math_abs(unsigned short x){ return x; } inline unsigned int vnl_math_abs(int x) { return x < 0 ? -x : x; } inline unsigned int vnl_math_abs(unsigned int x) { return x; } Index: Utilities/vxl/core/vnl/tests/test_math.cxx =================================================================== RCS file: /cvsroot/Insight/Insight/Utilities/vxl/core/vnl/tests/test_math.cxx,v retrieving revision 1.10 diff -u -r1.10 test_math.cxx --- Utilities/vxl/core/vnl/tests/test_math.cxx 20 Apr 2009 20:01:37 -0000 1.10 +++ Utilities/vxl/core/vnl/tests/test_math.cxx 15 May 2009 16:45:25 -0000 @@ -68,22 +68,135 @@ testlib_test_assert_near("exp(d*i) ~= -1", vnl_math_abs(e_ipi+1.0), 0); vcl_cout << vcl_endl; - testlib_test_assert("rnd(-8.4999) == -8", vnl_math_rnd(-8.4999) == -8); - testlib_test_assert("rnd(-8.4999f) == -8", vnl_math_rnd(-8.4999f) == -8); - vcl_cout << "vnl_math_rnd(-8.50) == " << vnl_math_rnd(-8.50) << vcl_endl; - testlib_test_assert("rnd(-8.50) == -8/9", vnl_math_rnd(-8.50)/2 == -4); - testlib_test_assert("rnd(-8.50f) == -8/9", vnl_math_rnd(-8.50f)/2 == -4); - vcl_cout << "vnl_math_rnd(-8.5001) == " << vnl_math_rnd(-8.5001) << vcl_endl; - testlib_test_assert("rnd(-8.5001) == -9", vnl_math_rnd(-8.5001) == -9); - testlib_test_assert("rnd(-8.5001f) == -9", vnl_math_rnd(-8.5001f) == -9); - testlib_test_assert("rnd(8.4999) == 8", vnl_math_rnd(8.4999) == 8); - testlib_test_assert("rnd(8.4999f) == 8", vnl_math_rnd(8.4999f) == 8); - testlib_test_assert("rnd(8.50) == 8/9", vnl_math_rnd(8.50)/2 == 4); - vcl_cout << "vnl_math_rnd(8.50) == " << vnl_math_rnd(8.50) << vcl_endl; - testlib_test_assert("rnd(8.50f) == 8/9", vnl_math_rnd(8.50f)/2 == 4); - vcl_cout << "vnl_math_rnd(8.5001) == " << vnl_math_rnd(8.5001) << vcl_endl; - testlib_test_assert("rnd(8.5001) == 9", vnl_math_rnd(8.5001) == 9); - testlib_test_assert("rnd(8.5001f) == 9", vnl_math_rnd(8.5001f) == 9); + testlib_test_assert("rnd(-8.4999) == -8 ", vnl_math_rnd(-8.4999) == -8); + testlib_test_assert("rnd(-8.4999f) == -8 ", vnl_math_rnd(-8.4999f) == -8); + testlib_test_assert("rnd(-8.50) == -8/9", vnl_math_rnd(-8.50)/2 == -4); + testlib_test_assert("rnd(-8.50f) == -8/9", vnl_math_rnd(-8.50f)/2 == -4); + testlib_test_assert("rnd(-8.5001) == -9 ", vnl_math_rnd(-8.5001) == -9); + testlib_test_assert("rnd(-8.5001f) == -9 ", vnl_math_rnd(-8.5001f) == -9); + testlib_test_assert("rnd(8.4999) == 8 ", vnl_math_rnd(8.4999) == 8); + testlib_test_assert("rnd(8.4999f) == 8 ", vnl_math_rnd(8.4999f) == 8); + testlib_test_assert("rnd(8.50) == 8/9", vnl_math_rnd(8.50)/2 == 4); + testlib_test_assert("rnd(8.50f) == 8/9", vnl_math_rnd(8.50f)/2 == 4); + testlib_test_assert("rnd(8.5001) == 9 ", vnl_math_rnd(8.5001) == 9); + testlib_test_assert("rnd(8.5001f) == 9 ", vnl_math_rnd(8.5001f) == 9); + + testlib_test_assert("rnd(-9.4999) == -9 ", vnl_math_rnd(-9.4999) == -9); + testlib_test_assert("rnd(-9.4999f) == -9 ", vnl_math_rnd(-9.4999f) == -9); + testlib_test_assert("rnd(-9.50) == -9/10", (vnl_math_rnd(-9.50)+1)/2 == -4); + testlib_test_assert("rnd(-9.50f) == -9/10", (vnl_math_rnd(-9.50f)+1)/2 == -4); + testlib_test_assert("rnd(-9.5001) == -10 ", vnl_math_rnd(-9.5001) == -10); + testlib_test_assert("rnd(-9.5001f) == -10 ", vnl_math_rnd(-9.5001f) == -10); + testlib_test_assert("rnd(9.4999) == 9 ", vnl_math_rnd(9.4999) == 9); + testlib_test_assert("rnd(9.4999f) == 9 ", vnl_math_rnd(9.4999f) == 9); + testlib_test_assert("rnd(9.50) == 9/10", (vnl_math_rnd(9.50)-1)/2 == 4); + testlib_test_assert("rnd(9.50f) == 9/10", (vnl_math_rnd(9.50f)-1)/2 == 4); + testlib_test_assert("rnd(9.5001) == 10 ", vnl_math_rnd(9.5001) == 10); + testlib_test_assert("rnd(9.5001f) == 10 ", vnl_math_rnd(9.5001f) == 10); + + testlib_test_assert("rnd_halfinttoeven(-8.4999) == -8", vnl_math_rnd_halfinttoeven(-8.4999) == -8); + testlib_test_assert("rnd_halfinttoeven(-8.4999f) == -8", vnl_math_rnd_halfinttoeven(-8.4999f)== -8); + testlib_test_assert("rnd_halfinttoeven(-8.50) == -8", vnl_math_rnd_halfinttoeven(-8.50) == -8); + testlib_test_assert("rnd_halfinttoeven(-8.50f) == -8", vnl_math_rnd_halfinttoeven(-8.50f) == -8); + testlib_test_assert("rnd_halfinttoeven(-8.5001) == -9", vnl_math_rnd_halfinttoeven(-8.5001) == -9); + testlib_test_assert("rnd_halfinttoeven(-8.5001f) == -9", vnl_math_rnd_halfinttoeven(-8.5001f)== -9); + testlib_test_assert("rnd_halfinttoeven(8.4999) == 8", vnl_math_rnd_halfinttoeven(8.4999) == 8); + testlib_test_assert("rnd_halfinttoeven(8.4999f) == 8", vnl_math_rnd_halfinttoeven(8.4999f)== 8); + testlib_test_assert("rnd_halfinttoeven(8.50) == 9", vnl_math_rnd_halfinttoeven(8.50) == 8); + testlib_test_assert("rnd_halfinttoeven(8.50f) == 9", vnl_math_rnd_halfinttoeven(8.50f) == 8); + testlib_test_assert("rnd_halfinttoeven(8.5001) == 9", vnl_math_rnd_halfinttoeven(8.5001) == 9); + testlib_test_assert("rnd_halfinttoeven(8.5001f) == 9", vnl_math_rnd_halfinttoeven(8.5001f)== 9); + + testlib_test_assert("rnd_halfinttoeven(-9.4999) == -9 ", vnl_math_rnd_halfinttoeven(-9.4999) == -9); + testlib_test_assert("rnd_halfinttoeven(-9.4999f) == -9 ", vnl_math_rnd_halfinttoeven(-9.4999f)== -9); + testlib_test_assert("rnd_halfinttoeven(-9.50) == -9 ", vnl_math_rnd_halfinttoeven(-9.50) == -10); + testlib_test_assert("rnd_halfinttoeven(-9.50f) == -9 ", vnl_math_rnd_halfinttoeven(-9.50f) == -10); + testlib_test_assert("rnd_halfinttoeven(-9.5001) == -10", vnl_math_rnd_halfinttoeven(-9.5001) == -10); + testlib_test_assert("rnd_halfinttoeven(-9.5001f) == -10", vnl_math_rnd_halfinttoeven(-9.5001f)== -10); + testlib_test_assert("rnd_halfinttoeven(9.4999) == 9 ", vnl_math_rnd_halfinttoeven(9.4999) == 9); + testlib_test_assert("rnd_halfinttoeven(9.4999f) == 9 ", vnl_math_rnd_halfinttoeven(9.4999f)== 9); + testlib_test_assert("rnd_halfinttoeven(9.50) == 10", vnl_math_rnd_halfinttoeven(9.50) == 10); + testlib_test_assert("rnd_halfinttoeven(9.50f) == 10", vnl_math_rnd_halfinttoeven(9.50f) == 10); + testlib_test_assert("rnd_halfinttoeven(9.5001) == 10", vnl_math_rnd_halfinttoeven(9.5001) == 10); + testlib_test_assert("rnd_halfinttoeven(9.5001f) == 10", vnl_math_rnd_halfinttoeven(9.5001f)== 10); + + testlib_test_assert("rnd_halfintup(-8.4999) == -8", vnl_math_rnd_halfintup(-8.4999) == -8); + testlib_test_assert("rnd_halfintup(-8.4999f) == -8", vnl_math_rnd_halfintup(-8.4999f)== -8); + testlib_test_assert("rnd_halfintup(-8.50) == -8", vnl_math_rnd_halfintup(-8.50) == -8); + testlib_test_assert("rnd_halfintup(-8.50f) == -8", vnl_math_rnd_halfintup(-8.50f) == -8); + testlib_test_assert("rnd_halfintup(-8.5001) == -9", vnl_math_rnd_halfintup(-8.5001) == -9); + testlib_test_assert("rnd_halfintup(-8.5001f) == -9", vnl_math_rnd_halfintup(-8.5001f)== -9); + testlib_test_assert("rnd_halfintup(8.4999) == 8", vnl_math_rnd_halfintup(8.4999) == 8); + testlib_test_assert("rnd_halfintup(8.4999f) == 8", vnl_math_rnd_halfintup(8.4999f)== 8); + testlib_test_assert("rnd_halfintup(8.50) == 9", vnl_math_rnd_halfintup(8.50) == 9); + testlib_test_assert("rnd_halfintup(8.50f) == 9", vnl_math_rnd_halfintup(8.50f) == 9); + testlib_test_assert("rnd_halfintup(8.5001) == 9", vnl_math_rnd_halfintup(8.5001) == 9); + testlib_test_assert("rnd_halfintup(8.5001f) == 9", vnl_math_rnd_halfintup(8.5001f)== 9); + + testlib_test_assert("rnd_halfintup(-9.4999) == -9 ", vnl_math_rnd_halfintup(-9.4999) == -9); + testlib_test_assert("rnd_halfintup(-9.4999f) == -9 ", vnl_math_rnd_halfintup(-9.4999f)== -9); + testlib_test_assert("rnd_halfintup(-9.50) == -9 ", vnl_math_rnd_halfintup(-9.50) == -9); + testlib_test_assert("rnd_halfintup(-9.50f) == -9 ", vnl_math_rnd_halfintup(-9.50f) == -9); + testlib_test_assert("rnd_halfintup(-9.5001) == -10", vnl_math_rnd_halfintup(-9.5001) == -10); + testlib_test_assert("rnd_halfintup(-9.5001f) == -10", vnl_math_rnd_halfintup(-9.5001f)== -10); + testlib_test_assert("rnd_halfintup(9.4999) == 9 ", vnl_math_rnd_halfintup(9.4999) == 9); + testlib_test_assert("rnd_halfintup(9.4999f) == 9 ", vnl_math_rnd_halfintup(9.4999f)== 9); + testlib_test_assert("rnd_halfintup(9.50) == 10", vnl_math_rnd_halfintup(9.50) == 10); + testlib_test_assert("rnd_halfintup(9.50f) == 10", vnl_math_rnd_halfintup(9.50f) == 10); + testlib_test_assert("rnd_halfintup(9.5001) == 10", vnl_math_rnd_halfintup(9.5001) == 10); + testlib_test_assert("rnd_halfintup(9.5001f) == 10", vnl_math_rnd_halfintup(9.5001f)== 10); + + testlib_test_assert("floor(8.0) == 8", vnl_math_floor(8.0) == 8); + testlib_test_assert("floor(8.0f) == 8", vnl_math_floor(8.0f) == 8); + testlib_test_assert("floor(8.9999) == 8", vnl_math_floor(8.9999) == 8); + testlib_test_assert("floor(8.9999f) == 8", vnl_math_floor(8.9999f) == 8); + testlib_test_assert("floor(8.0001) == 8", vnl_math_floor(8.0001) == 8); + testlib_test_assert("floor(8.0001f) == 8", vnl_math_floor(8.0001f) == 8); + testlib_test_assert("floor(-8.0) == -8", vnl_math_floor(-8.0) == -8); + testlib_test_assert("floor(-8.0f) == -8", vnl_math_floor(-8.0f) == -8); + testlib_test_assert("floor(-8.9999) == -9", vnl_math_floor(-8.9999) == -9); + testlib_test_assert("floor(-8.9999f) == -9", vnl_math_floor(-8.9999f) == -9); + testlib_test_assert("floor(-8.0001) == -9", vnl_math_floor(-8.0001) == -9); + testlib_test_assert("floor(-8.0001f) == -9", vnl_math_floor(-8.0001f) == -9); + + testlib_test_assert("floor(9.0) == 9", vnl_math_floor(9.0) == 9); + testlib_test_assert("floor(9.0f) == 9", vnl_math_floor(9.0f) == 9); + testlib_test_assert("floor(9.9999) == 9", vnl_math_floor(9.9999) == 9); + testlib_test_assert("floor(9.9999f) == 9", vnl_math_floor(9.9999f) == 9); + testlib_test_assert("floor(9.0001) == 9", vnl_math_floor(9.0001) == 9); + testlib_test_assert("floor(9.0001f) == 9", vnl_math_floor(9.0001f) == 9); + testlib_test_assert("floor(-9.0) == -9", vnl_math_floor(-9.0) == -9); + testlib_test_assert("floor(-9.0f) == -9", vnl_math_floor(-9.0f) == -9); + testlib_test_assert("floor(-9.9999) == -10", vnl_math_floor(-9.9999) == -10); + testlib_test_assert("floor(-9.9999f) == -10", vnl_math_floor(-9.9999f) == -10); + testlib_test_assert("floor(-9.0001) == -10", vnl_math_floor(-9.0001) == -10); + testlib_test_assert("floor(-9.0001f) == -10", vnl_math_floor(-9.0001f) == -10); + + testlib_test_assert("ceil(8.0) == 8", vnl_math_ceil(8.0) == 8); + testlib_test_assert("ceil(8.0f) == 8", vnl_math_ceil(8.0f) == 8); + testlib_test_assert("ceil(8.9999) == 9", vnl_math_ceil(8.9999) == 9); + testlib_test_assert("ceil(8.9999f) == 9", vnl_math_ceil(8.9999f) == 9); + testlib_test_assert("ceil(8.0001) == 9", vnl_math_ceil(8.0001) == 9); + testlib_test_assert("ceil(8.0001f) == 9", vnl_math_ceil(8.0001f) == 9); + testlib_test_assert("ceil(-8.0) == -8", vnl_math_ceil(-8.0) == -8); + testlib_test_assert("ceil(-8.0f) == -8", vnl_math_ceil(-8.0f) == -8); + testlib_test_assert("ceil(-8.9999) == -8", vnl_math_ceil(-8.9999) == -8); + testlib_test_assert("ceil(-8.9999f) == -8", vnl_math_ceil(-8.9999f) == -8); + testlib_test_assert("ceil(-8.0001) == -8", vnl_math_ceil(-8.0001) == -8); + testlib_test_assert("ceil(-8.0001f) == -8", vnl_math_ceil(-8.0001f) == -8); + + testlib_test_assert("ceil(9.0) == 9", vnl_math_ceil(9.0) == 9); + testlib_test_assert("ceil(9.0f) == 9", vnl_math_ceil(9.0f) == 9); + testlib_test_assert("ceil(9.9999) == 10", vnl_math_ceil(9.9999) == 10); + testlib_test_assert("ceil(9.9999f) == 10", vnl_math_ceil(9.9999f) == 10); + testlib_test_assert("ceil(9.0001) == 10", vnl_math_ceil(9.0001) == 10); + testlib_test_assert("ceil(9.0001f) == 10", vnl_math_ceil(9.0001f) == 10); + testlib_test_assert("ceil(-9.0) == -9", vnl_math_ceil(-9.0) == -9); + testlib_test_assert("ceil(-9.0f) == -9", vnl_math_ceil(-9.0f) == -9); + testlib_test_assert("ceil(-9.9999) == -9", vnl_math_ceil(-9.9999) == -9); + testlib_test_assert("ceil(-9.9999f) == -9", vnl_math_ceil(-9.9999f) == -9); + testlib_test_assert("ceil(-9.0001) == -9", vnl_math_ceil(-9.0001) == -9); + testlib_test_assert("ceil(-9.0001f) == -9", vnl_math_ceil(-9.0001f) == -9); testlib_test_assert(" isfinite(f) ", vnl_math_isfinite(f)); testlib_test_assert(" isfinite(d) ", vnl_math_isfinite(d)); itk-portable-round-2009-05-16.patch [^] (56,066 bytes) 2009-05-16 12:07 [Show Content] [Hide Content] Index: CMakeLists.txt =================================================================== RCS file: /cvsroot/Insight/Insight/CMakeLists.txt,v retrieving revision 1.338 diff -u -p -r1.338 CMakeLists.txt --- CMakeLists.txt 14 May 2009 02:12:55 -0000 1.338 +++ CMakeLists.txt 16 May 2009 16:02:30 -0000 @@ -490,6 +490,11 @@ IF(CMAKE_COMPILER_IS_GNUCXX) MARK_AS_ADVANCED(ITK_USE_64BITS_APPLE_TRUNCATION_WARNING) ENDIF(APPLE) + + # gcc must have -msse2 option to enable sse2 support + IF(VNL_CONFIG_ENABLE_SSE2 OR VNL_CONFIG_ENABLE_SSE2_ROUNDING) + SET(ITK_REQUIRED_CXX_FLAGS "${ITK_REQUIRED_CXX_FLAGS} -msse2") + ENDIF(VNL_CONFIG_ENABLE_SSE2 OR VNL_CONFIG_ENABLE_SSE2_ROUNDING) ENDIF(CMAKE_COMPILER_IS_GNUCXX) IF(UNIX) Index: ITKConfig.cmake.in =================================================================== RCS file: /cvsroot/Insight/Insight/ITKConfig.cmake.in,v retrieving revision 1.28 diff -u -p -r1.28 ITKConfig.cmake.in --- ITKConfig.cmake.in 8 May 2009 14:20:16 -0000 1.28 +++ ITKConfig.cmake.in 16 May 2009 16:02:30 -0000 @@ -68,3 +68,7 @@ SET(ITK_USE_ORIENTED_IMAGE_DIRECTION "@I # same for gdcm SET(ITK_VXL_DIR "@ITK_VXL_DIR@") SET(ITK_GDCM_DIR "@ITK_GDCM_DIR@") + +# Let's also export VNL_CONFIG_ENABLE_SSE2_ROUNDING as it may be requirred +# to know whether to add a -msse2 compilation flag for gcc +SET(VNL_CONFIG_ENABLE_SSE2_ROUNDING "@VNL_CONFIG_ENABLE_SSE2_ROUNDING@") Index: Code/Common/itkIndex.h =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkIndex.h,v retrieving revision 1.60 diff -u -p -r1.60 itkIndex.h --- Code/Common/itkIndex.h 7 May 2009 14:03:45 -0000 1.60 +++ Code/Common/itkIndex.h 16 May 2009 16:02:31 -0000 @@ -271,7 +271,7 @@ public: // produce consistent results. This can be removed once vnl_math_rnd is // fixed in VXL. #if (defined (VCL_VC) && !defined(__GCCXML__)) || (defined(_MSC_VER) && (_MSC_VER <= 1310)) -#define vnl_math_rnd(x) ((x>=0.0)?(int)(x + 0.5):(int)(x - 0.5)) +#define vnl_math_rnd_halfintup(x) ((x>=0.0)?(int)(x + 0.5):(int)(x - 0.5)) #endif #endif /** Copy values from a FixedArray by rounding each one of the components */ @@ -279,21 +279,21 @@ public: inline void CopyWithRound( const FixedArray<TCoordRep,VIndexDimension> & point ) { #ifdef ITK_USE_TEMPLATE_META_PROGRAMMING_LOOP_UNROLLING - itkFoorLoopRoundingAndAssignmentMacro(IndexType,ContinuousIndexType,IndexValueType,m_Index,point,VIndexDimension); + itkForLoopRoundingAndAssignmentMacro(IndexType,ContinuousIndexType,IndexValueType,m_Index,point,VIndexDimension); #else for(unsigned int i=0;i < VIndexDimension; ++i) { #ifdef ITK_USE_PORTABLE_ROUND m_Index[i] = static_cast< IndexValueType>( itk::Math::RoundHalfIntegerUp( point[i] ) ); #else - m_Index[i] = static_cast< IndexValueType>( vnl_math_rnd( point[i] ) ); + m_Index[i] = static_cast< IndexValueType>( vnl_math_rnd_halfintup( point[i] ) ); #endif } #endif } #ifndef ITK_USE_PORTABLE_ROUND #if (defined (VCL_VC) && !defined(__GCCXML__)) || (defined(_MSC_VER) && (_MSC_VER <= 1310)) -#undef vnl_math_rnd +#undef vnl_math_rnd_halfintup #endif #endif Index: Code/Common/itkMacro.h =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkMacro.h,v retrieving revision 1.93 diff -u -p -r1.93 itkMacro.h --- Code/Common/itkMacro.h 12 May 2009 14:41:39 -0000 1.93 +++ Code/Common/itkMacro.h 16 May 2009 16:02:32 -0000 @@ -39,9 +39,7 @@ #include <cassert> #endif -#ifndef ITK_USE_PORTABLE_ROUND #include "vnl/vnl_math.h" -#endif // Determine type of string stream to use. #if !defined(CMAKE_NO_ANSI_STRING_STREAM) @@ -974,194 +972,14 @@ private: namespace itk { - namespace Math { - -#ifdef ITK_USE_PORTABLE_ROUND -// RoundHalfIntegerUp -- round towards nearest integer -// halfway cases are rounded upward, e.g. -// RoundHalfIntegerUp( 1.5) == 2 -// RoundHalfIntegerUp(-1.5) == -1 -// RoundHalfIntegerUp( 2.5) == 3 -// -// Be careful: argument absolute value must be less than INT_MAX/2 -// for RoundHalfIntegerUp to be guaranteed to work. -// We also assume that the rounding mode is not changed from the default -// one (or at least that it is always restored to the default one). - -#if VNL_CONFIG_ENABLE_SSE2_ROUNDING || GCC_USE_FAST_IMPL || VC_USE_FAST_IMPL - -inline int RoundHalfIntegerUp(float x) { return RoundHalfIntegerToEven(2*x+0.5f)>>1; } -inline int RoundHalfIntegerUp(double x) { return RoundHalfIntegerToEven(2*x+0.5)>>1; } - -#else // Vanilla implementation - -inline int RoundHalfIntegerUp(float x) -{ - x += 0.5f; - return static_cast<int>(x>=0.f?x:(x==static_cast<int>(x)?x:x-1.f)); -} -inline int RoundHalfIntegerUp(double x) -{ - x += 0.5; - return static_cast<int>(x>=0.?x:(x==static_cast<int>(x)?x:x-1.)); -} - -#endif - - -// Round -- round towards nearest integer -// halfway cases such as 0.5 may be rounded either up or down -// so as to maximize the efficiency, e.g. -// RoundHalfIntegerToEven( 1.5) == 1 or 2 -// RoundHalfIntegerToEven(-1.5) == -2 or -1 -// RoundHalfIntegerToEven( 2.5) == 2 or 3 -// RoundHalfIntegerToEven( 3.5) == 3 or 4 -// -// We assume that the rounding mode is not changed from the default -// one (or at least that it is always restored to the default one). - -#if VNL_CONFIG_ENABLE_SSE2_ROUNDING || GCC_USE_FAST_IMPL || VC_USE_FAST_IMPL - -inline int Round(float x) { return RoundHalfIntegerToEven(x); } +inline int RoundHalfIntegerUp(float x) { return vnl_math_rnd_halfintup(x); } +inline int RoundHalfIntegerUp(double x) { return vnl_math_rnd_halfintup(x); } +inline int RoundHalfIntegerToEven(float x) { return vnl_math_rnd_halfinttoeven(x); } +inline int RoundHalfIntegerToEven(double x) { return vnl_math_rnd_halfinttoeven(x); } +inline int Round(float x) { return RoundHalfIntegerToEven(x); } inline int Round(double x) { return RoundHalfIntegerToEven(x); } - -#else // Vanilla implementation - -inline int Round(float x) { return x>=0.f?static_cast<int>(x+.5f):static_cast<int>(x-.5f); } -inline int Round(double x) { return x>=0.0?static_cast<int>(x+0.5):static_cast<int>(x-0.5); } - - -#endif - - -// RoundHalfIntegerToEven -- round towards nearest integer -// halfway cases are rounded towards the nearest even integer, e.g. -// RoundHalfIntegerToEven( 1.5) == 2 -// RoundHalfIntegerToEven(-1.5) == -2 -// RoundHalfIntegerToEven( 2.5) == 2 -// RoundHalfIntegerToEven( 3.5) == 4 -// -// We assume that the rounding mode is not changed from the default -// one (or at least that it is always restored to the default one). - -#if VNL_CONFIG_ENABLE_SSE2_ROUNDING // Fast sse2 implementation - -inline int RoundHalfIntegerToEven(float x) -{ -# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) - assert( fegetround() == FE_TONEAREST ); -# endif - return _mm_cvtss_si32(_mm_set_ss(x)); -} -inline int RoundHalfIntegerToEven(double x) -{ -# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) - assert( fegetround() == FE_TONEAREST ); -# endif - return _mm_cvtsd_si32(_mm_set_sd(x)); -} - -#elif GCC_USE_FAST_IMPL // Fast gcc asm implementation - -inline int RoundHalfIntegerToEven(float x) - { -# ifdef VNL_CHECK_FPU_ROUNDING_MODE - assert( fegetround() == FE_TONEAREST ); -# endif - int r; - __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); - return r; - } - -inline int RoundHalfIntegerToEven(double x) - { -# ifdef VNL_CHECK_FPU_ROUNDING_MODE - assert( fegetround() == FE_TONEAREST ); -# endif - int r; - __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); - return r; - } - -#elif VC_USE_FAST_IMPL // Fast msvc asm implementation - -inline int RoundHalfIntegerToEven(float x) - { - int r; - __asm { -@@ -218,10 +228,7 @@ - } - return r; - } - -inline int RoundHalfIntegerToEven(double x) - { - int r; - __asm { -@@ -230,59 +237,156 @@ - } - return r; - } - -#else // Vanilla implementation - -inline int RoundHalfIntegerToEven(float x) -{ - if (x>=0.f) - { - x += 0.5f; - const int r = static_cast<int>(x); - if ( x != static_cast<float>(r) ) - { - return r; - } - return 2*(r/2); - } - else - { - x -= 0.5f; - const int r = static_cast<int>(x); - if ( x != static_cast<float>(r) ) - { - return r; - } - return 2*(r/2); - } -} - -inline int RoundHalfIntegerToEven(double x) -{ - if (x >= 0.0) - { - x += 0.5; - const int r = static_cast<int>(x); - if ( x != static_cast<double>(r) ) - { - return r; - } - return 2*(r/2); - } - else - { - x -= 0.5; - const int r = static_cast<int>(x); - if ( x != static_cast<double>(r) ) - { - return r; - } - return 2*(r/2); - } -} - -#endif - -#else - // Resort to the previous vnl_math_rnd() - inline int Round(float x) { return vnl_math_rnd(x); } - inline int Round(double x) { return vnl_math_rnd(x); } -#endif } // end namespace Math } // end namespace itk @@ -1178,7 +996,7 @@ inline int RoundHalfIntegerToEven(double // No verification of size is performed. Casting is perfomed as part of the // assignment, by using the DestinationElementType as the casting type. // Source and destination array types must have defined opearator[] in their API. -#define itkFoorLoopAssignmentMacro(DestinationType,SourceType,DestinationElementType,DestinationArray,SourceArray,NumberOfIterations) \ +#define itkForLoopAssignmentMacro(DestinationType,SourceType,DestinationElementType,DestinationArray,SourceArray,NumberOfIterations) \ for(unsigned int i=0;i < NumberOfIterations; ++i) \ { \ DestinationArray[i] = static_cast< DestinationElementType >( SourceArray[i] ); \ @@ -1193,16 +1011,16 @@ inline int RoundHalfIntegerToEven(double // the casting type. // Source and destination array types must have defined opearator[] in their API. #ifdef ITK_USE_PORTABLE_ROUND -#define itkFoorLoopRoundingAndAssignmentMacro(DestinationType,SourceType,DestinationElementType,DestinationArray,SourceArray,NumberOfIterations) \ +#define itkForLoopRoundingAndAssignmentMacro(DestinationType,Sourcrnd_halfintup,DestinationElementType,DestinationArray,SourceArray,NumberOfIterations) \ for(unsigned int i=0;i < NumberOfIterations; ++i) \ { \ DestinationArray[i] = static_cast< DestinationElementType >( itk::Math::RoundHalfIntegerUp( SourceArray[i] ) ); \ } #else -#define itkFoorLoopRoundingAndAssignmentMacro(DestinationType,SourceType,DestinationElementType,DestinationArray,SourceArray,NumberOfIterations) \ +#define itkForLoopRoundingAndAssignmentMacro(DestinationType,SourceType,DestinationElementType,DestinationArray,SourceArray,NumberOfIterations) \ for(unsigned int i=0;i < NumberOfIterations; ++i) \ { \ - DestinationArray[i] = static_cast< DestinationElementType >( vnl_math_rnd( SourceArray[i] ) ); \ + DestinationArray[i] = static_cast< DestinationElementType >( vnl_math_rnd_halfintup( SourceArray[i] ) ); \ } #endif Index: Code/Common/itkNearestNeighborExtrapolateImageFunction.h =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkNearestNeighborExtrapolateImageFunction.h,v retrieving revision 1.6 diff -u -p -r1.6 itkNearestNeighborExtrapolateImageFunction.h --- Code/Common/itkNearestNeighborExtrapolateImageFunction.h 7 May 2009 14:03:46 -0000 1.6 +++ Code/Common/itkNearestNeighborExtrapolateImageFunction.h 16 May 2009 16:02:32 -0000 @@ -95,7 +95,7 @@ public: #ifdef ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY nindex[j] = static_cast<ValueType>( itk::Math::RoundHalfIntegerUp( index[j] ) ); #else - nindex[j] = static_cast<ValueType>( vnl_math_rnd( index[j] ) ); + nindex[j] = static_cast<ValueType>( vnl_math_rnd_halfintup( index[j] ) ); #endif } } Index: Testing/Code/Algorithms/itkInterpolateTest.cxx =================================================================== RCS file: /cvsroot/Insight/Insight/Testing/Code/Algorithms/itkInterpolateTest.cxx,v retrieving revision 1.32 diff -u -p -r1.32 itkInterpolateTest.cxx --- Testing/Code/Algorithms/itkInterpolateTest.cxx 20 Aug 2007 12:47:12 -0000 1.32 +++ Testing/Code/Algorithms/itkInterpolateTest.cxx 16 May 2009 16:02:33 -0000 @@ -180,12 +180,18 @@ int itkInterpolateTest(int, char *[] ) cindex = ContinuousIndexType(darray1); passed = TestContinuousIndex<InterpolatorType>( interp, cindex, true, 70 ); - if( !passed ) flag = 1; + if( !passed ) + { + flag = 1; + } image->TransformContinuousIndexToPhysicalPoint( cindex, point ); passed = TestGeometricPoint<InterpolatorType>( interp, point, true, 70 ); - if( !passed ) flag = 1; + if( !passed ) + { + flag = 1; + } index[0] = 10; index[1] = 20; @@ -203,12 +209,18 @@ int itkInterpolateTest(int, char *[] ) cindex = ContinuousIndexType(darray2); passed = TestContinuousIndex<InterpolatorType>( interp, cindex, true, 60 ); - if( !passed ) flag = 1; + if( !passed ) + { + flag = 1; + } image->TransformContinuousIndexToPhysicalPoint( cindex, point ); passed = TestGeometricPoint<InterpolatorType>( interp, point, true, 60 ); - if( !passed ) flag = 1; + if( !passed ) + { + flag = 1; + } // position near image border double epsilon = 1.0e-10; @@ -216,47 +228,161 @@ int itkInterpolateTest(int, char *[] ) cindex = ContinuousIndexType(darray3); passed = TestContinuousIndex<InterpolatorType>( interp, cindex, true, 79 ); - if( !passed ) flag = 1; + if( !passed ) + { + flag = 1; + } image->TransformContinuousIndexToPhysicalPoint( cindex, point ); passed = TestGeometricPoint<InterpolatorType>( interp, point, true, 79 ); - if( !passed ) flag = 1; + if( !passed ) + { + flag = 1; + } // position outside the image double darray4[3] = {20, 20, 40}; cindex = ContinuousIndexType(darray4); passed = TestContinuousIndex<InterpolatorType>( interp, cindex, false, 0 ); - if( !passed ) flag = 1; + if( !passed ) + { + flag = 1; + } image->TransformContinuousIndexToPhysicalPoint( cindex, point ); passed = TestGeometricPoint<InterpolatorType>( interp, point, false, 0 ); - if( !passed ) flag = 1; + if( !passed ) + { + flag = 1; + } - // at non-integer position - double darray5[3] = {5.25, 12.5, 42.0}; + // at non-integer position, before half value + double darray5[3] = {5.25, 12.4, 42.0}; cindex = ContinuousIndexType(darray5); - passed = TestContinuousIndex<InterpolatorType>( interp, cindex, true, 59.75 ); + passed = TestContinuousIndex<InterpolatorType>( interp, cindex, true, 59.65 ); - if( !passed ) flag = 1; + if( !passed ) + { + flag = 1; + } image->TransformContinuousIndexToPhysicalPoint( cindex, point ); - passed = TestGeometricPoint<InterpolatorType>( interp, point, true, 59.75 ); + passed = TestGeometricPoint<InterpolatorType>( interp, point, true, 59.65 ); - if( !passed ) flag = 1; + if( !passed ) + { + flag = 1; + } /* Create and initialize the nearest neigh. interpolator */ NNInterpolatorType::Pointer nninterp = NNInterpolatorType::New(); nninterp->SetInputImage(image); nninterp->Print( std::cout ); - passed = TestContinuousIndex<NNInterpolatorType>( nninterp, cindex, true, - 60 ); + double expectedValue = + itk::Math::Round( darray5[0] ) + + itk::Math::Round( darray5[1] ) + + itk::Math::Round( darray5[2] ); + + passed = TestContinuousIndex<NNInterpolatorType>( nninterp, cindex, true, expectedValue ); + + if( !passed ) + { + flag = 1; + } + + // at non-integer position, after half value + double darray6[3] = {5.25, 12.6, 42.0}; + cindex = ContinuousIndexType(darray6); + passed = TestContinuousIndex<InterpolatorType>( interp, cindex, true, 59.85 ); + + if( !passed ) + { + flag = 1; + } + + image->TransformContinuousIndexToPhysicalPoint( cindex, point ); + passed = TestGeometricPoint<InterpolatorType>( interp, point, true, 59.85 ); + + if( !passed ) + { + flag = 1; + } + + expectedValue = + itk::Math::Round( darray6[0] ) + + itk::Math::Round( darray6[1] ) + + itk::Math::Round( darray6[2] ); + + passed = TestContinuousIndex<NNInterpolatorType>( nninterp, cindex, true, expectedValue ); + + if( !passed ) + { + flag = 1; + } + + // at non-integer position, at half value with an even base number + double darray7[3] = {5.25, 12.5, 42.0}; + cindex = ContinuousIndexType(darray7); + passed = TestContinuousIndex<InterpolatorType>( interp, cindex, true, 59.75 ); + + if( !passed ) + { + flag = 1; + } + + image->TransformContinuousIndexToPhysicalPoint( cindex, point ); + passed = TestGeometricPoint<InterpolatorType>( interp, point, true, 59.75 ); + + if( !passed ) + { + flag = 1; + } + + expectedValue = + itk::Math::Round( darray7[0] ) + + itk::Math::Round( darray7[1] ) + + itk::Math::Round( darray7[2] ); + + passed = TestContinuousIndex<NNInterpolatorType>( nninterp, cindex, true, expectedValue ); + + if( !passed ) + { + flag = 1; + } + + // at non-integer position, at half value with an odd base number + double darray8[3] = {5.25, 11.5, 42.0}; + cindex = ContinuousIndexType(darray8); + passed = TestContinuousIndex<InterpolatorType>( interp, cindex, true, 58.75 ); + + if( !passed ) + { + flag = 1; + } + + image->TransformContinuousIndexToPhysicalPoint( cindex, point ); + passed = TestGeometricPoint<InterpolatorType>( interp, point, true, 58.75 ); - if( !passed ) flag = 1; + if( !passed ) + { + flag = 1; + } + expectedValue = + itk::Math::Round( darray8[0] ) + + itk::Math::Round( darray8[1] ) + + itk::Math::Round( darray8[2] ); + + passed = TestContinuousIndex<NNInterpolatorType>( nninterp, cindex, true, expectedValue ); + + if( !passed ) + { + flag = 1; + } /* Return results of test */ Index: Utilities/vxl/config/cmake/config/CMakeLists.txt =================================================================== RCS file: /cvsroot/Insight/Insight/Utilities/vxl/config/cmake/config/CMakeLists.txt,v retrieving revision 1.14 diff -u -p -r1.14 CMakeLists.txt --- Utilities/vxl/config/cmake/config/CMakeLists.txt 27 Feb 2009 19:51:12 -0000 1.14 +++ Utilities/vxl/config/cmake/config/CMakeLists.txt 16 May 2009 16:02:35 -0000 @@ -186,6 +186,30 @@ PERFORM_CHECK_HEADER(ieeefp.h VXL_HAS_IE PERFORM_CHECK_HEADER(iso646.h VCL_CXX_HAS_HEADER_ISO646_H) PERFORM_CHECK_HEADER(emmintrin.h VXL_HAS_EMMINTRIN_H) +# check for hardware support for sse2 with the current compiler flags +PERFORM_CMAKE_TEST_RUN(vxl_platform_tests.cxx VXL_HAS_SSE2_HARDWARE_SUPPORT) + +# if no support right now, see if the support exists if some flags +# are added. This can be used to give the user some useful info. +IF(NOT VXL_HAS_SSE2_HARDWARE_SUPPORT) + IF(CMAKE_COMPILER_IS_GNUCXX) + SET(VXL_SSE_TEST_FLAG_BACKUP ${CMAKE_REQUIRED_FLAGS}) + SET(CMAKE_REQUIRED_FLAGS " -msse2 ${VXL_SSE_TEST_FLAG_BACKUP} ") + PERFORM_CMAKE_TEST_RUN(vxl_platform_tests.cxx VXL_SSE2_HARDWARE_SUPPORT_POSSIBLE) + SET( VXL_SSE2_HARDWARE_SUPPORT_POSSIBLE_HELP + "The current compiler flags do not allow the SSE2 instructions to be used. " + "It looks like if you add the flag '-msse2' you will be able to use the " + "SSE2 instructions. If you chose to set VNL_CONFIG_ENABLE_SSE or " + "VNL_CONFIG_ENABLE_SSE2_ROUNDING to ON, cmake will put this flag for you. " + "You can also add this flag yourself. If you still see this message, after " + "the flag change, you may need to set VXL_UPDATE_CONFIGURATION to ON and " + "rerun cmake." + CACHE INTERNAL "help string for how to enable SSE2 support" ) + SET(CMAKE_REQUIRED_FLAGS ${VXL_SSE_TEST_FLAG_BACKUP}) + ENDIF(CMAKE_COMPILER_IS_GNUCXX) +ENDIF(NOT VXL_HAS_SSE2_HARDWARE_SUPPORT) + + # # Check for aligned dynamic memory allocation support, useful for sse # @@ -196,16 +220,6 @@ IF(VXL_HAS_EMMINTRIN_H) PERFORM_CMAKE_TEST(vxl_platform_tests.cxx VXL_HAS_ALIGNED_MALLOC) PERFORM_CMAKE_TEST(vxl_platform_tests.cxx VXL_HAS_MINGW_ALIGNED_MALLOC) PERFORM_CMAKE_TEST(vxl_platform_tests.cxx VXL_HAS_POSIX_MEMALIGN) - - # check for hardware support for sse2 - IF(CMAKE_COMPILER_IS_GNUCXX) - SET(VXL_SSE_TEST_FLAG_BACKUP ${CMAKE_REQUIRED_FLAGS}) - SET(CMAKE_REQUIRED_FLAGS " -msse2 ${VXL_SSE_TEST_FLAG_BACKUP} ") - PERFORM_CMAKE_TEST_RUN(vxl_platform_tests.cxx VXL_HAS_SSE2_HARDWARE_SUPPORT) - SET(CMAKE_REQUIRED_FLAGS ${VXL_SSE_TEST_FLAG_BACKUP}) - ELSE(CMAKE_COMPILER_IS_GNUCXX) - PERFORM_CMAKE_TEST_RUN(vxl_platform_tests.cxx VXL_HAS_SSE2_HARDWARE_SUPPORT) - ENDIF(CMAKE_COMPILER_IS_GNUCXX) ELSE(VXL_HAS_EMMINTRIN_H) SET( VXL_HAS_MM_MALLOC 0 ) SET( VXL_HAS_ALIGNED_MALLOC 0 ) Index: Utilities/vxl/config/cmake/config/vxl_platform_tests.cxx =================================================================== RCS file: /cvsroot/Insight/Insight/Utilities/vxl/config/cmake/config/vxl_platform_tests.cxx,v retrieving revision 1.9 diff -u -p -r1.9 vxl_platform_tests.cxx --- Utilities/vxl/config/cmake/config/vxl_platform_tests.cxx 13 Nov 2007 14:56:52 -0000 1.9 +++ Utilities/vxl/config/cmake/config/vxl_platform_tests.cxx 16 May 2009 16:02:36 -0000 @@ -1174,7 +1174,7 @@ int main() //------------------------------------- -#ifdef VXL_HAS_SSE2_HARDWARE_SUPPORT +#if defined(VXL_HAS_SSE2_HARDWARE_SUPPORT) || defined(VXL_SSE2_HARDWARE_SUPPORT_POSSIBLE) #include <emmintrin.h> int main() { @@ -1182,12 +1182,12 @@ int main() double d_a[] = { 6.75, 3.42 }; double d_b[] = { 2.3, 9.2 }; double res[2] = {0.0}; - + __m128d z; z = _mm_mul_pd(_mm_loadu_pd(d_a),_mm_loadu_pd(d_b)); - + _mm_storeu_pd(res,z); - + return 0; } #endif Index: Utilities/vxl/core/vnl/CMakeLists.txt =================================================================== RCS file: /cvsroot/Insight/Insight/Utilities/vxl/core/vnl/CMakeLists.txt,v retrieving revision 1.15 diff -u -p -r1.15 CMakeLists.txt --- Utilities/vxl/core/vnl/CMakeLists.txt 21 Nov 2007 20:24:34 -0000 1.15 +++ Utilities/vxl/core/vnl/CMakeLists.txt 16 May 2009 16:02:36 -0000 @@ -8,19 +8,40 @@ OPTION(VNL_CONFIG_LEGACY_METHODS OPTION(VNL_CONFIG_THREAD_SAFE "Whether thread-safe vnl implementations are used." ON) - + #IF( VXL_HAS_EMMINTRIN_H AND VXL_HAS_SSE2_HARDWARE_SUPPORT ) # OPTION(VNL_CONFIG_ENABLE_SSE2 # "Enable Streaming SIMD Extensions 2 optimisations (hardware dependant)." ON) #ELSE ( VXL_HAS_EMMINTRIN_H AND VXL_HAS_SSE2_HARDWARE_SUPPORT ) OPTION(VNL_CONFIG_ENABLE_SSE2 - "Enable Streaming SIMD Extensions 2 optimisations (hardware dependant)." OFF) + "Enable Streaming SIMD Extensions 2 optimisations (hardware dependant). Currently broken. For use by VNL developers only." OFF) #ENDIF( VXL_HAS_EMMINTRIN_H AND VXL_HAS_SSE2_HARDWARE_SUPPORT ) +OPTION(VNL_CONFIG_ENABLE_SSE2_ROUNDING + "Enable Streaming SIMD Extensions 2 implementation of rounding (hardware dependant)." + ${VXL_HAS_SSE2_HARDWARE_SUPPORT} ) +IF( VNL_CONFIG_ENABLE_SSE2_ROUNDING ) + IF( NOT VXL_HAS_SSE2_HARDWARE_SUPPORT ) + IF( VXL_SSE2_HARDWARE_SUPPORT_POSSIBLE ) + MESSAGE( ${VXL_SSE2_HARDWARE_SUPPORT_POSSIBLE_HELP} ) + # Reset the update configuration flag + SET( VXL_UPDATE_CONFIGURATION "ON" CACHE BOOL "Re-run the configuration tests?" FORCE ) + MESSAGE( SEND_ERROR "VXL_UPDATE_CONFIGURATION has been forced to ON. " + "Please rerun the cmake configure step" ) + ELSE( VXL_SSE2_HARDWARE_SUPPORT_POSSIBLE ) + MESSAGE( SEND_ERROR "Cannot have VNL_CONFIG_ENABLE_SSE2_ROUNDING because" + " there is no SSE2 hardware support" ) + SET(VNL_CONFIG_ENABLE_SSE2_ROUNDING 0) + ENDIF( VXL_SSE2_HARDWARE_SUPPORT_POSSIBLE ) + ENDIF( NOT VXL_HAS_SSE2_HARDWARE_SUPPORT ) +ENDIF( VNL_CONFIG_ENABLE_SSE2_ROUNDING ) + + MARK_AS_ADVANCED( VNL_CONFIG_CHECK_BOUNDS VNL_CONFIG_LEGACY_METHODS VNL_CONFIG_THREAD_SAFE + VNL_CONFIG_ENABLE_SSE2_ROUNDING VNL_CONFIG_ENABLE_SSE2 ) # Need to enforce 1/0 values for configuration. @@ -44,6 +65,11 @@ IF(VNL_CONFIG_ENABLE_SSE2) ELSE(VNL_CONFIG_ENABLE_SSE2) SET(VNL_CONFIG_ENABLE_SSE2 0) ENDIF(VNL_CONFIG_ENABLE_SSE2) +IF(VNL_CONFIG_ENABLE_SSE2_ROUNDING) + SET(VNL_CONFIG_ENABLE_SSE2_ROUNDING 1) +ELSE(VNL_CONFIG_ENABLE_SSE2_ROUNDING) + SET(VNL_CONFIG_ENABLE_SSE2_ROUNDING 0) +ENDIF(VNL_CONFIG_ENABLE_SSE2_ROUNDING) CONFIGURE_FILE(${vxl_SOURCE_DIR}/core/vnl/vnl_config.h.in ${vxl_BINARY_DIR}/core/vnl/vnl_config.h @ONLY IMMEDIATE) @@ -210,10 +236,6 @@ IF(CMAKE_COMPILER_IS_GNUCXX) SET_SOURCE_FILES_PROPERTIES(Templates/vnl_matrix_fixed+vnl_bignum.3.3-.cxx PROPERTIES COMPILE_FLAGS -O0) SET_SOURCE_FILES_PROPERTIES(Templates/vnl_vector+vnl_rational-.cxx PROPERTIES COMPILE_FLAGS -O0) SET_SOURCE_FILES_PROPERTIES(Templates/vnl_vector_fixed+vnl_rational.3-.cxx PROPERTIES COMPILE_FLAGS -O0) - # gcc must have -msse2 option to enable sse2 support - IF(VNL_CONFIG_ENABLE_SSE2) - ADD_DEFINITIONS( -msse2 ) - ENDIF(VNL_CONFIG_ENABLE_SSE2) ENDIF(CMAKE_COMPILER_IS_GNUCXX) ADD_LIBRARY(itkvnl ${vnl_sources}) Index: Utilities/vxl/core/vnl/vnl_config.h.in =================================================================== RCS file: /cvsroot/Insight/Insight/Utilities/vxl/core/vnl/vnl_config.h.in,v retrieving revision 1.3 diff -u -p -r1.3 vnl_config.h.in --- Utilities/vxl/core/vnl/vnl_config.h.in 13 Nov 2007 14:56:52 -0000 1.3 +++ Utilities/vxl/core/vnl/vnl_config.h.in 16 May 2009 16:02:36 -0000 @@ -19,4 +19,7 @@ //: Set to 0 if you don't have SSE2 support on your target platform #define VNL_CONFIG_ENABLE_SSE2 @VNL_CONFIG_ENABLE_SSE2@ +//: Set to 0 if you don't want to use SSE2 instructions to implement rounding, floor, and ceil functions. +#define VNL_CONFIG_ENABLE_SSE2_ROUNDING @VNL_CONFIG_ENABLE_SSE2_ROUNDING@ + #endif Index: Utilities/vxl/core/vnl/vnl_math.h =================================================================== RCS file: /cvsroot/Insight/Insight/Utilities/vxl/core/vnl/vnl_math.h,v retrieving revision 1.7 diff -u -p -r1.7 vnl_math.h --- Utilities/vxl/core/vnl/vnl_math.h 22 Aug 2007 17:47:43 -0000 1.7 +++ Utilities/vxl/core/vnl/vnl_math.h 16 May 2009 16:02:36 -0000 @@ -5,39 +5,66 @@ #pragma interface #endif //: -// \file -// \brief Namespace with standard math functions +// \file +// \brief Namespace with standard math functions // -// The vnl_math namespace provides a standard set of the simple mathematical -// functions (min, max, sqr, sgn, rnd, abs), and some predefined constants -// such as pi and e, which are not defined by the ANSI C++ standard. +// The vnl_math namespace provides a standard set of the simple mathematical +// functions (min, max, sqr, sgn, rnd, abs), and some predefined constants +// such as pi and e, which are not defined by the ANSI C++ standard. // -// There are complex versions defined in vnl_complex.h +// There are complex versions defined in vnl_complex.h // -// That's right, M_PI is nonstandard! +// That's right, M_PI is nonstandard! // -// Aside from e, pi and their associates the class also defines eps, -// the IEEE double machine precision. This is the smallest number -// eps such that 1+eps != 1. +// Aside from e, pi and their associates the class also defines eps, +// the IEEE double machine precision. This is the smallest number +// eps such that 1+eps != 1. // -// The operations are overloaded for int, float and double arguments, -// which in combination with inlining can make them more efficient than -// their counterparts in the standard C library. +// The operations are overloaded for int, float and double arguments, +// which in combination with inlining can make them more efficient than +// their counterparts in the standard C library. // -// \author Andrew W. Fitzgibbon, Oxford RRG -// \date July 13, 1996 +// \author Andrew W. Fitzgibbon, Oxford RRG +// \date July 13, 1996 // // \verbatim // Modifications -// 210598 AWF Removed conditional VCL_IMPLEMENT_STATIC_CONSTS, sometimes gcc needs them. -// LSB (Modifications) 23/1/01 Documentation tidied -// Peter Vanroose - 7 Sept. 2002 - maxdouble etc. replaced by vnl_numeric_traits<T>::maxval +// 21 May 1998 AWF Removed conditional VCL_IMPLEMENT_STATIC_CONSTS, sometimes gcc needs them. +// LSB (Modifications) 23 Jan 2001 Documentation tidied +// Peter Vanroose - 7 Sep 2002 - maxdouble etc. replaced by vnl_numeric_traits<T>::maxval // Amitha Perera - 13 Sep 2002 - make constant initialization standards compliant. // \endverbatim #include <vcl_cmath.h> #include "dll.h" -#include <vxl_config.h> // for VXL_C_MATH_HAS_LROUND +#include <vxl_config.h> +#include <vnl/vnl_config.h> // for VNL_CONFIG_ENABLE_SSE2_ROUNDING +#ifdef VNL_CHECK_FPU_ROUNDING_MODE +# include <vcl_cassert.h> +#endif + +// Figure out when the fast implementation can be used +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING +# if !VXL_HAS_EMMINTRIN_H +# error "Required file emmintrin.h for SSE2 not found" +# else +# include <emmintrin.h> // sse 2 intrinsics +# endif +#endif +// Turn on fast impl when using GCC on Intel-based machines with the following exception: +// PPC with Mac OS X +#if defined(__GNUC__) && (!defined(__APPLE__) || !defined(__ppc__) ) +# define GCC_USE_FAST_IMPL 1 +#else +# define GCC_USE_FAST_IMPL 0 +#endif +// Turn on fast impl when using msvc on 32 bits windows +#if defined(VCL_VC) && !defined(_WIN64) +# define VC_USE_FAST_IMPL 1 +#else +# define VC_USE_FAST_IMPL 0 +#endif + //: Type-accessible infinities for use in templates. template <class T> T vnl_huge_val(T); @@ -53,19 +80,20 @@ class vnl_math { public: //: pi, e and all that - static VNL_DLL_DATA const double e VCL_STATIC_CONST_INIT_FLOAT_DECL(2.7182818284590452354); - static VNL_DLL_DATA const double log2e VCL_STATIC_CONST_INIT_FLOAT_DECL(1.4426950408889634074); - static VNL_DLL_DATA const double log10e VCL_STATIC_CONST_INIT_FLOAT_DECL(0.43429448190325182765); - static VNL_DLL_DATA const double ln2 VCL_STATIC_CONST_INIT_FLOAT_DECL(0.69314718055994530942); - static VNL_DLL_DATA const double ln10 VCL_STATIC_CONST_INIT_FLOAT_DECL(2.30258509299404568402); - static VNL_DLL_DATA const double pi VCL_STATIC_CONST_INIT_FLOAT_DECL(3.14159265358979323846); - static VNL_DLL_DATA const double pi_over_2 VCL_STATIC_CONST_INIT_FLOAT_DECL(1.57079632679489661923); - static VNL_DLL_DATA const double pi_over_4 VCL_STATIC_CONST_INIT_FLOAT_DECL(0.78539816339744830962); - static VNL_DLL_DATA const double one_over_pi VCL_STATIC_CONST_INIT_FLOAT_DECL(0.31830988618379067154); - static VNL_DLL_DATA const double two_over_pi VCL_STATIC_CONST_INIT_FLOAT_DECL(0.63661977236758134308); - static VNL_DLL_DATA const double two_over_sqrtpi VCL_STATIC_CONST_INIT_FLOAT_DECL(1.12837916709551257390); - static VNL_DLL_DATA const double sqrt2 VCL_STATIC_CONST_INIT_FLOAT_DECL(1.41421356237309504880); - static VNL_DLL_DATA const double sqrt1_2 VCL_STATIC_CONST_INIT_FLOAT_DECL(0.70710678118654752440); + static VNL_DLL_DATA const double e VCL_STATIC_CONST_INIT_FLOAT_DECL(2.7182818284590452354); + static VNL_DLL_DATA const double log2e VCL_STATIC_CONST_INIT_FLOAT_DECL(1.4426950408889634074); + static VNL_DLL_DATA const double log10e VCL_STATIC_CONST_INIT_FLOAT_DECL(0.43429448190325182765); + static VNL_DLL_DATA const double ln2 VCL_STATIC_CONST_INIT_FLOAT_DECL(0.69314718055994530942); + static VNL_DLL_DATA const double ln10 VCL_STATIC_CONST_INIT_FLOAT_DECL(2.30258509299404568402); + static VNL_DLL_DATA const double pi VCL_STATIC_CONST_INIT_FLOAT_DECL(3.14159265358979323846); + static VNL_DLL_DATA const double pi_over_2 VCL_STATIC_CONST_INIT_FLOAT_DECL(1.57079632679489661923); + static VNL_DLL_DATA const double pi_over_4 VCL_STATIC_CONST_INIT_FLOAT_DECL(0.78539816339744830962); + static VNL_DLL_DATA const double one_over_pi VCL_STATIC_CONST_INIT_FLOAT_DECL(0.31830988618379067154); + static VNL_DLL_DATA const double two_over_pi VCL_STATIC_CONST_INIT_FLOAT_DECL(0.63661977236758134308); + static VNL_DLL_DATA const double two_over_sqrtpi VCL_STATIC_CONST_INIT_FLOAT_DECL(1.12837916709551257390); + static VNL_DLL_DATA const double one_over_sqrt2pi VCL_STATIC_CONST_INIT_FLOAT_DECL(0.39894228040143267794); + static VNL_DLL_DATA const double sqrt2 VCL_STATIC_CONST_INIT_FLOAT_DECL(1.41421356237309504880); + static VNL_DLL_DATA const double sqrt1_2 VCL_STATIC_CONST_INIT_FLOAT_DECL(0.70710678118654752440); //: IEEE double machine precision static VNL_DLL_DATA const double eps VCL_STATIC_CONST_INIT_FLOAT_DECL(2.2204460492503131e-16); @@ -140,50 +168,353 @@ bool vnl_math_isfinite(long double); template <class T> bool vnl_math_isfinite(T); #endif -// rnd (rounding; 0.5 rounds up) -#if VXL_C_MATH_HAS_LROUND -// Use C99 functions, which GCC implements as an intrinsic -// Or in simpler terms - is at least 3 times faster. -inline int vnl_math_rnd(float x) { return static_cast<int>(lroundf(x)); } -inline int vnl_math_rnd(double x) { return static_cast<int>(lround(x)); } -#elif defined (VCL_VC) && !defined(__GCCXML__) && !defined(_WIN64) -// Use assembly inline function from -// http://mega-nerd.com/FPcast/ -// - - // Win32 doesn't seem to have these functions. - // Therefore implement inline versions of these functions here. -// NB But Win64 does not support the non-standard _asm - __inline int - vnl_math_rnd (double flt) - { int intgr; - _asm - { fld flt - fistp intgr - } ; - return intgr ; - } - - __inline int - vnl_math_rnd (float flt) - { int intgr; - _asm - { fld flt - fistp intgr - } ; - return intgr; - } -#else -inline int vnl_math_rnd(float x) { return (x>=0.0)?(int)(x + 0.5):(int)(x - 0.5); } -inline int vnl_math_rnd(double x) { return (x>=0.0)?(int)(x + 0.5):(int)(x - 0.5); } + + +// vnl_math_rnd_halfinttoeven -- round towards nearest integer +// halfway cases are rounded towards the nearest even integer, e.g. +// vnl_math_rnd_halfinttoeven( 1.5) == 2 +// vnl_math_rnd_halfinttoeven(-1.5) == -2 +// vnl_math_rnd_halfinttoeven( 2.5) == 2 +// vnl_math_rnd_halfinttoeven( 3.5) == 4 +// +// We assume that the rounding mode is not changed from the default +// one (or at least that it is always restored to the default one). + +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING // Fast sse2 implementation + +inline int vnl_math_rnd_halfinttoeven(float x) +{ +# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) + assert(fegetround()==FE_TONEAREST); +# endif + return _mm_cvtss_si32(_mm_set_ss(x)); +} +inline int vnl_math_rnd_halfinttoeven(double x) +{ +# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) + assert(fegetround()==FE_TONEAREST); +# endif + return _mm_cvtsd_si32(_mm_set_sd(x)); +} + +#elif GCC_USE_FAST_IMPL // Fast gcc asm implementation + +inline int vnl_math_rnd_halfinttoeven(float x) +{ +# ifdef VNL_CHECK_FPU_ROUNDING_MODE + assert(fegetround()==FE_TONEAREST); +# endif + int r; + __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); + return r; +} +inline int vnl_math_rnd_halfinttoeven(double x) +{ +# ifdef VNL_CHECK_FPU_ROUNDING_MODE + assert(fegetround()==FE_TONEAREST); +# endif + int r; + __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); + return r; +} + +#elif VC_USE_FAST_IMPL // Fast msvc asm implementation + +inline int vnl_math_rnd_halfinttoeven(float x) +{ + int r; + __asm { + fld x + fistp r + } + return r; +} +inline int vnl_math_rnd_halfinttoeven(double x) +{ + int r; + __asm { + fld x + fistp r + } + return r; +} + +#else // Vanilla implementation + +inline int vnl_math_rnd_halfinttoeven(float x) +{ + if (x>=0.f) + { + x+=0.5f; + const int r = static_cast<int>(x); + if ( x != static_cast<float>(r) ) return r; + return 2*(r/2); + } + else + { + x-=0.5f; + const int r = static_cast<int>(x); + if ( x != static_cast<float>(r) ) return r; + return 2*(r/2); + } +} +inline int vnl_math_rnd_halfinttoeven(double x) +{ + if (x>=0.) + { + x+=0.5; + const int r = static_cast<int>(x); + if ( x != static_cast<double>(r) ) return r; + return 2*(r/2); + } + else + { + x-=0.5; + const int r = static_cast<int>(x); + if ( x != static_cast<double>(r) ) return r; + return 2*(r/2); + } +} + +#endif + + + +// vnl_math_rnd_halfintup -- round towards nearest integer +// halfway cases are rounded upward, e.g. +// vnl_math_rnd_halfintup( 1.5) == 2 +// vnl_math_rnd_halfintup(-1.5) == -1 +// vnl_math_rnd_halfintup( 2.5) == 3 +// +// Be careful: argument absolute value must be less than INT_MAX/2 +// for vnl_math_rnd_halfintup to be guaranteed to work. +// We also assume that the rounding mode is not changed from the default +// one (or at least that it is always restored to the default one). + +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING || GCC_USE_FAST_IMPL || VC_USE_FAST_IMPL + +inline int vnl_math_rnd_halfintup(float x) { return vnl_math_rnd_halfinttoeven(2*x+0.5f)>>1; } +inline int vnl_math_rnd_halfintup(double x) { return vnl_math_rnd_halfinttoeven(2*x+0.5)>>1; } + +#else // Vanilla implementation + +inline int vnl_math_rnd_halfintup(float x) +{ + x+=0.5f; + return static_cast<int>(x>=0.f?x:(x==static_cast<int>(x)?x:x-1.f)); +} +inline int vnl_math_rnd_halfintup(double x) +{ + x+=0.5; + return static_cast<int>(x>=0.?x:(x==static_cast<int>(x)?x:x-1.)); +} + +#endif + + + +// vnl_math_rnd -- round towards nearest integer +// halfway cases such as 0.5 may be rounded either up or down +// so as to maximize the efficiency, e.g. +// vnl_math_rnd_halfinttoeven( 1.5) == 1 or 2 +// vnl_math_rnd_halfinttoeven(-1.5) == -2 or -1 +// vnl_math_rnd_halfinttoeven( 2.5) == 2 or 3 +// vnl_math_rnd_halfinttoeven( 3.5) == 3 or 4 +// +// We assume that the rounding mode is not changed from the default +// one (or at least that it is always restored to the default one). + +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING || GCC_USE_FAST_IMPL || VC_USE_FAST_IMPL + +inline int vnl_math_rnd(float x) { return vnl_math_rnd_halfinttoeven(x); } +inline int vnl_math_rnd(double x) { return vnl_math_rnd_halfinttoeven(x); } + +#else // Vanilla implementation + +inline int vnl_math_rnd(float x) { return x>=0.f?static_cast<int>(x+.5f):static_cast<int>(x-.5f); } +inline int vnl_math_rnd(double x) { return x>=0.0?static_cast<int>(x+0.5):static_cast<int>(x-0.5); } + + +#endif + + + +// vnl_math_floor -- round towards minus infinity +// +// Be careful: argument absolute value must be less than INT_MAX/2 +// for vnl_math_floor to be guaranteed to work. +// We also assume that the rounding mode is not changed from the default +// one (or at least that it is always restored to the default one). + +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING // Fast sse2 implementation + +inline int vnl_math_floor(float x) +{ +# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) + assert(fegetround()==FE_TONEAREST); +# endif + return _mm_cvtss_si32(_mm_set_ss(2*x-.5f))>>1; +} +inline int vnl_math_floor(double x) +{ +# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) + assert(fegetround()==FE_TONEAREST); +# endif + return _mm_cvtsd_si32(_mm_set_sd(2*x-.5))>>1; +} + +#elif GCC_USE_FAST_IMPL // Fast gcc asm implementation + +inline int vnl_math_floor(float x) +{ +# ifdef VNL_CHECK_FPU_ROUNDING_MODE + assert(fegetround()==FE_TONEAREST); +# endif + int r; + x = 2*x-.5f; + __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); + return r>>1; +} +inline int vnl_math_floor(double x) +{ +# ifdef VNL_CHECK_FPU_ROUNDING_MODE + assert(fegetround()==FE_TONEAREST); +# endif + int r; + x = 2*x-.5; + __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); + return r>>1; +} + +#elif VC_USE_FAST_IMPL // Fast msvc asm implementation + +inline int vnl_math_floor(float x) +{ + int r; + x = 2*x-.5f; + __asm { + fld x + fistp r + } + return r>>1; +} +inline int vnl_math_floor(double x) +{ + int r; + x = 2*x-.5; + __asm { + fld x + fistp r + } + return r>>1; +} + +#else // Vanilla implementation + +inline int vnl_math_floor(float x) +{ + return static_cast<int>(x>=0.f?x:(x==static_cast<int>(x)?x:x-1.f)); +} +inline int vnl_math_floor(double x) +{ + return static_cast<int>(x>=0.0?x:(x==static_cast<int>(x)?x:x-1.0)); +} + #endif + + +// vnl_math_ceil -- round towards plus infinity +// +// Be careful: argument absolute value must be less than INT_MAX/2 +// for vnl_math_ceil to be guaranteed to work. +// We also assume that the rounding mode is not changed from the default +// one (or at least that it is always restored to the default one). + +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING // Fast sse2 implementation + +inline int vnl_math_ceil(float x) +{ +# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) + assert(fegetround()==FE_TONEAREST); +# endif + return -(_mm_cvtss_si32(_mm_set_ss(-.5f-2*x))>>1); +} +inline int vnl_math_ceil(double x) +{ +# if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__) + assert(fegetround()==FE_TONEAREST); +# endif + return -(_mm_cvtsd_si32(_mm_set_sd(-.5-2*x))>>1); +} + +#elif GCC_USE_FAST_IMPL // Fast gcc asm implementation + +inline int vnl_math_ceil(float x) +{ +# ifdef VNL_CHECK_FPU_ROUNDING_MODE + assert(fegetround()==FE_TONEAREST); +# endif + int r; + x = -.5f-2*x; + __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); + return -(r>>1); +} +inline int vnl_math_ceil(double x) +{ +# ifdef VNL_CHECK_FPU_ROUNDING_MODE + assert(fegetround()==FE_TONEAREST); +# endif + int r; + x = -.5-2*x; + __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); + return -(r>>1); +} + +#elif VC_USE_FAST_IMPL // Fast msvc asm implementation + +inline int vnl_math_ceil(float x) +{ + int r; + x = -.5f-2*x; + __asm { + fld x + fistp r + } + return -(r>>1); +} +inline int vnl_math_ceil(double x) +{ + int r; + x = -.5-2*x; + __asm { + fld x + fistp r + } + return -(r>>1); +} + +#else // Vanilla implementation + +inline int vnl_math_ceil(float x) +{ + return static_cast<int>(x<0.f?x:(x==static_cast<int>(x)?x:x+1.f)); +} +inline int vnl_math_ceil(double x) +{ + return static_cast<int>(x<0.0?x:(x==static_cast<int>(x)?x:x+1.0)); +} + +#endif + + + // abs inline bool vnl_math_abs(bool x) { return x; } inline unsigned char vnl_math_abs(unsigned char x) { return x; } -inline unsigned char vnl_math_abs(signed char x) { return x < 0 ? -x : x; } -inline unsigned char vnl_math_abs(char x) { return (unsigned char)x; } -inline unsigned short vnl_math_abs(short x) { return x < 0 ? -x : x; } +inline unsigned char vnl_math_abs(signed char x) { return x < 0 ? static_cast<unsigned char>(-x) : x; } +inline unsigned char vnl_math_abs(char x) { return static_cast<unsigned char>(x); } +inline unsigned short vnl_math_abs(short x) { return x < 0 ? static_cast<unsigned short>(-x) : x; } inline unsigned short vnl_math_abs(unsigned short x){ return x; } inline unsigned int vnl_math_abs(int x) { return x < 0 ? -x : x; } inline unsigned int vnl_math_abs(unsigned int x) { return x; } Index: Utilities/vxl/core/vnl/tests/test_math.cxx =================================================================== RCS file: /cvsroot/Insight/Insight/Utilities/vxl/core/vnl/tests/test_math.cxx,v retrieving revision 1.10 diff -u -p -r1.10 test_math.cxx --- Utilities/vxl/core/vnl/tests/test_math.cxx 20 Apr 2009 20:01:37 -0000 1.10 +++ Utilities/vxl/core/vnl/tests/test_math.cxx 16 May 2009 16:02:37 -0000 @@ -68,22 +68,135 @@ void test_math() testlib_test_assert_near("exp(d*i) ~= -1", vnl_math_abs(e_ipi+1.0), 0); vcl_cout << vcl_endl; - testlib_test_assert("rnd(-8.4999) == -8", vnl_math_rnd(-8.4999) == -8); - testlib_test_assert("rnd(-8.4999f) == -8", vnl_math_rnd(-8.4999f) == -8); - vcl_cout << "vnl_math_rnd(-8.50) == " << vnl_math_rnd(-8.50) << vcl_endl; - testlib_test_assert("rnd(-8.50) == -8/9", vnl_math_rnd(-8.50)/2 == -4); - testlib_test_assert("rnd(-8.50f) == -8/9", vnl_math_rnd(-8.50f)/2 == -4); - vcl_cout << "vnl_math_rnd(-8.5001) == " << vnl_math_rnd(-8.5001) << vcl_endl; - testlib_test_assert("rnd(-8.5001) == -9", vnl_math_rnd(-8.5001) == -9); - testlib_test_assert("rnd(-8.5001f) == -9", vnl_math_rnd(-8.5001f) == -9); - testlib_test_assert("rnd(8.4999) == 8", vnl_math_rnd(8.4999) == 8); - testlib_test_assert("rnd(8.4999f) == 8", vnl_math_rnd(8.4999f) == 8); - testlib_test_assert("rnd(8.50) == 8/9", vnl_math_rnd(8.50)/2 == 4); - vcl_cout << "vnl_math_rnd(8.50) == " << vnl_math_rnd(8.50) << vcl_endl; - testlib_test_assert("rnd(8.50f) == 8/9", vnl_math_rnd(8.50f)/2 == 4); - vcl_cout << "vnl_math_rnd(8.5001) == " << vnl_math_rnd(8.5001) << vcl_endl; - testlib_test_assert("rnd(8.5001) == 9", vnl_math_rnd(8.5001) == 9); - testlib_test_assert("rnd(8.5001f) == 9", vnl_math_rnd(8.5001f) == 9); + testlib_test_assert("rnd(-8.4999) == -8 ", vnl_math_rnd(-8.4999) == -8); + testlib_test_assert("rnd(-8.4999f) == -8 ", vnl_math_rnd(-8.4999f) == -8); + testlib_test_assert("rnd(-8.50) == -8/9", vnl_math_rnd(-8.50)/2 == -4); + testlib_test_assert("rnd(-8.50f) == -8/9", vnl_math_rnd(-8.50f)/2 == -4); + testlib_test_assert("rnd(-8.5001) == -9 ", vnl_math_rnd(-8.5001) == -9); + testlib_test_assert("rnd(-8.5001f) == -9 ", vnl_math_rnd(-8.5001f) == -9); + testlib_test_assert("rnd(8.4999) == 8 ", vnl_math_rnd(8.4999) == 8); + testlib_test_assert("rnd(8.4999f) == 8 ", vnl_math_rnd(8.4999f) == 8); + testlib_test_assert("rnd(8.50) == 8/9", vnl_math_rnd(8.50)/2 == 4); + testlib_test_assert("rnd(8.50f) == 8/9", vnl_math_rnd(8.50f)/2 == 4); + testlib_test_assert("rnd(8.5001) == 9 ", vnl_math_rnd(8.5001) == 9); + testlib_test_assert("rnd(8.5001f) == 9 ", vnl_math_rnd(8.5001f) == 9); + + testlib_test_assert("rnd(-9.4999) == -9 ", vnl_math_rnd(-9.4999) == -9); + testlib_test_assert("rnd(-9.4999f) == -9 ", vnl_math_rnd(-9.4999f) == -9); + testlib_test_assert("rnd(-9.50) == -9/10", (vnl_math_rnd(-9.50)+1)/2 == -4); + testlib_test_assert("rnd(-9.50f) == -9/10", (vnl_math_rnd(-9.50f)+1)/2 == -4); + testlib_test_assert("rnd(-9.5001) == -10 ", vnl_math_rnd(-9.5001) == -10); + testlib_test_assert("rnd(-9.5001f) == -10 ", vnl_math_rnd(-9.5001f) == -10); + testlib_test_assert("rnd(9.4999) == 9 ", vnl_math_rnd(9.4999) == 9); + testlib_test_assert("rnd(9.4999f) == 9 ", vnl_math_rnd(9.4999f) == 9); + testlib_test_assert("rnd(9.50) == 9/10", (vnl_math_rnd(9.50)-1)/2 == 4); + testlib_test_assert("rnd(9.50f) == 9/10", (vnl_math_rnd(9.50f)-1)/2 == 4); + testlib_test_assert("rnd(9.5001) == 10 ", vnl_math_rnd(9.5001) == 10); + testlib_test_assert("rnd(9.5001f) == 10 ", vnl_math_rnd(9.5001f) == 10); + + testlib_test_assert("rnd_halfinttoeven(-8.4999) == -8", vnl_math_rnd_halfinttoeven(-8.4999) == -8); + testlib_test_assert("rnd_halfinttoeven(-8.4999f) == -8", vnl_math_rnd_halfinttoeven(-8.4999f)== -8); + testlib_test_assert("rnd_halfinttoeven(-8.50) == -8", vnl_math_rnd_halfinttoeven(-8.50) == -8); + testlib_test_assert("rnd_halfinttoeven(-8.50f) == -8", vnl_math_rnd_halfinttoeven(-8.50f) == -8); + testlib_test_assert("rnd_halfinttoeven(-8.5001) == -9", vnl_math_rnd_halfinttoeven(-8.5001) == -9); + testlib_test_assert("rnd_halfinttoeven(-8.5001f) == -9", vnl_math_rnd_halfinttoeven(-8.5001f)== -9); + testlib_test_assert("rnd_halfinttoeven(8.4999) == 8", vnl_math_rnd_halfinttoeven(8.4999) == 8); + testlib_test_assert("rnd_halfinttoeven(8.4999f) == 8", vnl_math_rnd_halfinttoeven(8.4999f)== 8); + testlib_test_assert("rnd_halfinttoeven(8.50) == 9", vnl_math_rnd_halfinttoeven(8.50) == 8); + testlib_test_assert("rnd_halfinttoeven(8.50f) == 9", vnl_math_rnd_halfinttoeven(8.50f) == 8); + testlib_test_assert("rnd_halfinttoeven(8.5001) == 9", vnl_math_rnd_halfinttoeven(8.5001) == 9); + testlib_test_assert("rnd_halfinttoeven(8.5001f) == 9", vnl_math_rnd_halfinttoeven(8.5001f)== 9); + + testlib_test_assert("rnd_halfinttoeven(-9.4999) == -9 ", vnl_math_rnd_halfinttoeven(-9.4999) == -9); + testlib_test_assert("rnd_halfinttoeven(-9.4999f) == -9 ", vnl_math_rnd_halfinttoeven(-9.4999f)== -9); + testlib_test_assert("rnd_halfinttoeven(-9.50) == -9 ", vnl_math_rnd_halfinttoeven(-9.50) == -10); + testlib_test_assert("rnd_halfinttoeven(-9.50f) == -9 ", vnl_math_rnd_halfinttoeven(-9.50f) == -10); + testlib_test_assert("rnd_halfinttoeven(-9.5001) == -10", vnl_math_rnd_halfinttoeven(-9.5001) == -10); + testlib_test_assert("rnd_halfinttoeven(-9.5001f) == -10", vnl_math_rnd_halfinttoeven(-9.5001f)== -10); + testlib_test_assert("rnd_halfinttoeven(9.4999) == 9 ", vnl_math_rnd_halfinttoeven(9.4999) == 9); + testlib_test_assert("rnd_halfinttoeven(9.4999f) == 9 ", vnl_math_rnd_halfinttoeven(9.4999f)== 9); + testlib_test_assert("rnd_halfinttoeven(9.50) == 10", vnl_math_rnd_halfinttoeven(9.50) == 10); + testlib_test_assert("rnd_halfinttoeven(9.50f) == 10", vnl_math_rnd_halfinttoeven(9.50f) == 10); + testlib_test_assert("rnd_halfinttoeven(9.5001) == 10", vnl_math_rnd_halfinttoeven(9.5001) == 10); + testlib_test_assert("rnd_halfinttoeven(9.5001f) == 10", vnl_math_rnd_halfinttoeven(9.5001f)== 10); + + testlib_test_assert("rnd_halfintup(-8.4999) == -8", vnl_math_rnd_halfintup(-8.4999) == -8); + testlib_test_assert("rnd_halfintup(-8.4999f) == -8", vnl_math_rnd_halfintup(-8.4999f)== -8); + testlib_test_assert("rnd_halfintup(-8.50) == -8", vnl_math_rnd_halfintup(-8.50) == -8); + testlib_test_assert("rnd_halfintup(-8.50f) == -8", vnl_math_rnd_halfintup(-8.50f) == -8); + testlib_test_assert("rnd_halfintup(-8.5001) == -9", vnl_math_rnd_halfintup(-8.5001) == -9); + testlib_test_assert("rnd_halfintup(-8.5001f) == -9", vnl_math_rnd_halfintup(-8.5001f)== -9); + testlib_test_assert("rnd_halfintup(8.4999) == 8", vnl_math_rnd_halfintup(8.4999) == 8); + testlib_test_assert("rnd_halfintup(8.4999f) == 8", vnl_math_rnd_halfintup(8.4999f)== 8); + testlib_test_assert("rnd_halfintup(8.50) == 9", vnl_math_rnd_halfintup(8.50) == 9); + testlib_test_assert("rnd_halfintup(8.50f) == 9", vnl_math_rnd_halfintup(8.50f) == 9); + testlib_test_assert("rnd_halfintup(8.5001) == 9", vnl_math_rnd_halfintup(8.5001) == 9); + testlib_test_assert("rnd_halfintup(8.5001f) == 9", vnl_math_rnd_halfintup(8.5001f)== 9); + + testlib_test_assert("rnd_halfintup(-9.4999) == -9 ", vnl_math_rnd_halfintup(-9.4999) == -9); + testlib_test_assert("rnd_halfintup(-9.4999f) == -9 ", vnl_math_rnd_halfintup(-9.4999f)== -9); + testlib_test_assert("rnd_halfintup(-9.50) == -9 ", vnl_math_rnd_halfintup(-9.50) == -9); + testlib_test_assert("rnd_halfintup(-9.50f) == -9 ", vnl_math_rnd_halfintup(-9.50f) == -9); + testlib_test_assert("rnd_halfintup(-9.5001) == -10", vnl_math_rnd_halfintup(-9.5001) == -10); + testlib_test_assert("rnd_halfintup(-9.5001f) == -10", vnl_math_rnd_halfintup(-9.5001f)== -10); + testlib_test_assert("rnd_halfintup(9.4999) == 9 ", vnl_math_rnd_halfintup(9.4999) == 9); + testlib_test_assert("rnd_halfintup(9.4999f) == 9 ", vnl_math_rnd_halfintup(9.4999f)== 9); + testlib_test_assert("rnd_halfintup(9.50) == 10", vnl_math_rnd_halfintup(9.50) == 10); + testlib_test_assert("rnd_halfintup(9.50f) == 10", vnl_math_rnd_halfintup(9.50f) == 10); + testlib_test_assert("rnd_halfintup(9.5001) == 10", vnl_math_rnd_halfintup(9.5001) == 10); + testlib_test_assert("rnd_halfintup(9.5001f) == 10", vnl_math_rnd_halfintup(9.5001f)== 10); + + testlib_test_assert("floor(8.0) == 8", vnl_math_floor(8.0) == 8); + testlib_test_assert("floor(8.0f) == 8", vnl_math_floor(8.0f) == 8); + testlib_test_assert("floor(8.9999) == 8", vnl_math_floor(8.9999) == 8); + testlib_test_assert("floor(8.9999f) == 8", vnl_math_floor(8.9999f) == 8); + testlib_test_assert("floor(8.0001) == 8", vnl_math_floor(8.0001) == 8); + testlib_test_assert("floor(8.0001f) == 8", vnl_math_floor(8.0001f) == 8); + testlib_test_assert("floor(-8.0) == -8", vnl_math_floor(-8.0) == -8); + testlib_test_assert("floor(-8.0f) == -8", vnl_math_floor(-8.0f) == -8); + testlib_test_assert("floor(-8.9999) == -9", vnl_math_floor(-8.9999) == -9); + testlib_test_assert("floor(-8.9999f) == -9", vnl_math_floor(-8.9999f) == -9); + testlib_test_assert("floor(-8.0001) == -9", vnl_math_floor(-8.0001) == -9); + testlib_test_assert("floor(-8.0001f) == -9", vnl_math_floor(-8.0001f) == -9); + + testlib_test_assert("floor(9.0) == 9", vnl_math_floor(9.0) == 9); + testlib_test_assert("floor(9.0f) == 9", vnl_math_floor(9.0f) == 9); + testlib_test_assert("floor(9.9999) == 9", vnl_math_floor(9.9999) == 9); + testlib_test_assert("floor(9.9999f) == 9", vnl_math_floor(9.9999f) == 9); + testlib_test_assert("floor(9.0001) == 9", vnl_math_floor(9.0001) == 9); + testlib_test_assert("floor(9.0001f) == 9", vnl_math_floor(9.0001f) == 9); + testlib_test_assert("floor(-9.0) == -9", vnl_math_floor(-9.0) == -9); + testlib_test_assert("floor(-9.0f) == -9", vnl_math_floor(-9.0f) == -9); + testlib_test_assert("floor(-9.9999) == -10", vnl_math_floor(-9.9999) == -10); + testlib_test_assert("floor(-9.9999f) == -10", vnl_math_floor(-9.9999f) == -10); + testlib_test_assert("floor(-9.0001) == -10", vnl_math_floor(-9.0001) == -10); + testlib_test_assert("floor(-9.0001f) == -10", vnl_math_floor(-9.0001f) == -10); + + testlib_test_assert("ceil(8.0) == 8", vnl_math_ceil(8.0) == 8); + testlib_test_assert("ceil(8.0f) == 8", vnl_math_ceil(8.0f) == 8); + testlib_test_assert("ceil(8.9999) == 9", vnl_math_ceil(8.9999) == 9); + testlib_test_assert("ceil(8.9999f) == 9", vnl_math_ceil(8.9999f) == 9); + testlib_test_assert("ceil(8.0001) == 9", vnl_math_ceil(8.0001) == 9); + testlib_test_assert("ceil(8.0001f) == 9", vnl_math_ceil(8.0001f) == 9); + testlib_test_assert("ceil(-8.0) == -8", vnl_math_ceil(-8.0) == -8); + testlib_test_assert("ceil(-8.0f) == -8", vnl_math_ceil(-8.0f) == -8); + testlib_test_assert("ceil(-8.9999) == -8", vnl_math_ceil(-8.9999) == -8); + testlib_test_assert("ceil(-8.9999f) == -8", vnl_math_ceil(-8.9999f) == -8); + testlib_test_assert("ceil(-8.0001) == -8", vnl_math_ceil(-8.0001) == -8); + testlib_test_assert("ceil(-8.0001f) == -8", vnl_math_ceil(-8.0001f) == -8); + + testlib_test_assert("ceil(9.0) == 9", vnl_math_ceil(9.0) == 9); + testlib_test_assert("ceil(9.0f) == 9", vnl_math_ceil(9.0f) == 9); + testlib_test_assert("ceil(9.9999) == 10", vnl_math_ceil(9.9999) == 10); + testlib_test_assert("ceil(9.9999f) == 10", vnl_math_ceil(9.9999f) == 10); + testlib_test_assert("ceil(9.0001) == 10", vnl_math_ceil(9.0001) == 10); + testlib_test_assert("ceil(9.0001f) == 10", vnl_math_ceil(9.0001f) == 10); + testlib_test_assert("ceil(-9.0) == -9", vnl_math_ceil(-9.0) == -9); + testlib_test_assert("ceil(-9.0f) == -9", vnl_math_ceil(-9.0f) == -9); + testlib_test_assert("ceil(-9.9999) == -9", vnl_math_ceil(-9.9999) == -9); + testlib_test_assert("ceil(-9.9999f) == -9", vnl_math_ceil(-9.9999f) == -9); + testlib_test_assert("ceil(-9.0001) == -9", vnl_math_ceil(-9.0001) == -9); + testlib_test_assert("ceil(-9.0001f) == -9", vnl_math_ceil(-9.0001f) == -9); testlib_test_assert(" isfinite(f) ", vnl_math_isfinite(f)); testlib_test_assert(" isfinite(d) ", vnl_math_isfinite(d)); itk-portable-round-2009-05-26-bis.patch [^] (34,310 bytes) 2009-05-26 08:48 [Show Content] [Hide Content] ? Code/Algorithms/itkMultiResolutionPDEDeformableRegistration.txx-old ? Code/Algorithms/itkMultiResolutionPyramidImageFilter.txx-old ? Code/Algorithms/itkNCCRegistrationFunction.h-old ? Code/Algorithms/itkNCCRegistrationFunction.txx-old ? Code/Algorithms/itkRecursiveMultiResolutionPyramidImageFilter.txx-old ? Testing/Code/Algorithms/itkMultiResolutionPyramidImageFilterTest.cxx-old ? Testing/Code/Algorithms/itkRecursiveMultiResolutionPyramidImageFilterTest.cxx-old Index: CMakeLists.txt =================================================================== RCS file: /cvsroot/Insight/Insight/CMakeLists.txt,v retrieving revision 1.341 diff -u -r1.341 CMakeLists.txt --- CMakeLists.txt 24 May 2009 21:05:08 -0000 1.341 +++ CMakeLists.txt 26 May 2009 12:28:33 -0000 @@ -261,19 +261,10 @@ #----------------------------------------------------------------------------- # ITK turn on the correct usage of centered-pixel coordinates. -OPTION(ITK_USE_PORTABLE_ROUND "Turn on round implementation that works in multiple-platforms." OFF) -MARK_AS_ADVANCED(ITK_USE_PORTABLE_ROUND) - - -#----------------------------------------------------------------------------- -# ITK turn on the correct usage of centered-pixel coordinates. OPTION(ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY "Turn on correct usage of centered-pixel coordinates." OFF) MARK_AS_ADVANCED(ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY) IF(ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY) MESSAGE("Attention: You enabled ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY This feature has not been fully tested and validated.") - IF(NOT ITK_USE_PORTABLE_ROUND) - MESSAGE(FATAL_ERROR "ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY is currently ON but ITK_USE_PORTABLE_ROUND is OFF, you should enable the portable round") - ENDIF(NOT ITK_USE_PORTABLE_ROUND) ENDIF(ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY) Index: itkConfigure.h.in =================================================================== RCS file: /cvsroot/Insight/Insight/itkConfigure.h.in,v retrieving revision 1.32 diff -u -r1.32 itkConfigure.h.in --- itkConfigure.h.in 7 May 2009 14:03:33 -0000 1.32 +++ itkConfigure.h.in 26 May 2009 12:28:33 -0000 @@ -85,7 +85,6 @@ #cmakedefine ITK_USE_ORIENTED_IMAGE_DIRECTION #cmakedefine ITK_IMAGE_BEHAVES_AS_ORIENTED_IMAGE #cmakedefine ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY -#cmakedefine ITK_USE_PORTABLE_ROUND #cmakedefine ITK_USE_REGION_VALIDATION_IN_ITERATORS #cmakedefine ITK_USE_TEMPLATE_META_PROGRAMMING_LOOP_UNROLLING #cmakedefine ITK_USE_DEPRECATED_LEVELSET_INTERPOLATION Index: CMake/itkSampleBuildTest.cmake.in =================================================================== RCS file: /cvsroot/Insight/Insight/CMake/itkSampleBuildTest.cmake.in,v retrieving revision 1.10 diff -u -r1.10 itkSampleBuildTest.cmake.in --- CMake/itkSampleBuildTest.cmake.in 9 May 2009 16:14:04 -0000 1.10 +++ CMake/itkSampleBuildTest.cmake.in 26 May 2009 12:28:33 -0000 @@ -111,7 +111,6 @@ ITK_USE_PATENTED:BOOL=@ITK_USE_PATENTED@ ITK_USE_REVIEW:BOOL=@ITK_USE_REVIEW@ ITK_USE_REVIEW_STATISTICS:BOOL=@ITK_USE_REVIEW_STATISTICS@ -ITK_USE_PORTABLE_ROUND:BOOL=@ITK_USE_PORTABLE_ROUND@ ITK_USE_REGION_VALIDATION_IN_ITERATORS:BOOL=@ITK_USE_REGION_VALIDATION_IN_ITERATORS@ ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY:BOOL=@ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY@ ITK_USE_CONCEPT_CHECKING:BOOL=@ITK_USE_CONCEPT_CHECKING@ Index: Code/BasicFilters/itkBilateralImageFilter.txx =================================================================== RCS file: /cvsroot/Insight/Insight/Code/BasicFilters/itkBilateralImageFilter.txx,v retrieving revision 1.29 diff -u -r1.29 itkBilateralImageFilter.txx --- Code/BasicFilters/itkBilateralImageFilter.txx 7 Oct 2008 17:31:02 -0000 1.29 +++ Code/BasicFilters/itkBilateralImageFilter.txx 26 May 2009 12:28:33 -0000 @@ -26,28 +26,6 @@ #include "itkStatisticsImageFilter.h" -// anonymous namespace -namespace -{ -//-------------------------------------------------------------------------- -// The 'floor' function on x86 and mips is many times slower than these -// and is used a lot in this code, optimize for different CPU architectures -inline int BilateralFloor(double x) -{ -#if defined mips || defined sparc || defined __ppc__ - return (int)((unsigned int)(x + 2147483648.0) - 2147483648U); -#elif defined i386 || defined _M_IX86 - union { unsigned int hilo[2]; double d; } u; - u.d = x + 103079215104.0; - return (int)((u.hilo[1]<<16)|(u.hilo[0]>>16)); -#else - return int(floor(x)); -#endif -} - -} - - namespace itk { template< class TInputImage, class TOutputImage > @@ -327,7 +305,7 @@ { // look up the range gaussian in a table tableArg = rangeDistance * distanceToTableIndex; - rangeGaussian = m_RangeGaussianTable[BilateralFloor(tableArg)]; + rangeGaussian = m_RangeGaussianTable[itk::Math::Floor(tableArg)]; // normalization factor so filter integrates to one // (product of the domain and the range gaussian) Index: Code/Common/itkBSplineInterpolationWeightFunction.txx =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkBSplineInterpolationWeightFunction.txx,v retrieving revision 1.14 diff -u -r1.14 itkBSplineInterpolationWeightFunction.txx --- Code/Common/itkBSplineInterpolationWeightFunction.txx 21 Mar 2008 00:47:43 -0000 1.14 +++ Code/Common/itkBSplineInterpolationWeightFunction.txx 26 May 2009 12:28:34 -0000 @@ -22,27 +22,6 @@ #include "itkMatrix.h" #include "itkImageRegionConstIteratorWithIndex.h" -// anonymous namespace -namespace -{ -//-------------------------------------------------------------------------- -// The 'floor' function on x86 and mips is many times slower than these -// and is used a lot in this code, optimize for different CPU architectures -inline int BSplineFloor(double x) -{ -#if defined mips || defined sparc || defined __ppc__ - return (int)((unsigned int)(x + 2147483648.0) - 2147483648U); -#elif defined i386 || defined _M_IX86 - union { unsigned int hilo[2]; double d; } u; - u.d = x + 103079215104.0; - return (int)((u.hilo[1]<<16)|(u.hilo[0]>>16)); -#else - return int(floor(x)); -#endif -} - -} - namespace itk { @@ -147,7 +126,7 @@ for ( j = 0; j < SpaceDimension; j++ ) { startIndex[j] = static_cast<typename IndexType::IndexValueType>( - BSplineFloor( index[j] - static_cast<double>( SplineOrder - 1 ) / 2.0 ) ); + itk::Math::Floor( index[j] - static_cast<double>( SplineOrder - 1 ) / 2.0 ) ); } // Compute the weights Index: Code/Common/itkIndex.h =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkIndex.h,v retrieving revision 1.62 diff -u -r1.62 itkIndex.h --- Code/Common/itkIndex.h 17 May 2009 02:31:26 -0000 1.62 +++ Code/Common/itkIndex.h 26 May 2009 12:28:34 -0000 @@ -260,20 +260,6 @@ * Index<3> index = {5, 2, 7}; */ IndexValueType m_Index[VIndexDimension]; -#ifndef ITK_USE_PORTABLE_ROUND - // The Windows implementaton of vnl_math_rnd() does not round the - // same way as other versions. It has an assembly "fast" implementation - // but with the drawback of rounding to the closest even number. - // See: http://www.musicdsp.org/showone.php?id=170 - // For example 0.5 is rounded down to 0.0. - // This conditional code replaces the standard vnl implementation that uses - // assembler code. The code below will be slower for windows but will - // produce consistent results. This can be removed once vnl_math_rnd is - // fixed in VXL. -#if (defined (VCL_VC) && !defined(__GCCXML__)) || (defined(_MSC_VER) && (_MSC_VER <= 1310)) -#define vnl_math_rnd_halfintup(x) ((x>=0.0)?(int)(x + 0.5):(int)(x - 0.5)) -#endif -#endif /** Copy values from a FixedArray by rounding each one of the components */ template <class TCoordRep> inline void CopyWithRound( const FixedArray<TCoordRep,VIndexDimension> & point ) @@ -283,19 +269,10 @@ #else for(unsigned int i=0;i < VIndexDimension; ++i) { -#ifdef ITK_USE_PORTABLE_ROUND m_Index[i] = static_cast< IndexValueType>( itk::Math::Round( point[i] ) ); -#else - m_Index[i] = static_cast< IndexValueType>( vnl_math_rnd_halfintup( point[i] ) ); -#endif } #endif } -#ifndef ITK_USE_PORTABLE_ROUND -#if (defined (VCL_VC) && !defined(__GCCXML__)) || (defined(_MSC_VER) && (_MSC_VER <= 1310)) -#undef vnl_math_rnd_halfintup -#endif -#endif /** Copy values from a FixedArray by casting each one of the components */ template <class TCoordRep> Index: Code/Common/itkMacro.h =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkMacro.h,v retrieving revision 1.95 diff -u -r1.95 itkMacro.h --- Code/Common/itkMacro.h 17 May 2009 02:31:26 -0000 1.95 +++ Code/Common/itkMacro.h 26 May 2009 12:28:35 -0000 @@ -978,8 +978,12 @@ inline int RoundHalfIntegerUp(double x) { return vnl_math_rnd_halfintup(x); } inline int RoundHalfIntegerToEven(float x) { return vnl_math_rnd_halfinttoeven(x); } inline int RoundHalfIntegerToEven(double x) { return vnl_math_rnd_halfinttoeven(x); } -inline int Round(float x) { return RoundHalfIntegerToEven(x); } -inline int Round(double x) { return RoundHalfIntegerToEven(x); } +inline int Round(float x) { return RoundHalfIntegerUp(x); } +inline int Round(double x) { return RoundHalfIntegerUp(x); } +inline int Floor(float x) { return vnl_math_floor(x); } +inline int Floor(double x) { return vnl_math_floor(x); } +inline int Ceil(float x) { return vnl_math_ceil(x); } +inline int Ceil(double x) { return vnl_math_ceil(x); } } // end namespace Math } // end namespace itk @@ -1010,19 +1014,11 @@ // perfomed as part of the assignment, by using the DestinationElementType as // the casting type. // Source and destination array types must have defined opearator[] in their API. -#ifdef ITK_USE_PORTABLE_ROUND #define itkForLoopRoundingAndAssignmentMacro(DestinationType,Sourcrnd_halfintup,DestinationElementType,DestinationArray,SourceArray,NumberOfIterations) \ for(unsigned int i=0;i < NumberOfIterations; ++i) \ { \ DestinationArray[i] = static_cast< DestinationElementType >( itk::Math::Round( SourceArray[i] ) ); \ } -#else -#define itkForLoopRoundingAndAssignmentMacro(DestinationType,SourceType,DestinationElementType,DestinationArray,SourceArray,NumberOfIterations) \ - for(unsigned int i=0;i < NumberOfIterations; ++i) \ - { \ - DestinationArray[i] = static_cast< DestinationElementType >( itk::Math::RoundHalfIntegerUp( SourceArray[i] ) ); \ - } -#endif #endif // end of Template Meta Programming helper macros Index: Examples/Filtering/CMakeLists.txt =================================================================== RCS file: /cvsroot/Insight/Insight/Examples/Filtering/CMakeLists.txt,v retrieving revision 1.148 diff -u -r1.148 CMakeLists.txt --- Examples/Filtering/CMakeLists.txt 15 May 2009 13:36:12 -0000 1.148 +++ Examples/Filtering/CMakeLists.txt 26 May 2009 12:28:37 -0000 @@ -464,7 +464,7 @@ ${TEMP}/ResampleImageFilter3Test1PixelCentered.png ResampleImageFilter3Test ${ITK_SOURCE_DIR}/Examples/Data/BrainProtonDensitySlice.png - ${TEMP}/ResampleImageFilter3Test1Extrapolation.png + ${TEMP}/ResampleImageFilter3Test1PixelCentered.png 0 ) ELSE( ITK_USE_CENTERED_PIXEL_COORDINATES_CONSISTENTLY ) Index: Testing/Code/Common/CMakeLists.txt =================================================================== RCS file: /cvsroot/Insight/Insight/Testing/Code/Common/CMakeLists.txt,v retrieving revision 1.242 diff -u -r1.242 CMakeLists.txt --- Testing/Code/Common/CMakeLists.txt 13 May 2009 17:10:45 -0000 1.242 +++ Testing/Code/Common/CMakeLists.txt 26 May 2009 12:28:38 -0000 @@ -282,6 +282,8 @@ ADD_TEST(itkOrientedImageProfileTest2 ${COMMON_TESTS2} itkOrientedImageProfileTest2) ADD_TEST(itkOrientedImageProfileTest3 ${COMMON_TESTS2} itkOrientedImageProfileTest3) +ADD_TEST(itkMathRoundTest ${COMMON_TESTS2} itkMathRoundTest) + ADD_TEST(itkVNLRoundProfileTest1 ${COMMON_TESTS2} itkVNLRoundProfileTest1) ADD_TEST(itkMathRoundProfileTest1 ${COMMON_TESTS2} itkMathRoundProfileTest1) @@ -538,6 +540,7 @@ itkOrientedImageProfileTest2.cxx itkOrientedImageProfileTest3.cxx itkVNLRoundProfileTest1.cxx +itkMathRoundTest.cxx itkMathRoundProfileTest1.cxx itkPathFunctionsTest.cxx itkPathIteratorTest.cxx Index: Testing/Code/Common/itkCommonTests2.cxx =================================================================== RCS file: /cvsroot/Insight/Insight/Testing/Code/Common/itkCommonTests2.cxx,v retrieving revision 1.23 diff -u -r1.23 itkCommonTests2.cxx --- Testing/Code/Common/itkCommonTests2.cxx 7 May 2009 14:04:05 -0000 1.23 +++ Testing/Code/Common/itkCommonTests2.cxx 26 May 2009 12:28:38 -0000 @@ -99,6 +99,7 @@ REGISTER_TEST(itkVectorTest ); REGISTER_TEST(itkVectorInterpolateImageFunctionTest ); REGISTER_TEST(itkVectorToRGBImageAdaptorTest ); +REGISTER_TEST(itkMathRoundTest ); REGISTER_TEST(itkVNLRoundProfileTest1 ); REGISTER_TEST(itkMathRoundProfileTest1 ); REGISTER_TEST(itkWindowedSincInterpolateImageFunctionTest ); Index: Testing/Code/Common/itkMathRoundProfileTest1.cxx =================================================================== RCS file: /cvsroot/Insight/Insight/Testing/Code/Common/itkMathRoundProfileTest1.cxx,v retrieving revision 1.1 diff -u -r1.1 itkMathRoundProfileTest1.cxx --- Testing/Code/Common/itkMathRoundProfileTest1.cxx 7 May 2009 14:04:07 -0000 1.1 +++ Testing/Code/Common/itkMathRoundProfileTest1.cxx 26 May 2009 12:28:38 -0000 @@ -23,24 +23,27 @@ #include "vnl/vnl_math.h" #include <math.h> -double itkMathRoundTestHelperFunction( double x ) +int itkMathRoundTestHelperFunction( double x ) { - if( x >= 0.0 ) - { - return static_cast< int >( x + 0.5f ); - } - - return static_cast< int >( x - 0.5f ); + x+=0.5; + return static_cast<int>(x>=0.?x:(x==static_cast<int>(x)?x:x-1.)); } #define itkRoundMacro( x, y ) \ - if( x >= 0.0 ) \ + if( x >= 0.5 ) \ { \ - y = static_cast< int >( x + 0.5f ); \ + y = static_cast< int >( x + 0.5 ); \ } \ else \ { \ - y = static_cast< int >( x - 0.5f ); \ + if( (x+0.5)==static_cast<int>(x+0.5) ) \ + { \ + y = static_cast< int >( x + 0.5 ); \ + } \ + else \ + { \ + y = static_cast< int >( x - 0.5 ); \ + } \ } @@ -49,12 +52,13 @@ itk::TimeProbesCollectorBase chronometer; typedef std::vector< double > ArrayType; + typedef std::vector< int > IntArrayType; ArrayType input; - ArrayType output1; - ArrayType output2; - ArrayType output3; - ArrayType output4; + IntArrayType output1; + IntArrayType output2; + IntArrayType output3; + IntArrayType output4; const unsigned long numberOfValues = 1000000L; @@ -93,18 +97,16 @@ // Count the time of simply assigning values in an std::vector // // - ArrayType::const_iterator outItr1src = output1.begin(); - ArrayType::iterator outItr2dst = output2.begin(); + IntArrayType::const_iterator outItr1src = output1.begin(); + IntArrayType::iterator outItr2dst = output2.begin(); - ArrayType::const_iterator outEnd1 = output1.end(); + IntArrayType::const_iterator outEnd1 = output1.end(); chronometer.Start("std::vector"); while( outItr1src != outEnd1 ) { - *outItr2dst = *outItr1src; - ++outItr1src; - ++outItr2dst; + *outItr2dst++ = *outItr1src++; } chronometer.Stop("std::vector"); @@ -112,7 +114,7 @@ ArrayType::const_iterator inpItr = input.begin(); ArrayType::const_iterator inputEnd = input.end(); - ArrayType::iterator outItr1nc = output1.begin(); + IntArrayType::iterator outItr1nc = output1.begin(); // // Count the time of rounding plus storing in container @@ -121,9 +123,7 @@ while( inpItr != inputEnd ) { - *outItr1nc = itkMathRoundTestHelperFunction( *inpItr ); - ++outItr1nc; - ++inpItr; + *outItr1nc++ = itkMathRoundTestHelperFunction( *inpItr++ ); } chronometer.Stop("if-round"); @@ -132,7 +132,7 @@ inpItr = input.begin(); inputEnd = input.end(); - ArrayType::iterator outItr3nc = output3.begin(); + IntArrayType::iterator outItr3nc = output3.begin(); // // Count the time of rounding plus storing in container @@ -141,15 +141,8 @@ while( inpItr != inputEnd ) { - if( *inpItr >= 0.0 ) - { - *outItr3nc = static_cast< int >( *inpItr + 0.5f ); - } - - *outItr3nc = static_cast< int >( *inpItr - 0.5f ); - - ++outItr3nc; - ++inpItr; + const double x = (*inpItr++) + 0.5; + *outItr3nc++ = static_cast<int>(x>=0.?x:(x==static_cast<int>(x)?x:x-1.)); } chronometer.Stop("Functor"); @@ -157,7 +150,7 @@ inpItr = input.begin(); inputEnd = input.end(); - ArrayType::iterator outItr4nc = output4.begin(); + IntArrayType::iterator outItr4nc = output4.begin(); // // Count the time of rounding plus storing in container @@ -167,8 +160,8 @@ while( inpItr != inputEnd ) { itkRoundMacro(*inpItr, *outItr4nc ); - ++outItr4nc; ++inpItr; + ++outItr4nc; } chronometer.Stop("Macro"); @@ -177,7 +170,7 @@ inpItr = input.begin(); inputEnd = input.end(); - ArrayType::iterator outItr = output2.begin(); + IntArrayType::iterator outItr = output2.begin(); // // Count the time of rounding plus storing in container @@ -186,9 +179,7 @@ while( inpItr != inputEnd ) { - *outItr = itk::Math::Round( *inpItr ); - ++outItr; - ++inpItr; + *outItr++ = itk::Math::Round( *inpItr++ ); } chronometer.Stop("itk::Math::Round"); @@ -203,12 +194,9 @@ ArrayType::const_iterator inpItr = input.begin(); ArrayType::const_iterator inputEnd = input.end(); - ArrayType::const_iterator outItr1 = output1.begin(); - ArrayType::const_iterator outItr2 = output2.begin(); - - const double tolerance = 1e-5; - - bool roundUp = true; + IntArrayType::const_iterator outItr1 = output1.begin(); + IntArrayType::const_iterator outItr2 = output2.begin(); + bool roundMismatch = false; std::cout << std::endl; @@ -216,17 +204,11 @@ while( inpItr != inputEnd ) { - if( vnl_math_abs( *outItr1 - *outItr2 ) > tolerance ) + if( (*outItr1) != (*outItr2) ) { std::cout << "Warning*** For input: " << *inpItr << " if-round: " << *outItr1 << " differs from itk::Math::Round: " << *outItr2 << std::endl; - if ((static_cast<int>(*outItr2) % 2) == 0) - { - roundUp = false; - } - else - { - roundMismatch = true; - } + + roundMismatch = true; } ++inpItr; ++outItr1; @@ -237,23 +219,9 @@ std::cout << "Tested " << output1.size() << " entries " << std::endl; std::cout << std::endl; - if (!roundMismatch) - { - if( roundUp) - { - std::cout << "******* On this platform, itk::Math::Round() rounds up ********" << std::endl; - } - else - { - std::cout << "******* On this platform, itk::Math::Round() rounds to even ********" << std::endl; - } - } - else - { - std::cout << "******* On this platform, itk::Math::Round() neither rounds up nor rounds to even consistently ********" << std::endl; - } if (roundMismatch) { + std::cout << "******* On this platform, itk::Math::Round() does not rounds half integers upward ********" << std::endl; return EXIT_FAILURE; } return EXIT_SUCCESS; Index: Testing/Code/Common/itkMathRoundTest.cxx =================================================================== RCS file: Testing/Code/Common/itkMathRoundTest.cxx diff -N Testing/Code/Common/itkMathRoundTest.cxx --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Testing/Code/Common/itkMathRoundTest.cxx 26 May 2009 12:28:38 -0000 @@ -0,0 +1,176 @@ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkMathRoundTest.cxx,v $ + Language: C++ + Date: $Date: 2009-05-07 14:04:07 $ + Version: $Revision: 1.1 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/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 notices for more information. + +=========================================================================*/ +#if defined(_MSC_VER) +#pragma warning ( disable : 4786 ) +#endif + +#include "itkMacro.h" +#include <math.h> + +bool math_test_helper(std::string str, bool test) +{ + if (!test) + { + std::cout<<"test ("<<str<<") failed"<<std::endl; + } + return test; +} + +int itkMathRoundTest( int, char *[] ) +{ + bool ok = true; + + ok &= math_test_helper("rnd(-8.4999) == -8", itk::Math::Round(-8.4999) == -8); + ok &= math_test_helper("rnd(-8.4999f) == -8", itk::Math::Round(-8.4999f) == -8); + ok &= math_test_helper("rnd(-8.50) == -8", itk::Math::Round(-8.50) == -8); + ok &= math_test_helper("rnd(-8.50f) == -8", itk::Math::Round(-8.50f) == -8); + ok &= math_test_helper("rnd(-8.5001) == -9", itk::Math::Round(-8.5001) == -9); + ok &= math_test_helper("rnd(-8.5001f) == -9", itk::Math::Round(-8.5001f) == -9); + ok &= math_test_helper("rnd(8.4999) == 8", itk::Math::Round(8.4999) == 8); + ok &= math_test_helper("rnd(8.4999f) == 8", itk::Math::Round(8.4999f) == 8); + ok &= math_test_helper("rnd(8.50) == 8", itk::Math::Round(8.50) == 9); + ok &= math_test_helper("rnd(8.50f) == 8", itk::Math::Round(8.50f) == 9); + ok &= math_test_helper("rnd(8.5001) == 9", itk::Math::Round(8.5001) == 9); + ok &= math_test_helper("rnd(8.5001f) == 9", itk::Math::Round(8.5001f) == 9); + + ok &= math_test_helper("rnd(-9.4999) == -9 ", itk::Math::Round(-9.4999) == -9); + ok &= math_test_helper("rnd(-9.4999f) == -9 ", itk::Math::Round(-9.4999f) == -9); + ok &= math_test_helper("rnd(-9.50) == -9 ", itk::Math::Round(-9.50) == -9); + ok &= math_test_helper("rnd(-9.50f) == -9 ", itk::Math::Round(-9.50f) == -9); + ok &= math_test_helper("rnd(-9.5001) == -10", itk::Math::Round(-9.5001) == -10); + ok &= math_test_helper("rnd(-9.5001f) == -10", itk::Math::Round(-9.5001f) == -10); + ok &= math_test_helper("rnd(9.4999) == 9 ", itk::Math::Round(9.4999) == 9); + ok &= math_test_helper("rnd(9.4999f) == 9 ", itk::Math::Round(9.4999f) == 9); + ok &= math_test_helper("rnd(9.50) == 9 ", itk::Math::Round(9.50) == 10); + ok &= math_test_helper("rnd(9.50f) == 9 ", itk::Math::Round(9.50f) == 10); + ok &= math_test_helper("rnd(9.5001) == 10", itk::Math::Round(9.5001) == 10); + ok &= math_test_helper("rnd(9.5001f) == 10", itk::Math::Round(9.5001f) == 10); + + ok &= math_test_helper("rnd_halfinttoeven(-8.4999) == -8", itk::Math::RoundHalfIntegerToEven(-8.4999) == -8); + ok &= math_test_helper("rnd_halfinttoeven(-8.4999f) == -8", itk::Math::RoundHalfIntegerToEven(-8.4999f)== -8); + ok &= math_test_helper("rnd_halfinttoeven(-8.50) == -8", itk::Math::RoundHalfIntegerToEven(-8.50) == -8); + ok &= math_test_helper("rnd_halfinttoeven(-8.50f) == -8", itk::Math::RoundHalfIntegerToEven(-8.50f) == -8); + ok &= math_test_helper("rnd_halfinttoeven(-8.5001) == -9", itk::Math::RoundHalfIntegerToEven(-8.5001) == -9); + ok &= math_test_helper("rnd_halfinttoeven(-8.5001f) == -9", itk::Math::RoundHalfIntegerToEven(-8.5001f)== -9); + ok &= math_test_helper("rnd_halfinttoeven(8.4999) == 8", itk::Math::RoundHalfIntegerToEven(8.4999) == 8); + ok &= math_test_helper("rnd_halfinttoeven(8.4999f) == 8", itk::Math::RoundHalfIntegerToEven(8.4999f) == 8); + ok &= math_test_helper("rnd_halfinttoeven(8.50) == 9", itk::Math::RoundHalfIntegerToEven(8.50) == 8); + ok &= math_test_helper("rnd_halfinttoeven(8.50f) == 9", itk::Math::RoundHalfIntegerToEven(8.50f) == 8); + ok &= math_test_helper("rnd_halfinttoeven(8.5001) == 9", itk::Math::RoundHalfIntegerToEven(8.5001) == 9); + ok &= math_test_helper("rnd_halfinttoeven(8.5001f) == 9", itk::Math::RoundHalfIntegerToEven(8.5001f) == 9); + + ok &= math_test_helper("rnd_halfinttoeven(-9.4999) == -9 ", itk::Math::RoundHalfIntegerToEven(-9.4999) == -9); + ok &= math_test_helper("rnd_halfinttoeven(-9.4999f) == -9 ", itk::Math::RoundHalfIntegerToEven(-9.4999f)== -9); + ok &= math_test_helper("rnd_halfinttoeven(-9.50) == -9 ", itk::Math::RoundHalfIntegerToEven(-9.50) == -10); + ok &= math_test_helper("rnd_halfinttoeven(-9.50f) == -9 ", itk::Math::RoundHalfIntegerToEven(-9.50f) == -10); + ok &= math_test_helper("rnd_halfinttoeven(-9.5001) == -10", itk::Math::RoundHalfIntegerToEven(-9.5001) == -10); + ok &= math_test_helper("rnd_halfinttoeven(-9.5001f) == -10", itk::Math::RoundHalfIntegerToEven(-9.5001f)== -10); + ok &= math_test_helper("rnd_halfinttoeven(9.4999) == 9 ", itk::Math::RoundHalfIntegerToEven(9.4999) == 9); + ok &= math_test_helper("rnd_halfinttoeven(9.4999f) == 9 ", itk::Math::RoundHalfIntegerToEven(9.4999f) == 9); + ok &= math_test_helper("rnd_halfinttoeven(9.50) == 10", itk::Math::RoundHalfIntegerToEven(9.50) == 10); + ok &= math_test_helper("rnd_halfinttoeven(9.50f) == 10", itk::Math::RoundHalfIntegerToEven(9.50f) == 10); + ok &= math_test_helper("rnd_halfinttoeven(9.5001) == 10", itk::Math::RoundHalfIntegerToEven(9.5001) == 10); + ok &= math_test_helper("rnd_halfinttoeven(9.5001f) == 10", itk::Math::RoundHalfIntegerToEven(9.5001f) == 10); + + ok &= math_test_helper("rnd_halfintup(-8.4999) == -8", itk::Math::RoundHalfIntegerUp(-8.4999) == -8); + ok &= math_test_helper("rnd_halfintup(-8.4999f) == -8", itk::Math::RoundHalfIntegerUp(-8.4999f)== -8); + ok &= math_test_helper("rnd_halfintup(-8.50) == -8", itk::Math::RoundHalfIntegerUp(-8.50) == -8); + ok &= math_test_helper("rnd_halfintup(-8.50f) == -8", itk::Math::RoundHalfIntegerUp(-8.50f) == -8); + ok &= math_test_helper("rnd_halfintup(-8.5001) == -9", itk::Math::RoundHalfIntegerUp(-8.5001) == -9); + ok &= math_test_helper("rnd_halfintup(-8.5001f) == -9", itk::Math::RoundHalfIntegerUp(-8.5001f)== -9); + ok &= math_test_helper("rnd_halfintup(8.4999) == 8", itk::Math::RoundHalfIntegerUp(8.4999) == 8); + ok &= math_test_helper("rnd_halfintup(8.4999f) == 8", itk::Math::RoundHalfIntegerUp(8.4999f) == 8); + ok &= math_test_helper("rnd_halfintup(8.50) == 9", itk::Math::RoundHalfIntegerUp(8.50) == 9); + ok &= math_test_helper("rnd_halfintup(8.50f) == 9", itk::Math::RoundHalfIntegerUp(8.50f) == 9); + ok &= math_test_helper("rnd_halfintup(8.5001) == 9", itk::Math::RoundHalfIntegerUp(8.5001) == 9); + ok &= math_test_helper("rnd_halfintup(8.5001f) == 9", itk::Math::RoundHalfIntegerUp(8.5001f) == 9); + + ok &= math_test_helper("rnd_halfintup(-9.4999) == -9 ", itk::Math::RoundHalfIntegerUp(-9.4999) == -9); + ok &= math_test_helper("rnd_halfintup(-9.4999f) == -9 ", itk::Math::RoundHalfIntegerUp(-9.4999f)== -9); + ok &= math_test_helper("rnd_halfintup(-9.50) == -9 ", itk::Math::RoundHalfIntegerUp(-9.50) == -9); + ok &= math_test_helper("rnd_halfintup(-9.50f) == -9 ", itk::Math::RoundHalfIntegerUp(-9.50f) == -9); + ok &= math_test_helper("rnd_halfintup(-9.5001) == -10", itk::Math::RoundHalfIntegerUp(-9.5001) == -10); + ok &= math_test_helper("rnd_halfintup(-9.5001f) == -10", itk::Math::RoundHalfIntegerUp(-9.5001f)== -10); + ok &= math_test_helper("rnd_halfintup(9.4999) == 9 ", itk::Math::RoundHalfIntegerUp(9.4999) == 9); + ok &= math_test_helper("rnd_halfintup(9.4999f) == 9 ", itk::Math::RoundHalfIntegerUp(9.4999f) == 9); + ok &= math_test_helper("rnd_halfintup(9.50) == 10", itk::Math::RoundHalfIntegerUp(9.50) == 10); + ok &= math_test_helper("rnd_halfintup(9.50f) == 10", itk::Math::RoundHalfIntegerUp(9.50f) == 10); + ok &= math_test_helper("rnd_halfintup(9.5001) == 10", itk::Math::RoundHalfIntegerUp(9.5001) == 10); + ok &= math_test_helper("rnd_halfintup(9.5001f) == 10", itk::Math::RoundHalfIntegerUp(9.5001f) == 10); + + ok &= math_test_helper("floor(8.0) == 8", itk::Math::Floor(8.0) == 8); + ok &= math_test_helper("floor(8.0f) == 8", itk::Math::Floor(8.0f) == 8); + ok &= math_test_helper("floor(8.9999) == 8", itk::Math::Floor(8.9999) == 8); + ok &= math_test_helper("floor(8.9999f) == 8", itk::Math::Floor(8.9999f) == 8); + ok &= math_test_helper("floor(8.0001) == 8", itk::Math::Floor(8.0001) == 8); + ok &= math_test_helper("floor(8.0001f) == 8", itk::Math::Floor(8.0001f) == 8); + ok &= math_test_helper("floor(-8.0) == -8", itk::Math::Floor(-8.0) == -8); + ok &= math_test_helper("floor(-8.0f) == -8", itk::Math::Floor(-8.0f) == -8); + ok &= math_test_helper("floor(-8.9999) == -9", itk::Math::Floor(-8.9999) == -9); + ok &= math_test_helper("floor(-8.9999f) == -9", itk::Math::Floor(-8.9999f) == -9); + ok &= math_test_helper("floor(-8.0001) == -9", itk::Math::Floor(-8.0001) == -9); + ok &= math_test_helper("floor(-8.0001f) == -9", itk::Math::Floor(-8.0001f) == -9); + + ok &= math_test_helper("floor(9.0) == 9 ", itk::Math::Floor(9.0) == 9); + ok &= math_test_helper("floor(9.0f) == 9 ", itk::Math::Floor(9.0f) == 9); + ok &= math_test_helper("floor(9.9999) == 9 ", itk::Math::Floor(9.9999) == 9); + ok &= math_test_helper("floor(9.9999f) == 9 ", itk::Math::Floor(9.9999f) == 9); + ok &= math_test_helper("floor(9.0001) == 9 ", itk::Math::Floor(9.0001) == 9); + ok &= math_test_helper("floor(9.0001f) == 9 ", itk::Math::Floor(9.0001f) == 9); + ok &= math_test_helper("floor(-9.0) == -9 ", itk::Math::Floor(-9.0) == -9); + ok &= math_test_helper("floor(-9.0f) == -9 ", itk::Math::Floor(-9.0f) == -9); + ok &= math_test_helper("floor(-9.9999) == -10", itk::Math::Floor(-9.9999) == -10); + ok &= math_test_helper("floor(-9.9999f) == -10", itk::Math::Floor(-9.9999f) == -10); + ok &= math_test_helper("floor(-9.0001) == -10", itk::Math::Floor(-9.0001) == -10); + ok &= math_test_helper("floor(-9.0001f) == -10", itk::Math::Floor(-9.0001f) == -10); + + ok &= math_test_helper("ceil(8.0) == 8", itk::Math::Ceil(8.0) == 8); + ok &= math_test_helper("ceil(8.0f) == 8", itk::Math::Ceil(8.0f) == 8); + ok &= math_test_helper("ceil(8.9999) == 9", itk::Math::Ceil(8.9999) == 9); + ok &= math_test_helper("ceil(8.9999f) == 9", itk::Math::Ceil(8.9999f) == 9); + ok &= math_test_helper("ceil(8.0001) == 9", itk::Math::Ceil(8.0001) == 9); + ok &= math_test_helper("ceil(8.0001f) == 9", itk::Math::Ceil(8.0001f) == 9); + ok &= math_test_helper("ceil(-8.0) == -8", itk::Math::Ceil(-8.0) == -8); + ok &= math_test_helper("ceil(-8.0f) == -8", itk::Math::Ceil(-8.0f) == -8); + ok &= math_test_helper("ceil(-8.9999) == -8", itk::Math::Ceil(-8.9999) == -8); + ok &= math_test_helper("ceil(-8.9999f) == -8", itk::Math::Ceil(-8.9999f) == -8); + ok &= math_test_helper("ceil(-8.0001) == -8", itk::Math::Ceil(-8.0001) == -8); + ok &= math_test_helper("ceil(-8.0001f) == -8", itk::Math::Ceil(-8.0001f) == -8); + + ok &= math_test_helper("ceil(9.0) == 9 ", itk::Math::Ceil(9.0) == 9); + ok &= math_test_helper("ceil(9.0f) == 9 ", itk::Math::Ceil(9.0f) == 9); + ok &= math_test_helper("ceil(9.9999) == 10", itk::Math::Ceil(9.9999) == 10); + ok &= math_test_helper("ceil(9.9999f) == 10", itk::Math::Ceil(9.9999f) == 10); + ok &= math_test_helper("ceil(9.0001) == 10", itk::Math::Ceil(9.0001) == 10); + ok &= math_test_helper("ceil(9.0001f) == 10", itk::Math::Ceil(9.0001f) == 10); + ok &= math_test_helper("ceil(-9.0) == -9 ", itk::Math::Ceil(-9.0) == -9); + ok &= math_test_helper("ceil(-9.0f) == -9 ", itk::Math::Ceil(-9.0f) == -9); + ok &= math_test_helper("ceil(-9.9999) == -9 ", itk::Math::Ceil(-9.9999) == -9); + ok &= math_test_helper("ceil(-9.9999f) == -9 ", itk::Math::Ceil(-9.9999f) == -9); + ok &= math_test_helper("ceil(-9.0001) == -9 ", itk::Math::Ceil(-9.0001) == -9); + ok &= math_test_helper("ceil(-9.0001f) == -9 ", itk::Math::Ceil(-9.0001f) == -9); + + if (!ok) + { + return EXIT_FAILURE; + } + else + { + std::cout<<"Test passed"<<std::endl; + return EXIT_SUCCESS; + } +} Index: Utilities/vxl/core/vnl/vnl_math.h =================================================================== RCS file: /cvsroot/Insight/Insight/Utilities/vxl/core/vnl/vnl_math.h,v retrieving revision 1.11 diff -u -r1.11 vnl_math.h --- Utilities/vxl/core/vnl/vnl_math.h 21 May 2009 18:28:37 -0000 1.11 +++ Utilities/vxl/core/vnl/vnl_math.h 26 May 2009 12:28:40 -0000 @@ -54,9 +54,9 @@ #else # define USE_SSE2_IMPL 0 #endif -// Turn on fast impl when using GCC with the following exception: -// GCCXML, PPC, PPC64 -#if defined(__GNUC__) && (!defined(__GCCXML__)) && (!defined(__ppc__)) && (!defined(__ppc64__)) +// Turn on fast impl when using GCC on x86 platform with the following exception: +// GCCXML +#if defined(__GNUC__) && (!defined(__GCCXML__)) && (defined(__i386__) || defined(__i386) || defined(__x86_64__) || defined(__x86_64)) # define GCC_USE_FAST_IMPL 1 #else # define GCC_USE_FAST_IMPL 0 itk-templatedmathround-2009-07-27.patch [^] (42,410 bytes) 2009-07-27 12:48 [Show Content] [Hide Content] Index: Code/Common/itkMacro.h =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkMacro.h,v retrieving revision 1.97 diff -u -r1.97 itkMacro.h --- Code/Common/itkMacro.h 16 Jun 2009 07:58:46 -0000 1.97 +++ Code/Common/itkMacro.h 27 Jul 2009 16:12:05 -0000 @@ -32,6 +32,7 @@ #include "itkWin32Header.h" #include "itkConfigure.h" +#include "itkMath.h" #include <string> #include <cstdlib> @@ -39,8 +40,6 @@ #include <cassert> #endif -#include "vnl/vnl_math.h" - // Determine type of string stream to use. #if !defined(CMAKE_NO_ANSI_STRING_STREAM) # include <sstream> @@ -970,24 +969,6 @@ #endif -namespace itk -{ -namespace Math -{ -inline int RoundHalfIntegerUp(float x) { return vnl_math_rnd_halfintup(x); } -inline int RoundHalfIntegerUp(double x) { return vnl_math_rnd_halfintup(x); } -inline int RoundHalfIntegerToEven(float x) { return vnl_math_rnd_halfinttoeven(x); } -inline int RoundHalfIntegerToEven(double x) { return vnl_math_rnd_halfinttoeven(x); } -inline int Round(float x) { return RoundHalfIntegerUp(x); } -inline int Round(double x) { return RoundHalfIntegerUp(x); } -inline int Floor(float x) { return vnl_math_floor(x); } -inline int Floor(double x) { return vnl_math_floor(x); } -inline int Ceil(float x) { return vnl_math_ceil(x); } -inline int Ceil(double x) { return vnl_math_ceil(x); } -} // end namespace Math -} // end namespace itk - - #ifdef ITK_USE_TEMPLATE_META_PROGRAMMING_LOOP_UNROLLING //-------------------------------------------------------------------------------- // Helper macros for Template Meta-Programming techniques of for-loops unrolling Index: Code/Common/itkMath.h =================================================================== RCS file: Code/Common/itkMath.h diff -N Code/Common/itkMath.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Code/Common/itkMath.h 27 Jul 2009 16:12:05 -0000 @@ -0,0 +1,362 @@ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkMath.h,v $ + Language: C++ + Date: $Date: 2009-07-27 07:58:46 $ + Version: $Revision: 1.0 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/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 notices for more information. + +=========================================================================*/ +/** + * itkMath.h defines some simple math tools such as round floor and ceil + */ + +#ifndef __itkMath_h +#define __itkMath_h + +#include "vnl/vnl_math.h" + + +namespace itk +{ +namespace Math +{ + +namespace Detail +{ +// The functions defined in this namespace are not meant to be used directly +// Please use the functions from the itk::Math namespace + + +// Vanilla versions + +template <typename TReturn, typename TInput> +inline TReturn RoundHalfIntegerToEven_base(TInput x) +{ + if (x>=static_cast<TInput>(0)) x+=static_cast<TInput>(0.5); + else x-=static_cast<TInput>(0.5); + + const TReturn r = static_cast<TReturn>(x); + return (x!=static_cast<TInput>(r)) ? r : static_cast<TReturn>(2*r/2); +} + +template <typename TReturn, typename TInput> +inline TReturn RoundHalfIntegerUp_base(TInput x) +{ + x+=0.5; + const TReturn r = static_cast<TReturn>(x); + return (r>=static_cast<TReturn>(0)) ? + r : + (x==static_cast<TInput>(r) ? r : r-static_cast<TReturn>(1)); +} + +template <typename TReturn, typename TInput> +inline TReturn Floor_base(TInput x) +{ + const TReturn r = static_cast<TReturn>(x); + return (x>=static_cast<TInput>(0)) ? + r : + (x==static_cast<TInput>(r) ? r : r-static_cast<TReturn>(1)); +} + +template <typename TReturn, typename TInput> +inline TReturn Ceil_base(TInput x) +{ + const TReturn r = static_cast<TReturn>(x); + return (x<static_cast<TInput>(0)) ? + r : + (x==static_cast<TInput>(r) ? r : r+static_cast<TReturn>(1)); +} + + +// 32 bits versions + +// Figure out when the fast implementation can be used + +// Turn on 32-bit sse2 impl if asked for +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING && defined(__SSE2__) && (!defined(__GCCXML__)) +# define USE_SSE2_32IMPL 1 +#else +# define USE_SSE2_32IMPL 0 +#endif +// Turn on 32-bit asm impl when using GCC on x86 platform with the following exception: +// GCCXML +#if defined(__GNUC__) && (!defined(__GCCXML__)) && (defined(__i386__) || defined(__i386) || defined(__x86_64__) || defined(__x86_64)) +# define GCC_USE_ASM_32IMPL 1 +#else +# define GCC_USE_ASM_32IMPL 0 +#endif +// Turn on 32-bit asm impl when using msvc on 32 bits windows +#if defined(VCL_VC) && (!defined(__GCCXML__)) && !defined(_WIN64) +# define VC_USE_ASM_32IMPL 1 +#else +# define VC_USE_ASM_32IMPL 0 +#endif + +#if USE_SSE2_32IMPL // sse2 implementation + +inline vxl_int_32 RoundHalfIntegerToEven_32(double x) { return _mm_cvtsd_si32(_mm_set_sd(x)); } +inline vxl_int_32 RoundHalfIntegerToEven_32(float x) { return _mm_cvtss_si32(_mm_set_ss(x)); } + +#elif GCC_USE_ASM_32IMPL // gcc asm implementation + +inline vxl_int_32 RoundHalfIntegerToEven_32(double x) +{ + vxl_int_32 r; + __asm__ __volatile__( "fistpl %0" : "=m"(r) : "t"(x) : "st" ); + return r; +} + +inline vxl_int_32 RoundHalfIntegerToEven_32(float x) +{ + vxl_int_32 r; + __asm__ __volatile__( "fistpl %0" : "=m"(r) : "t"(x) : "st" ); + return r; +} + +#elif VC_USE_ASM_32IMPL // msvc asm implementation + +inline vxl_int_32 RoundHalfIntegerToEven_32(double x) +{ + vxl_int_32 r; + __asm { + fld x + fistp r + } + return r; +} + +inline vxl_int_32 RoundHalfIntegerToEven_32(float x) +{ + vxl_int_32 r; + __asm { + fld x + fistp r + } + return r; +} + +#else // Vanilla implementation + +inline vxl_int_32 RoundHalfIntegerToEven_32(double x) { return RoundHalfIntegerToEven_base<vxl_int_32,double>(x); } +inline vxl_int_32 RoundHalfIntegerToEven_32(float x) { return RoundHalfIntegerToEven_base<vxl_int_32,float>(x); } + +#endif + + +#if USE_SSE2_32IMPL || GCC_USE_ASM_32IMPL || VC_USE_ASM_32IMPL + +inline vxl_int_32 RoundHalfIntegerUp_32(double x) { return RoundHalfIntegerToEven_32(2*x+0.5)>>1; } +inline vxl_int_32 RoundHalfIntegerUp_32(float x) { return RoundHalfIntegerToEven_32(2*x+0.5f)>>1; } + +#else // Vanilla implementation + +inline vxl_int_32 RoundHalfIntegerUp_32(double x) { return RoundHalfIntegerUp_base<vxl_int_32,double>(x); } +inline vxl_int_32 RoundHalfIntegerUp_32(float x) { return RoundHalfIntegerUp_base<vxl_int_32,float>(x); } + +#endif + + +#if USE_SSE2_32IMPL || GCC_USE_ASM_32IMPL || VC_USE_ASM_32IMPL + +inline vxl_int_32 Floor_32(double x) { return RoundHalfIntegerToEven_32(2*x-0.5)>>1; } +inline vxl_int_32 Floor_32(float x) { return RoundHalfIntegerToEven_32(2*x-0.5f)>>1; } + +#else // Vanilla implementation + +inline vxl_int_32 Floor_32(double x) { return Floor_base<vxl_int_32,double>(x); } +inline vxl_int_32 Floor_32(float x) { return Floor_base<vxl_int_32,float>(x); } + +#endif + + +#if USE_SSE2_32IMPL || GCC_USE_ASM_32IMPL || VC_USE_ASM_32IMPL + +inline vxl_int_32 Ceil_32(double x) { return -(RoundHalfIntegerToEven_32(-0.5-2*x)>>1); } +inline vxl_int_32 Ceil_32(float x) { return -(RoundHalfIntegerToEven_32(-0.5f-2*x)>>1); } + +#else // Vanilla implementation + +inline vxl_int_32 Ceil_32(double x) { return Ceil_base<vxl_int_32,double>(x); } +inline vxl_int_32 Ceil_32(float x) { return Ceil_base<vxl_int_32,float>(x); } + +#endif + + +#undef USE_SSE2_32IMPL +#undef GCC_USE_ASM_32IMPL +#undef VC_USE_ASM_32IMPL + + +// 64 bits versions + +// Figure out when the fast implementation can be used + +// Turn on 64-bit sse2 impl on 64-bit architectures if asked for +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING && defined(__SSE2__) && (defined(__x86_64) || defined(__x86_64__) || defined(_M_X64)) && (!defined(__GCCXML__)) +# define USE_SSE2_64IMPL 1 +#else +# define USE_SSE2_64IMPL 0 +#endif +// Turn on 64-bit asm impl when using GCC on x86 platform with the following exception: +// GCCXML +#if defined(__GNUC__) && (!defined(__GCCXML__)) && (defined(__i386__) || defined(__i386) || defined(__x86_64__) || defined(__x86_64)) +# define GCC_USE_ASM_64IMPL 1 +#else +# define GCC_USE_ASM_64IMPL 0 +#endif +// Turn on 64-bit asm impl when using msvc on 32 bits windows +#if defined(VCL_VC) && (!defined(__GCCXML__)) && !defined(_WIN64) +# define VC_USE_ASM_64IMPL 1 +#else +# define VC_USE_ASM_64IMPL 0 +#endif + +#if USE_SSE2_64IMPL // sse2 implementation + +inline vxl_int_64 RoundHalfIntegerToEven_64(double x) { return _mm_cvtsd_si64(_mm_set_sd(x)); } +inline vxl_int_64 RoundHalfIntegerToEven_64(float x) { return _mm_cvtsd_si64(_mm_set_ss(x)); } + +#elif GCC_USE_ASM_64IMPL // gcc asm implementation + +inline vxl_int_64 RoundHalfIntegerToEven_64(double x) +{ + vxl_int_64 r; + __asm__ __volatile__( "fistpll %0" : "=m"(r) : "t"(x) : "st" ); + return r; +} + +inline vxl_int_64 RoundHalfIntegerToEven_64(float x) +{ + vxl_int_64 r; + __asm__ __volatile__( "fistpll %0" : "=m"(r) : "t"(x) : "st" ); + return r; +} + +#elif VC_USE_ASM_64IMPL // msvc asm implementation + +inline vxl_int_64 RoundHalfIntegerToEven_64(double x) +{ + vxl_int_64 r; + __asm { + fld x + fistp r + } + return r; +} + +inline vxl_int_64 RoundHalfIntegerToEven_64(float x) +{ + vxl_int_64 r; + __asm { + fld x + fistp r + } + return r; +} + +#else // Vanilla implementation + +inline vxl_int_64 RoundHalfIntegerToEven_64(double x) { return RoundHalfIntegerToEven_base<vxl_int_64,double>(x); } +inline vxl_int_64 RoundHalfIntegerToEven_64(float x) { return RoundHalfIntegerToEven_base<vxl_int_64,float>(x); } + +#endif + + +#if USE_SSE2_64IMPL || GCC_USE_ASM_64IMPL || VC_USE_ASM_64IMPL + +inline vxl_int_64 RoundHalfIntegerUp_64(double x) { return RoundHalfIntegerToEven_64(2*x+0.5)>>1; } +inline vxl_int_64 RoundHalfIntegerUp_64(float x) { return RoundHalfIntegerToEven_64(2*x+0.5f)>>1; } + +#else // Vanilla implementation + +inline vxl_int_64 RoundHalfIntegerUp_64(double x) { return RoundHalfIntegerUp_base<vxl_int_64,double>(x); } +inline vxl_int_64 RoundHalfIntegerUp_64(float x) { return RoundHalfIntegerUp_base<vxl_int_64,float>(x); } + +#endif + + +#if USE_SSE2_64IMPL || GCC_USE_ASM_64IMPL || VC_USE_ASM_64IMPL + +inline vxl_int_64 Floor_64(double x) { return RoundHalfIntegerToEven_64(2*x-0.5)>>1; } +inline vxl_int_64 Floor_64(float x) { return RoundHalfIntegerToEven_64(2*x-0.5f)>>1; } + +#else // Vanilla implementation + +inline vxl_int_64 Floor_64(double x) { return Floor_base<vxl_int_64,double>(x); } +inline vxl_int_64 Floor_64(float x) { return Floor_base<vxl_int_64,float>(x); } + +#endif + + +#if USE_SSE2_64IMPL || GCC_USE_ASM_64IMPL || VC_USE_ASM_64IMPL + +inline vxl_int_64 Ceil_64(double x) { return -(RoundHalfIntegerToEven_64(-0.5-2*x)>>1); } +inline vxl_int_64 Ceil_64(float x) { return -(RoundHalfIntegerToEven_64(-0.5f-2*x)>>1); } + +#else // Vanilla implementation + +inline vxl_int_64 Ceil_64(double x) { return Ceil_base<vxl_int_64,double>(x); } +inline vxl_int_64 Ceil_64(float x) { return Ceil_base<vxl_int_64,float>(x); } + +#endif + + +#undef USE_SSE2_64IMPL +#undef GCC_USE_ASM_64IMPL +#undef VC_USE_ASM_64IMPL + +} // end namespace Detail + + + +// A useful macro to generate a template floating point to integer conversion +// templated on the return type and using either the 32 bit, the 64 bit or +// the vanilla version +#define itkTemplateFloatingToIntegerMacro(name) \ + inline int name(double x) { return Detail::name##_32(x); } \ + inline int name(float x) { return Detail::name##_32(x); } \ + \ + template <typename TReturn,typename TInput> \ + inline TReturn T##name(TInput x) \ + { \ + if (sizeof(TReturn) <= 4) \ + { \ + return static_cast<TReturn>(Detail::name##_32(x)); \ + } \ + else if (sizeof(TReturn) <= 8) \ + { \ + return static_cast<TReturn>(Detail::name##_64(x)); \ + } \ + else \ + { \ + return static_cast<TReturn>(Detail::name##_base<TReturn,TInput>(x)); \ + } \ + } + +itkTemplateFloatingToIntegerMacro(RoundHalfIntegerToEven); +itkTemplateFloatingToIntegerMacro(RoundHalfIntegerUp); + +inline int Round(double x) { return RoundHalfIntegerUp(x); } +inline int Round(float x) { return RoundHalfIntegerUp(x); } + +template <typename TReturn, typename TInput> +inline TReturn TRound(TInput x) { return TRoundHalfIntegerUp<TReturn,TInput>(x); } + +itkTemplateFloatingToIntegerMacro(Floor); +itkTemplateFloatingToIntegerMacro(Ceil); + +#undef TemplateFloatingToInteger + + +} // end namespace Math +} // end namespace itk + +#endif //end of itkMath.h Index: Testing/Code/Common/itkMathRoundProfileTest1.cxx =================================================================== RCS file: /cvsroot/Insight/Insight/Testing/Code/Common/itkMathRoundProfileTest1.cxx,v retrieving revision 1.3 diff -u -r1.3 itkMathRoundProfileTest1.cxx --- Testing/Code/Common/itkMathRoundProfileTest1.cxx 2 Jun 2009 20:45:16 -0000 1.3 +++ Testing/Code/Common/itkMathRoundProfileTest1.cxx 27 Jul 2009 16:12:05 -0000 @@ -18,10 +18,9 @@ #pragma warning ( disable : 4786 ) #endif -#include "itkMacro.h" +#include "itkMath.h" #include "itkTimeProbesCollectorBase.h" -#include "vnl/vnl_math.h" -#include <math.h> +#include <cmath> int itkMathRoundTestHelperFunction( double x ) { Index: Testing/Code/Common/itkMathRoundTest.cxx =================================================================== RCS file: /cvsroot/Insight/Insight/Testing/Code/Common/itkMathRoundTest.cxx,v retrieving revision 1.3 diff -u -r1.3 itkMathRoundTest.cxx --- Testing/Code/Common/itkMathRoundTest.cxx 27 Jul 2009 08:56:19 -0000 1.3 +++ Testing/Code/Common/itkMathRoundTest.cxx 27 Jul 2009 16:12:06 -0000 @@ -18,8 +18,11 @@ #pragma warning ( disable : 4786 ) #endif -#include "itkMacro.h" -#include <math.h> +#include "itkMath.h" + +#include <cmath> +#include <string> +#include <iostream> bool math_test_helper(std::string str, bool test) { @@ -30,139 +33,285 @@ return test; } +template <typename TReturn, typename TInput> +bool itkRoundHalfIntegerUpTest( TReturn (*func)(TInput) ) +{ + bool ok = true; + + ok &= math_test_helper("rnd_halfintup(-8.4999) == -8", func(static_cast<TInput>(-8.4999)) == static_cast<TReturn>(-8)); + ok &= math_test_helper("rnd_halfintup(-8.50) == -8", func(static_cast<TInput>(-8.50)) == static_cast<TReturn>(-8)); + ok &= math_test_helper("rnd_halfintup(-8.5001) == -9", func(static_cast<TInput>(-8.5001)) == static_cast<TReturn>(-9)); + ok &= math_test_helper("rnd_halfintup(8.4999) == 8", func(static_cast<TInput>(8.4999)) == static_cast<TReturn>( 8)); + ok &= math_test_helper("rnd_halfintup(8.50) == 9", func(static_cast<TInput>(8.50)) == static_cast<TReturn>( 9)); + ok &= math_test_helper("rnd_halfintup(8.5001) == 9", func(static_cast<TInput>(8.5001)) == static_cast<TReturn>( 9)); + + ok &= math_test_helper("rnd_halfintup(-9.4999) == -9 ", func(static_cast<TInput>(-9.4999)) == static_cast<TReturn>(-9 )); + ok &= math_test_helper("rnd_halfintup(-9.50) == -9 ", func(static_cast<TInput>(-9.50)) == static_cast<TReturn>(-9 )); + ok &= math_test_helper("rnd_halfintup(-9.5001) == -10", func(static_cast<TInput>(-9.5001)) == static_cast<TReturn>(-10)); + ok &= math_test_helper("rnd_halfintup(9.4999) == 9 ", func(static_cast<TInput>(9.4999)) == static_cast<TReturn>( 9 )); + ok &= math_test_helper("rnd_halfintup(9.50) == 10", func(static_cast<TInput>(9.50)) == static_cast<TReturn>( 10)); + ok &= math_test_helper("rnd_halfintup(9.5001) == 10", func(static_cast<TInput>(9.5001)) == static_cast<TReturn>( 10)); + + if (sizeof(TReturn)>=8 && sizeof(TInput)>=8) + { + ok &= math_test_helper("rnd_halfintup(20000000000.2) == 20000000000", + func(static_cast<TInput>( 20000000000.2)) == static_cast<TReturn>(20000000000ll)); + ok &= math_test_helper("rnd_halfintup(-30000000000.2)==-30000000000", + func(static_cast<TInput>(-30000000000.2)) == static_cast<TReturn>(-30000000000ll)); + } + + if (!ok) + { + std::cout<<"Partial test failed"<<std::endl; + } + + return ok; +} + +template <typename TReturn, typename TInput> +bool itkRoundHalfIntegerToEvenTest( TReturn (*func)(TInput) ) +{ + bool ok = true; + + ok &= math_test_helper("rnd_halfinttoeven(-8.4999) == -8", func(static_cast<TInput>(-8.4999)) == static_cast<TReturn>(-8)); + ok &= math_test_helper("rnd_halfinttoeven(-8.50) == -8", func(static_cast<TInput>(-8.50)) == static_cast<TReturn>(-8)); + ok &= math_test_helper("rnd_halfinttoeven(-8.5001) == -9", func(static_cast<TInput>(-8.5001)) == static_cast<TReturn>(-9)); + ok &= math_test_helper("rnd_halfinttoeven(8.4999) == 8", func(static_cast<TInput>(8.4999)) == static_cast<TReturn>( 8)); + ok &= math_test_helper("rnd_halfinttoeven(8.50) == 8", func(static_cast<TInput>(8.50)) == static_cast<TReturn>( 8)); + ok &= math_test_helper("rnd_halfinttoeven(8.5001) == 9", func(static_cast<TInput>(8.5001)) == static_cast<TReturn>( 9)); + + ok &= math_test_helper("rnd_halfinttoeven(-9.4999) == -9 ", func(static_cast<TInput>(-9.4999)) == static_cast<TReturn>(-9 )); + ok &= math_test_helper("rnd_halfinttoeven(-9.50) == -10", func(static_cast<TInput>(-9.50)) == static_cast<TReturn>(-10)); + ok &= math_test_helper("rnd_halfinttoeven(-9.5001) == -10", func(static_cast<TInput>(-9.5001)) == static_cast<TReturn>(-10)); + ok &= math_test_helper("rnd_halfinttoeven(9.4999) == 9 ", func(static_cast<TInput>(9.4999)) == static_cast<TReturn>( 9 )); + ok &= math_test_helper("rnd_halfinttoeven(9.50) == 10", func(static_cast<TInput>(9.50)) == static_cast<TReturn>( 10)); + ok &= math_test_helper("rnd_halfinttoeven(9.5001) == 10", func(static_cast<TInput>(9.5001)) == static_cast<TReturn>( 10)); + + if (sizeof(TReturn) >= 8 && sizeof(TInput)>=8) + { + ok &= math_test_helper("rnd_halfinttoeven(20000000000.2) == 20000000000", + func(static_cast<TInput>( 20000000000.2)) == static_cast<TReturn>( 20000000000ll)); + ok &= math_test_helper("rnd_halfinttoeven(-30000000000.2)==-30000000000", + func(static_cast<TInput>(-30000000000.2)) == static_cast<TReturn>(-30000000000ll)); + } + + if (!ok) + { + std::cout<<"Partial test failed"<<std::endl; + } + + return ok; +} + +template <typename TReturn, typename TInput> +bool itkFloorTest( TReturn (*func)(TInput) ) +{ + bool ok = true; + + ok &= math_test_helper("floor(8.0) == 8", func(static_cast<TInput>(8.0)) == static_cast<TReturn>( 8)); + ok &= math_test_helper("floor(8.9999) == 8", func(static_cast<TInput>(8.9999)) == static_cast<TReturn>( 8)); + ok &= math_test_helper("floor(8.0001) == 8", func(static_cast<TInput>(8.0001)) == static_cast<TReturn>( 8)); + ok &= math_test_helper("floor(-8.0) == -8", func(static_cast<TInput>(-8.0)) == static_cast<TReturn>(-8)); + ok &= math_test_helper("floor(-8.9999) == -9", func(static_cast<TInput>(-8.9999)) == static_cast<TReturn>(-9)); + ok &= math_test_helper("floor(-8.0001) == -9", func(static_cast<TInput>(-8.0001)) == static_cast<TReturn>(-9)); + + ok &= math_test_helper("floor(9.0) == 9 ", func(static_cast<TInput>(9.0)) == static_cast<TReturn>( 9 )); + ok &= math_test_helper("floor(9.9999) == 9 ", func(static_cast<TInput>(9.9999)) == static_cast<TReturn>( 9 )); + ok &= math_test_helper("floor(9.0001) == 9 ", func(static_cast<TInput>(9.0001)) == static_cast<TReturn>( 9 )); + ok &= math_test_helper("floor(-9.0) == -9 ", func(static_cast<TInput>(-9.0)) == static_cast<TReturn>(-9 )); + ok &= math_test_helper("floor(-9.9999) == -10", func(static_cast<TInput>(-9.9999)) == static_cast<TReturn>(-10)); + ok &= math_test_helper("floor(-9.0001) == -10", func(static_cast<TInput>(-9.0001)) == static_cast<TReturn>(-10)); + + if (sizeof(TReturn) >= 8 && sizeof(TInput)>=8) + { + ok &= math_test_helper("floor(20000000000.2) == 20000000000", + func(static_cast<TInput>( 20000000000.2)) == static_cast<TReturn>( 20000000000ll)); + ok &= math_test_helper("floor(-30000000000.2)==-30000000001", + func(static_cast<TInput>(-30000000000.2)) == static_cast<TReturn>(-30000000001ll)); + } + + if (!ok) + { + std::cout<<"Partial test failed"<<std::endl; + } + + return ok; +} + +template <typename TReturn, typename TInput> +bool itkCeilTest( TReturn (*func)(TInput) ) +{ + bool ok = true; + + ok &= math_test_helper("ceil(8.0) == 8", func(static_cast<TInput>(8.0)) == static_cast<TReturn>( 8)); + ok &= math_test_helper("ceil(8.9999) == 9", func(static_cast<TInput>(8.9999)) == static_cast<TReturn>( 9)); + ok &= math_test_helper("ceil(8.0001) == 9", func(static_cast<TInput>(8.0001)) == static_cast<TReturn>( 9)); + ok &= math_test_helper("ceil(-8.0) == -8", func(static_cast<TInput>(-8.0)) == static_cast<TReturn>(-8)); + ok &= math_test_helper("ceil(-8.9999) == -8", func(static_cast<TInput>(-8.9999)) == static_cast<TReturn>(-8)); + ok &= math_test_helper("ceil(-8.0001) == -8", func(static_cast<TInput>(-8.0001)) == static_cast<TReturn>(-8)); + + ok &= math_test_helper("ceil(9.0) == 9 ", func(static_cast<TInput>(9.0)) == static_cast<TReturn>( 9 )); + ok &= math_test_helper("ceil(9.9999) == 10", func(static_cast<TInput>(9.9999)) == static_cast<TReturn>( 10)); + ok &= math_test_helper("ceil(9.0001) == 10", func(static_cast<TInput>(9.0001)) == static_cast<TReturn>( 10)); + ok &= math_test_helper("ceil(-9.0) == -9 ", func(static_cast<TInput>(-9.0)) == static_cast<TReturn>(-9 )); + ok &= math_test_helper("ceil(-9.9999) == -9 ", func(static_cast<TInput>(-9.9999)) == static_cast<TReturn>(-9 )); + ok &= math_test_helper("ceil(-9.0001) == -9 ", func(static_cast<TInput>(-9.0001)) == static_cast<TReturn>(-9 )); + + if (sizeof(TReturn) >= 8 && sizeof(TInput)>=8) + { + ok &= math_test_helper("ceil(20000000000.2) == 20000000000", + func(static_cast<TInput>( 20000000000.2)) == static_cast<TReturn>( 20000000000ll)); + ok &= math_test_helper("ceil(-30000000000.2)==-30000000001", + func(static_cast<TInput>(-30000000000.2)) == static_cast<TReturn>(-30000000001ll)); + } + + if (!ok) + { + std::cout<<"Partial test failed"<<std::endl; + } + + return ok; +} + int itkMathRoundTest( int, char *[] ) { bool ok = true; + + + //--------- + std::cout<<std::endl; + + std::cout<<" int,float,round"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<int, float>(itk::Math::Round); + std::cout<<" int,double,round"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<int,double>(itk::Math::Round); + + std::cout<<" T,int,float,round"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<int, float>(itk::Math::TRound<int, float>); + std::cout<<" T,int,double,round"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<int,double>(itk::Math::TRound<int,double>); + + std::cout<<" T,short,float,round"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<short, float>(itk::Math::TRound<short, float>); + std::cout<<" T,short,double,round"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<short,double>(itk::Math::TRound<short,double>); + + std::cout<<" T,unsigned int,float,round"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<unsigned int, float>(itk::Math::TRound<unsigned int, float>); + std::cout<<" T,unsigned int,double,round"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<unsigned int,double>(itk::Math::TRound<unsigned int,double>); + + std::cout<<" T,long int,float,round"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<long int, float>(itk::Math::TRound<long int, float>); + std::cout<<" T,long int,double,round"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<long int,double>(itk::Math::TRound<long int,double>); + + std::cout<<" T,vxl_int_64,float,round"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<vxl_int_64, float>(itk::Math::TRound<vxl_int_64, float>); + std::cout<<" T,vxl_int_64,double,round"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<vxl_int_64,double>(itk::Math::TRound<vxl_int_64,double>); + + + //--------- + std::cout<<std::endl; + + std::cout<<" int,float,roundhalfintup"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<int, float>(itk::Math::RoundHalfIntegerUp); + std::cout<<" int,double,roundhalfintup"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<int,double>(itk::Math::RoundHalfIntegerUp); + + std::cout<<" T,int,float,roundhalfintup"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<int, float>(itk::Math::TRoundHalfIntegerUp<int, float>); + std::cout<<" T,int,double,roundhalfintup"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<int,double>(itk::Math::TRoundHalfIntegerUp<int,double>); + + std::cout<<" T,short,float,roundhalfintup"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<short, float>(itk::Math::TRoundHalfIntegerUp<short, float>); + std::cout<<" T,short,double,roundhalfintup"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<short,double>(itk::Math::TRoundHalfIntegerUp<short,double>); + + std::cout<<" T,unsigned int,float,roundhalfintup"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<unsigned int, float>(itk::Math::TRoundHalfIntegerUp<unsigned int, float>); + std::cout<<" T,unsigned int,double,roundhalfintup"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<unsigned int,double>(itk::Math::TRoundHalfIntegerUp<unsigned int,double>); + + std::cout<<" T,long int,float,roundhalfintup"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<long int, float>(itk::Math::TRoundHalfIntegerUp<long int, float>); + std::cout<<" T,long int,double,roundhalfintup"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<long int,double>(itk::Math::TRoundHalfIntegerUp<long int,double>); + + std::cout<<" T,vxl_int_64,float,roundhalfintup"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<vxl_int_64, float>(itk::Math::TRoundHalfIntegerUp<vxl_int_64, float>); + std::cout<<" T,vxl_int_64,double,roundhalfintup"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<vxl_int_64,double>(itk::Math::TRoundHalfIntegerUp<vxl_int_64,double>); + + + //--------- + std::cout<<std::endl; + + std::cout<<" int,float,roundhalfinttoeven"<<std::endl; + ok &= itkRoundHalfIntegerToEvenTest<int, float>(itk::Math::RoundHalfIntegerToEven); + std::cout<<" int,double,roundhalfinttoeven"<<std::endl; + ok &= itkRoundHalfIntegerToEvenTest<int,double>(itk::Math::RoundHalfIntegerToEven); + + std::cout<<" T,int,float,roundhalfinttoeven"<<std::endl; + ok &= itkRoundHalfIntegerToEvenTest<int, float>(itk::Math::TRoundHalfIntegerToEven<int, float>); + std::cout<<" T,int,double,roundhalfinttoeven"<<std::endl; + ok &= itkRoundHalfIntegerToEvenTest<int,double>(itk::Math::TRoundHalfIntegerToEven<int,double>); + + std::cout<<" T,short,float,roundhalfinttoeven"<<std::endl; + ok &= itkRoundHalfIntegerToEvenTest<short, float>(itk::Math::TRoundHalfIntegerToEven<short, float>); + std::cout<<" T,short,double,roundhalfinttoeven"<<std::endl; + ok &= itkRoundHalfIntegerToEvenTest<short,double>(itk::Math::TRoundHalfIntegerToEven<short,double>); + + std::cout<<" T,unsigned int,float,roundhalfinttoeven"<<std::endl; + ok &= itkRoundHalfIntegerToEvenTest<unsigned int, float>(itk::Math::TRoundHalfIntegerToEven<unsigned int, float>); + std::cout<<" T,unsigned int,double,roundhalfinttoeven"<<std::endl; + ok &= itkRoundHalfIntegerToEvenTest<unsigned int,double>(itk::Math::TRoundHalfIntegerToEven<unsigned int,double>); + + std::cout<<" T,long int,float,roundhalfinttoeven"<<std::endl; + ok &= itkRoundHalfIntegerToEvenTest<long int, float>(itk::Math::TRoundHalfIntegerToEven<long int, float>); + std::cout<<" T,long int,double,roundhalfinttoeven"<<std::endl; + ok &= itkRoundHalfIntegerToEvenTest<long int,double>(itk::Math::TRoundHalfIntegerToEven<long int,double>); + + std::cout<<" T,vxl_int_64,float,roundhalfinttoeven"<<std::endl; + ok &= itkRoundHalfIntegerToEvenTest<vxl_int_64, float>(itk::Math::TRoundHalfIntegerToEven<vxl_int_64, float>); + std::cout<<" T,vxl_int_64,double,roundhalfinttoeven"<<std::endl; + ok &= itkRoundHalfIntegerToEvenTest<vxl_int_64,double>(itk::Math::TRoundHalfIntegerToEven<vxl_int_64,double>); + + + //--------- + std::cout<<std::endl; + + std::cout<<" int,float,floor"<<std::endl; + ok &= itkFloorTest<int, float>(itk::Math::Floor); + std::cout<<" int,double,floor"<<std::endl; + ok &= itkFloorTest<int,double>(itk::Math::Floor); + + std::cout<<" T,int,float,floor"<<std::endl; + ok &= itkFloorTest<int, float>(itk::Math::TFloor<int, float>); + std::cout<<" T,int,double,floor"<<std::endl; + ok &= itkFloorTest<int,double>(itk::Math::TFloor<int,double>); + + std::cout<<" T,short,float,floor"<<std::endl; + ok &= itkFloorTest<short, float>(itk::Math::TFloor<short, float>); + std::cout<<" T,short,double,floor"<<std::endl; + ok &= itkFloorTest<short,double>(itk::Math::TFloor<short,double>); + + std::cout<<" T,unsigned int,float,floor"<<std::endl; + ok &= itkFloorTest<unsigned int, float>(itk::Math::TFloor<unsigned int, float>); + std::cout<<" T,unsigned int,double,floor"<<std::endl; + ok &= itkFloorTest<unsigned int,double>(itk::Math::TFloor<unsigned int,double>); + + std::cout<<" T,long int,float,floor"<<std::endl; + ok &= itkFloorTest<long int, float>(itk::Math::TFloor<long int, float>); + std::cout<<" T,long int,double,floor"<<std::endl; + ok &= itkFloorTest<long int,double>(itk::Math::TFloor<long int,double>); - ok &= math_test_helper("rnd(-8.4999) == -8", itk::Math::Round(-8.4999) == -8); - ok &= math_test_helper("rnd(-8.4999f) == -8", itk::Math::Round(-8.4999f) == -8); - ok &= math_test_helper("rnd(-8.50) == -8", itk::Math::Round(-8.50) == -8); - ok &= math_test_helper("rnd(-8.50f) == -8", itk::Math::Round(-8.50f) == -8); - ok &= math_test_helper("rnd(-8.5001) == -9", itk::Math::Round(-8.5001) == -9); - ok &= math_test_helper("rnd(-8.5001f) == -9", itk::Math::Round(-8.5001f) == -9); - ok &= math_test_helper("rnd(8.4999) == 8", itk::Math::Round(8.4999) == 8); - ok &= math_test_helper("rnd(8.4999f) == 8", itk::Math::Round(8.4999f) == 8); - ok &= math_test_helper("rnd(8.50) == 9", itk::Math::Round(8.50) == 9); - ok &= math_test_helper("rnd(8.50f) == 9", itk::Math::Round(8.50f) == 9); - ok &= math_test_helper("rnd(8.5001) == 9", itk::Math::Round(8.5001) == 9); - ok &= math_test_helper("rnd(8.5001f) == 9", itk::Math::Round(8.5001f) == 9); - - ok &= math_test_helper("rnd(-9.4999) == -9 ", itk::Math::Round(-9.4999) == -9); - ok &= math_test_helper("rnd(-9.4999f) == -9 ", itk::Math::Round(-9.4999f) == -9); - ok &= math_test_helper("rnd(-9.50) == -9 ", itk::Math::Round(-9.50) == -9); - ok &= math_test_helper("rnd(-9.50f) == -9 ", itk::Math::Round(-9.50f) == -9); - ok &= math_test_helper("rnd(-9.5001) == -10", itk::Math::Round(-9.5001) == -10); - ok &= math_test_helper("rnd(-9.5001f) == -10", itk::Math::Round(-9.5001f) == -10); - ok &= math_test_helper("rnd(9.4999) == 9 ", itk::Math::Round(9.4999) == 9); - ok &= math_test_helper("rnd(9.4999f) == 9 ", itk::Math::Round(9.4999f) == 9); - ok &= math_test_helper("rnd(9.50) == 10", itk::Math::Round(9.50) == 10); - ok &= math_test_helper("rnd(9.50f) == 10", itk::Math::Round(9.50f) == 10); - ok &= math_test_helper("rnd(9.5001) == 10", itk::Math::Round(9.5001) == 10); - ok &= math_test_helper("rnd(9.5001f) == 10", itk::Math::Round(9.5001f) == 10); - - ok &= math_test_helper("rnd_halfinttoeven(-8.4999) == -8", itk::Math::RoundHalfIntegerToEven(-8.4999) == -8); - ok &= math_test_helper("rnd_halfinttoeven(-8.4999f) == -8", itk::Math::RoundHalfIntegerToEven(-8.4999f)== -8); - ok &= math_test_helper("rnd_halfinttoeven(-8.50) == -8", itk::Math::RoundHalfIntegerToEven(-8.50) == -8); - ok &= math_test_helper("rnd_halfinttoeven(-8.50f) == -8", itk::Math::RoundHalfIntegerToEven(-8.50f) == -8); - ok &= math_test_helper("rnd_halfinttoeven(-8.5001) == -9", itk::Math::RoundHalfIntegerToEven(-8.5001) == -9); - ok &= math_test_helper("rnd_halfinttoeven(-8.5001f) == -9", itk::Math::RoundHalfIntegerToEven(-8.5001f)== -9); - ok &= math_test_helper("rnd_halfinttoeven(8.4999) == 8", itk::Math::RoundHalfIntegerToEven(8.4999) == 8); - ok &= math_test_helper("rnd_halfinttoeven(8.4999f) == 8", itk::Math::RoundHalfIntegerToEven(8.4999f) == 8); - ok &= math_test_helper("rnd_halfinttoeven(8.50) == 8", itk::Math::RoundHalfIntegerToEven(8.50) == 8); - ok &= math_test_helper("rnd_halfinttoeven(8.50f) == 8", itk::Math::RoundHalfIntegerToEven(8.50f) == 8); - ok &= math_test_helper("rnd_halfinttoeven(8.5001) == 9", itk::Math::RoundHalfIntegerToEven(8.5001) == 9); - ok &= math_test_helper("rnd_halfinttoeven(8.5001f) == 9", itk::Math::RoundHalfIntegerToEven(8.5001f) == 9); - - ok &= math_test_helper("rnd_halfinttoeven(-9.4999) == -9 ", itk::Math::RoundHalfIntegerToEven(-9.4999) == -9); - ok &= math_test_helper("rnd_halfinttoeven(-9.4999f) == -9 ", itk::Math::RoundHalfIntegerToEven(-9.4999f)== -9); - ok &= math_test_helper("rnd_halfinttoeven(-9.50) == -10", itk::Math::RoundHalfIntegerToEven(-9.50) == -10); - ok &= math_test_helper("rnd_halfinttoeven(-9.50f) == -10", itk::Math::RoundHalfIntegerToEven(-9.50f) == -10); - ok &= math_test_helper("rnd_halfinttoeven(-9.5001) == -10", itk::Math::RoundHalfIntegerToEven(-9.5001) == -10); - ok &= math_test_helper("rnd_halfinttoeven(-9.5001f) == -10", itk::Math::RoundHalfIntegerToEven(-9.5001f)== -10); - ok &= math_test_helper("rnd_halfinttoeven(9.4999) == 9 ", itk::Math::RoundHalfIntegerToEven(9.4999) == 9); - ok &= math_test_helper("rnd_halfinttoeven(9.4999f) == 9 ", itk::Math::RoundHalfIntegerToEven(9.4999f) == 9); - ok &= math_test_helper("rnd_halfinttoeven(9.50) == 10", itk::Math::RoundHalfIntegerToEven(9.50) == 10); - ok &= math_test_helper("rnd_halfinttoeven(9.50f) == 10", itk::Math::RoundHalfIntegerToEven(9.50f) == 10); - ok &= math_test_helper("rnd_halfinttoeven(9.5001) == 10", itk::Math::RoundHalfIntegerToEven(9.5001) == 10); - ok &= math_test_helper("rnd_halfinttoeven(9.5001f) == 10", itk::Math::RoundHalfIntegerToEven(9.5001f) == 10); - - ok &= math_test_helper("rnd_halfintup(-8.4999) == -8", itk::Math::RoundHalfIntegerUp(-8.4999) == -8); - ok &= math_test_helper("rnd_halfintup(-8.4999f) == -8", itk::Math::RoundHalfIntegerUp(-8.4999f)== -8); - ok &= math_test_helper("rnd_halfintup(-8.50) == -8", itk::Math::RoundHalfIntegerUp(-8.50) == -8); - ok &= math_test_helper("rnd_halfintup(-8.50f) == -8", itk::Math::RoundHalfIntegerUp(-8.50f) == -8); - ok &= math_test_helper("rnd_halfintup(-8.5001) == -9", itk::Math::RoundHalfIntegerUp(-8.5001) == -9); - ok &= math_test_helper("rnd_halfintup(-8.5001f) == -9", itk::Math::RoundHalfIntegerUp(-8.5001f)== -9); - ok &= math_test_helper("rnd_halfintup(8.4999) == 8", itk::Math::RoundHalfIntegerUp(8.4999) == 8); - ok &= math_test_helper("rnd_halfintup(8.4999f) == 8", itk::Math::RoundHalfIntegerUp(8.4999f) == 8); - ok &= math_test_helper("rnd_halfintup(8.50) == 9", itk::Math::RoundHalfIntegerUp(8.50) == 9); - ok &= math_test_helper("rnd_halfintup(8.50f) == 9", itk::Math::RoundHalfIntegerUp(8.50f) == 9); - ok &= math_test_helper("rnd_halfintup(8.5001) == 9", itk::Math::RoundHalfIntegerUp(8.5001) == 9); - ok &= math_test_helper("rnd_halfintup(8.5001f) == 9", itk::Math::RoundHalfIntegerUp(8.5001f) == 9); - - ok &= math_test_helper("rnd_halfintup(-9.4999) == -9 ", itk::Math::RoundHalfIntegerUp(-9.4999) == -9); - ok &= math_test_helper("rnd_halfintup(-9.4999f) == -9 ", itk::Math::RoundHalfIntegerUp(-9.4999f)== -9); - ok &= math_test_helper("rnd_halfintup(-9.50) == -9 ", itk::Math::RoundHalfIntegerUp(-9.50) == -9); - ok &= math_test_helper("rnd_halfintup(-9.50f) == -9 ", itk::Math::RoundHalfIntegerUp(-9.50f) == -9); - ok &= math_test_helper("rnd_halfintup(-9.5001) == -10", itk::Math::RoundHalfIntegerUp(-9.5001) == -10); - ok &= math_test_helper("rnd_halfintup(-9.5001f) == -10", itk::Math::RoundHalfIntegerUp(-9.5001f)== -10); - ok &= math_test_helper("rnd_halfintup(9.4999) == 9 ", itk::Math::RoundHalfIntegerUp(9.4999) == 9); - ok &= math_test_helper("rnd_halfintup(9.4999f) == 9 ", itk::Math::RoundHalfIntegerUp(9.4999f) == 9); - ok &= math_test_helper("rnd_halfintup(9.50) == 10", itk::Math::RoundHalfIntegerUp(9.50) == 10); - ok &= math_test_helper("rnd_halfintup(9.50f) == 10", itk::Math::RoundHalfIntegerUp(9.50f) == 10); - ok &= math_test_helper("rnd_halfintup(9.5001) == 10", itk::Math::RoundHalfIntegerUp(9.5001) == 10); - ok &= math_test_helper("rnd_halfintup(9.5001f) == 10", itk::Math::RoundHalfIntegerUp(9.5001f) == 10); - - ok &= math_test_helper("floor(8.0) == 8", itk::Math::Floor(8.0) == 8); - ok &= math_test_helper("floor(8.0f) == 8", itk::Math::Floor(8.0f) == 8); - ok &= math_test_helper("floor(8.9999) == 8", itk::Math::Floor(8.9999) == 8); - ok &= math_test_helper("floor(8.9999f) == 8", itk::Math::Floor(8.9999f) == 8); - ok &= math_test_helper("floor(8.0001) == 8", itk::Math::Floor(8.0001) == 8); - ok &= math_test_helper("floor(8.0001f) == 8", itk::Math::Floor(8.0001f) == 8); - ok &= math_test_helper("floor(-8.0) == -8", itk::Math::Floor(-8.0) == -8); - ok &= math_test_helper("floor(-8.0f) == -8", itk::Math::Floor(-8.0f) == -8); - ok &= math_test_helper("floor(-8.9999) == -9", itk::Math::Floor(-8.9999) == -9); - ok &= math_test_helper("floor(-8.9999f) == -9", itk::Math::Floor(-8.9999f) == -9); - ok &= math_test_helper("floor(-8.0001) == -9", itk::Math::Floor(-8.0001) == -9); - ok &= math_test_helper("floor(-8.0001f) == -9", itk::Math::Floor(-8.0001f) == -9); - - ok &= math_test_helper("floor(9.0) == 9 ", itk::Math::Floor(9.0) == 9); - ok &= math_test_helper("floor(9.0f) == 9 ", itk::Math::Floor(9.0f) == 9); - ok &= math_test_helper("floor(9.9999) == 9 ", itk::Math::Floor(9.9999) == 9); - ok &= math_test_helper("floor(9.9999f) == 9 ", itk::Math::Floor(9.9999f) == 9); - ok &= math_test_helper("floor(9.0001) == 9 ", itk::Math::Floor(9.0001) == 9); - ok &= math_test_helper("floor(9.0001f) == 9 ", itk::Math::Floor(9.0001f) == 9); - ok &= math_test_helper("floor(-9.0) == -9 ", itk::Math::Floor(-9.0) == -9); - ok &= math_test_helper("floor(-9.0f) == -9 ", itk::Math::Floor(-9.0f) == -9); - ok &= math_test_helper("floor(-9.9999) == -10", itk::Math::Floor(-9.9999) == -10); - ok &= math_test_helper("floor(-9.9999f) == -10", itk::Math::Floor(-9.9999f) == -10); - ok &= math_test_helper("floor(-9.0001) == -10", itk::Math::Floor(-9.0001) == -10); - ok &= math_test_helper("floor(-9.0001f) == -10", itk::Math::Floor(-9.0001f) == -10); - - ok &= math_test_helper("ceil(8.0) == 8", itk::Math::Ceil(8.0) == 8); - ok &= math_test_helper("ceil(8.0f) == 8", itk::Math::Ceil(8.0f) == 8); - ok &= math_test_helper("ceil(8.9999) == 9", itk::Math::Ceil(8.9999) == 9); - ok &= math_test_helper("ceil(8.9999f) == 9", itk::Math::Ceil(8.9999f) == 9); - ok &= math_test_helper("ceil(8.0001) == 9", itk::Math::Ceil(8.0001) == 9); - ok &= math_test_helper("ceil(8.0001f) == 9", itk::Math::Ceil(8.0001f) == 9); - ok &= math_test_helper("ceil(-8.0) == -8", itk::Math::Ceil(-8.0) == -8); - ok &= math_test_helper("ceil(-8.0f) == -8", itk::Math::Ceil(-8.0f) == -8); - ok &= math_test_helper("ceil(-8.9999) == -8", itk::Math::Ceil(-8.9999) == -8); - ok &= math_test_helper("ceil(-8.9999f) == -8", itk::Math::Ceil(-8.9999f) == -8); - ok &= math_test_helper("ceil(-8.0001) == -8", itk::Math::Ceil(-8.0001) == -8); - ok &= math_test_helper("ceil(-8.0001f) == -8", itk::Math::Ceil(-8.0001f) == -8); - - ok &= math_test_helper("ceil(9.0) == 9 ", itk::Math::Ceil(9.0) == 9); - ok &= math_test_helper("ceil(9.0f) == 9 ", itk::Math::Ceil(9.0f) == 9); - ok &= math_test_helper("ceil(9.9999) == 10", itk::Math::Ceil(9.9999) == 10); - ok &= math_test_helper("ceil(9.9999f) == 10", itk::Math::Ceil(9.9999f) == 10); - ok &= math_test_helper("ceil(9.0001) == 10", itk::Math::Ceil(9.0001) == 10); - ok &= math_test_helper("ceil(9.0001f) == 10", itk::Math::Ceil(9.0001f) == 10); - ok &= math_test_helper("ceil(-9.0) == -9 ", itk::Math::Ceil(-9.0) == -9); - ok &= math_test_helper("ceil(-9.0f) == -9 ", itk::Math::Ceil(-9.0f) == -9); - ok &= math_test_helper("ceil(-9.9999) == -9 ", itk::Math::Ceil(-9.9999) == -9); - ok &= math_test_helper("ceil(-9.9999f) == -9 ", itk::Math::Ceil(-9.9999f) == -9); - ok &= math_test_helper("ceil(-9.0001) == -9 ", itk::Math::Ceil(-9.0001) == -9); - ok &= math_test_helper("ceil(-9.0001f) == -9 ", itk::Math::Ceil(-9.0001f) == -9); + std::cout<<" T,vxl_int_64,float,floor"<<std::endl; + ok &= itkFloorTest<vxl_int_64, float>(itk::Math::TFloor<vxl_int_64, float>); + std::cout<<" T,vxl_int_64,double,floor"<<std::endl; + ok &= itkFloorTest<vxl_int_64,double>(itk::Math::TFloor<vxl_int_64,double>); if (!ok) { itk-templatedmathround-2009-07-30.patch [^] (45,131 bytes) 2009-07-30 08:41 [Show Content] [Hide Content] Index: Code/Common/itkMacro.h =================================================================== RCS file: /cvsroot/Insight/Insight/Code/Common/itkMacro.h,v retrieving revision 1.97 diff -u -r1.97 itkMacro.h --- Code/Common/itkMacro.h 16 Jun 2009 07:58:46 -0000 1.97 +++ Code/Common/itkMacro.h 30 Jul 2009 12:39:45 -0000 @@ -32,6 +32,7 @@ #include "itkWin32Header.h" #include "itkConfigure.h" +#include "itkMath.h" #include <string> #include <cstdlib> @@ -39,8 +40,6 @@ #include <cassert> #endif -#include "vnl/vnl_math.h" - // Determine type of string stream to use. #if !defined(CMAKE_NO_ANSI_STRING_STREAM) # include <sstream> @@ -970,24 +969,6 @@ #endif -namespace itk -{ -namespace Math -{ -inline int RoundHalfIntegerUp(float x) { return vnl_math_rnd_halfintup(x); } -inline int RoundHalfIntegerUp(double x) { return vnl_math_rnd_halfintup(x); } -inline int RoundHalfIntegerToEven(float x) { return vnl_math_rnd_halfinttoeven(x); } -inline int RoundHalfIntegerToEven(double x) { return vnl_math_rnd_halfinttoeven(x); } -inline int Round(float x) { return RoundHalfIntegerUp(x); } -inline int Round(double x) { return RoundHalfIntegerUp(x); } -inline int Floor(float x) { return vnl_math_floor(x); } -inline int Floor(double x) { return vnl_math_floor(x); } -inline int Ceil(float x) { return vnl_math_ceil(x); } -inline int Ceil(double x) { return vnl_math_ceil(x); } -} // end namespace Math -} // end namespace itk - - #ifdef ITK_USE_TEMPLATE_META_PROGRAMMING_LOOP_UNROLLING //-------------------------------------------------------------------------------- // Helper macros for Template Meta-Programming techniques of for-loops unrolling Index: Code/Common/itkMath.h =================================================================== RCS file: Code/Common/itkMath.h diff -N Code/Common/itkMath.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Code/Common/itkMath.h 30 Jul 2009 12:39:46 -0000 @@ -0,0 +1,390 @@ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkMath.h,v $ + Language: C++ + Date: $Date: 2009-07-27 07:58:46 $ + Version: $Revision: 1.0 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/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 notices for more information. + +=========================================================================*/ +/** + * itkMath.h defines some simple math tools such as round floor and ceil + */ + +#ifndef __itkMath_h +#define __itkMath_h + +#include "vnl/vnl_math.h" + + +namespace itk +{ +namespace Math +{ + +namespace Detail +{ +// The functions defined in this namespace are not meant to be used directly +// and thus do not adhere to the standard backward-compatibility policy of ITK +// Please use the functions from the itk::Math namespace instead + + +// Vanilla versions + +template <typename TReturn, typename TInput> +inline TReturn RoundHalfIntegerToEven_base(TInput x) +{ + if (x>=static_cast<TInput>(0)) x+=static_cast<TInput>(0.5); + else x-=static_cast<TInput>(0.5); + + const TReturn r = static_cast<TReturn>(x); + return (x!=static_cast<TInput>(r)) ? r : static_cast<TReturn>(2*r/2); +} + +template <typename TReturn, typename TInput> +inline TReturn RoundHalfIntegerUp_base(TInput x) +{ + x+=static_cast<TInput>(0.5); + const TReturn r = static_cast<TReturn>(x); + return (r>=static_cast<TReturn>(0)) ? + r : + (x==static_cast<TInput>(r) ? r : r-static_cast<TReturn>(1)); +} + +template <typename TReturn, typename TInput> +inline TReturn Floor_base(TInput x) +{ + const TReturn r = static_cast<TReturn>(x); + return (x>=static_cast<TInput>(0)) ? + r : + (x==static_cast<TInput>(r) ? r : r-static_cast<TReturn>(1)); +} + +template <typename TReturn, typename TInput> +inline TReturn Ceil_base(TInput x) +{ + const TReturn r = static_cast<TReturn>(x); + return (x<static_cast<TInput>(0)) ? + r : + (x==static_cast<TInput>(r) ? r : r+static_cast<TReturn>(1)); +} + + +// 32 bits versions + +// Figure out when the fast implementation can be used + +// Turn on 32-bit sse2 impl if asked for +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING && defined(__SSE2__) && (!defined(__GCCXML__)) +# define USE_SSE2_32IMPL 1 +#else +# define USE_SSE2_32IMPL 0 +#endif +// Turn on 32-bit asm impl when using GCC on x86 platform with the following exception: +// GCCXML +#if defined(__GNUC__) && (!defined(__GCCXML__)) && (defined(__i386__) || defined(__i386) || defined(__x86_64__) || defined(__x86_64)) +# define GCC_USE_ASM_32IMPL 1 +#else +# define GCC_USE_ASM_32IMPL 0 +#endif +// Turn on 32-bit asm impl when using msvc on 32 bits windows +#if defined(VCL_VC) && (!defined(__GCCXML__)) && !defined(_WIN64) +# define VC_USE_ASM_32IMPL 1 +#else +# define VC_USE_ASM_32IMPL 0 +#endif + +#if USE_SSE2_32IMPL // sse2 implementation + +inline vxl_int_32 RoundHalfIntegerToEven_32(double x) { return _mm_cvtsd_si32(_mm_set_sd(x)); } +inline vxl_int_32 RoundHalfIntegerToEven_32(float x) { return _mm_cvtss_si32(_mm_set_ss(x)); } + +#elif GCC_USE_ASM_32IMPL // gcc asm implementation + +inline vxl_int_32 RoundHalfIntegerToEven_32(double x) +{ + vxl_int_32 r; + __asm__ __volatile__( "fistpl %0" : "=m"(r) : "t"(x) : "st" ); + return r; +} + +inline vxl_int_32 RoundHalfIntegerToEven_32(float x) +{ + vxl_int_32 r; + __asm__ __volatile__( "fistpl %0" : "=m"(r) : "t"(x) : "st" ); + return r; +} + +#elif VC_USE_ASM_32IMPL // msvc asm implementation + +inline vxl_int_32 RoundHalfIntegerToEven_32(double x) +{ + vxl_int_32 r; + __asm { + fld x + fistp r + } + return r; +} + +inline vxl_int_32 RoundHalfIntegerToEven_32(float x) +{ + vxl_int_32 r; + __asm { + fld x + fistp r + } + return r; +} + +#else // Vanilla implementation + +inline vxl_int_32 RoundHalfIntegerToEven_32(double x) { return RoundHalfIntegerToEven_base<vxl_int_32,double>(x); } +inline vxl_int_32 RoundHalfIntegerToEven_32(float x) { return RoundHalfIntegerToEven_base<vxl_int_32,float>(x); } + +#endif + + +#if USE_SSE2_32IMPL || GCC_USE_ASM_32IMPL || VC_USE_ASM_32IMPL + +inline vxl_int_32 RoundHalfIntegerUp_32(double x) { return RoundHalfIntegerToEven_32(2*x+0.5)>>1; } +inline vxl_int_32 RoundHalfIntegerUp_32(float x) { return RoundHalfIntegerToEven_32(2*x+0.5f)>>1; } + +#else // Vanilla implementation + +inline vxl_int_32 RoundHalfIntegerUp_32(double x) { return RoundHalfIntegerUp_base<vxl_int_32,double>(x); } +inline vxl_int_32 RoundHalfIntegerUp_32(float x) { return RoundHalfIntegerUp_base<vxl_int_32,float>(x); } + +#endif + + +#if USE_SSE2_32IMPL || GCC_USE_ASM_32IMPL || VC_USE_ASM_32IMPL + +inline vxl_int_32 Floor_32(double x) { return RoundHalfIntegerToEven_32(2*x-0.5)>>1; } +inline vxl_int_32 Floor_32(float x) { return RoundHalfIntegerToEven_32(2*x-0.5f)>>1; } + +#else // Vanilla implementation + +inline vxl_int_32 Floor_32(double x) { return Floor_base<vxl_int_32,double>(x); } +inline vxl_int_32 Floor_32(float x) { return Floor_base<vxl_int_32,float>(x); } + +#endif + + +#if USE_SSE2_32IMPL || GCC_USE_ASM_32IMPL || VC_USE_ASM_32IMPL + +inline vxl_int_32 Ceil_32(double x) { return -(RoundHalfIntegerToEven_32(-0.5-2*x)>>1); } +inline vxl_int_32 Ceil_32(float x) { return -(RoundHalfIntegerToEven_32(-0.5f-2*x)>>1); } + +#else // Vanilla implementation + +inline vxl_int_32 Ceil_32(double x) { return Ceil_base<vxl_int_32,double>(x); } +inline vxl_int_32 Ceil_32(float x) { return Ceil_base<vxl_int_32,float>(x); } + +#endif + + +#undef USE_SSE2_32IMPL +#undef GCC_USE_ASM_32IMPL +#undef VC_USE_ASM_32IMPL + + +// 64 bits versions + +// Figure out when the fast implementation can be used + +// Turn on 64-bit sse2 impl on 64-bit architectures if asked for +#if VNL_CONFIG_ENABLE_SSE2_ROUNDING && defined(__SSE2__) && (defined(__x86_64) || defined(__x86_64__) || defined(_M_X64)) && (!defined(__GCCXML__)) +# define USE_SSE2_64IMPL 1 +#else +# define USE_SSE2_64IMPL 0 +#endif +// Turn on 64-bit asm impl when using GCC on x86 platform with the following exception: +// GCCXML +#if defined(__GNUC__) && (!defined(__GCCXML__)) && (defined(__i386__) || defined(__i386) || defined(__x86_64__) || defined(__x86_64)) +# define GCC_USE_ASM_64IMPL 1 +#else +# define GCC_USE_ASM_64IMPL 0 +#endif +// Turn on 64-bit asm impl when using msvc on 32 bits windows +#if defined(VCL_VC) && (!defined(__GCCXML__)) && !defined(_WIN64) +# define VC_USE_ASM_64IMPL 1 +#else +# define VC_USE_ASM_64IMPL 0 +#endif + +#if USE_SSE2_64IMPL // sse2 implementation + +inline vxl_int_64 RoundHalfIntegerToEven_64(double x) { return _mm_cvtsd_si64(_mm_set_sd(x)); } +inline vxl_int_64 RoundHalfIntegerToEven_64(float x) { return _mm_cvtsd_si64(_mm_set_ss(x)); } + +#elif GCC_USE_ASM_64IMPL // gcc asm implementation + +inline vxl_int_64 RoundHalfIntegerToEven_64(double x) +{ + vxl_int_64 r; + __asm__ __volatile__( "fistpll %0" : "=m"(r) : "t"(x) : "st" ); + return r; +} + +inline vxl_int_64 RoundHalfIntegerToEven_64(float x) +{ + vxl_int_64 r; + __asm__ __volatile__( "fistpll %0" : "=m"(r) : "t"(x) : "st" ); + return r; +} + +#elif VC_USE_ASM_64IMPL // msvc asm implementation + +inline vxl_int_64 RoundHalfIntegerToEven_64(double x) +{ + vxl_int_64 r; + __asm { + fld x + fistp r + } + return r; +} + +inline vxl_int_64 RoundHalfIntegerToEven_64(float x) +{ + vxl_int_64 r; + __asm { + fld x + fistp r + } + return r; +} + +#else // Vanilla implementation + +inline vxl_int_64 RoundHalfIntegerToEven_64(double x) { return RoundHalfIntegerToEven_base<vxl_int_64,double>(x); } +inline vxl_int_64 RoundHalfIntegerToEven_64(float x) { return RoundHalfIntegerToEven_base<vxl_int_64,float>(x); } + +#endif + + +#if USE_SSE2_64IMPL || GCC_USE_ASM_64IMPL || VC_USE_ASM_64IMPL + +inline vxl_int_64 RoundHalfIntegerUp_64(double x) { return RoundHalfIntegerToEven_64(2*x+0.5)>>1; } +inline vxl_int_64 RoundHalfIntegerUp_64(float x) { return RoundHalfIntegerToEven_64(2*x+0.5f)>>1; } + +#else // Vanilla implementation + +inline vxl_int_64 RoundHalfIntegerUp_64(double x) { return RoundHalfIntegerUp_base<vxl_int_64,double>(x); } +inline vxl_int_64 RoundHalfIntegerUp_64(float x) { return RoundHalfIntegerUp_base<vxl_int_64,float>(x); } + +#endif + + +#if USE_SSE2_64IMPL || GCC_USE_ASM_64IMPL || VC_USE_ASM_64IMPL + +inline vxl_int_64 Floor_64(double x) { return RoundHalfIntegerToEven_64(2*x-0.5)>>1; } +inline vxl_int_64 Floor_64(float x) { return RoundHalfIntegerToEven_64(2*x-0.5f)>>1; } + +#else // Vanilla implementation + +inline vxl_int_64 Floor_64(double x) { return Floor_base<vxl_int_64,double>(x); } +inline vxl_int_64 Floor_64(float x) { return Floor_base<vxl_int_64,float>(x); } + +#endif + + +#if USE_SSE2_64IMPL || GCC_USE_ASM_64IMPL || VC_USE_ASM_64IMPL + +inline vxl_int_64 Ceil_64(double x) { return -(RoundHalfIntegerToEven_64(-0.5-2*x)>>1); } +inline vxl_int_64 Ceil_64(float x) { return -(RoundHalfIntegerToEven_64(-0.5f-2*x)>>1); } + +#else // Vanilla implementation + +inline vxl_int_64 Ceil_64(double x) { return Ceil_base<vxl_int_64,double>(x); } +inline vxl_int_64 Ceil_64(float x) { return Ceil_base<vxl_int_64,float>(x); } + +#endif + + +#undef USE_SSE2_64IMPL +#undef GCC_USE_ASM_64IMPL +#undef VC_USE_ASM_64IMPL + +} // end namespace Detail + + + +// A useful macro to generate a template floating point to integer conversion +// templated on the return type and using either the 32 bit, the 64 bit or +// the vanilla version +#define itkTemplateFloatingToIntegerMacro(name) \ + template <typename TReturn,typename TInput> \ + inline TReturn name(TInput x) \ + { \ + if (sizeof(TReturn) <= 4) \ + { \ + return static_cast<TReturn>(Detail::name##_32(x)); \ + } \ + else if (sizeof(TReturn) <= 8) \ + { \ + return static_cast<TReturn>(Detail::name##_64(x)); \ + } \ + else \ + { \ + return static_cast<TReturn>(Detail::name##_base<TReturn,TInput>(x)); \ + } \ + } + +/** Define TReturn itk::Math::RoundHalfIntegerToEven<TReturn,TInput>(TInput x) */ +itkTemplateFloatingToIntegerMacro(RoundHalfIntegerToEven); + +/** Define TReturn itk::Math::RoundHalfIntegerUp<TReturn,TInput>(TInput x) */ +itkTemplateFloatingToIntegerMacro(RoundHalfIntegerUp); + +/** Define TReturn itk::Math::Round<TReturn,TInput>(TInput x) */ +template <typename TReturn, typename TInput> +inline TReturn Round(TInput x) { return RoundHalfIntegerUp<TReturn,TInput>(x); } + +/** Define TReturn itk::Math::Floor<TReturn,TInput>(TInput x) */ +itkTemplateFloatingToIntegerMacro(Floor); + +/** Define TReturn itk::Math::Ceil<TReturn,TInput>(TInput x) */ +itkTemplateFloatingToIntegerMacro(Ceil); + + + +#ifndef ITK_LEGACY_REMOVE +/** + * These methods have been deprecated as of ITK 3.16 + * Please use the templated method + * TReturn itk::Math::XXX<TReturn,TInput>(TInput x) instead. + */ + +inline int RoundHalfIntegerToEven(double x) { return Detail::RoundHalfIntegerToEven_32(x); } +inline int RoundHalfIntegerToEven(float x) { return Detail::RoundHalfIntegerToEven_32(x); } + +inline int RoundHalfIntegerUp(double x) { return Detail::RoundHalfIntegerUp_32(x); } +inline int RoundHalfIntegerUp(float x) { return Detail::RoundHalfIntegerUp_32(x); } + +inline int Round(double x) { return RoundHalfIntegerUp(x); } +inline int Round(float x) { return RoundHalfIntegerUp(x); } + +inline int Floor(double x) { return Detail::Floor_32(x); } +inline int Floor(float x) { return Detail::Floor_32(x); } + +inline int Ceil(double x) { return Detail::Ceil_32(x); } +inline int Ceil(float x) { return Detail::Ceil_32(x); } + +#endif // end of ITK_LEGACY_REMOVE + +#undef TemplateFloatingToInteger + + +} // end namespace Math +} // end namespace itk + +#endif //end of itkMath.h Index: Testing/Code/Common/itkMathRoundTest.cxx =================================================================== RCS file: /cvsroot/Insight/Insight/Testing/Code/Common/itkMathRoundTest.cxx,v retrieving revision 1.3 diff -u -r1.3 itkMathRoundTest.cxx --- Testing/Code/Common/itkMathRoundTest.cxx 27 Jul 2009 08:56:19 -0000 1.3 +++ Testing/Code/Common/itkMathRoundTest.cxx 30 Jul 2009 12:39:46 -0000 @@ -18,8 +18,11 @@ #pragma warning ( disable : 4786 ) #endif -#include "itkMacro.h" -#include <math.h> +#include "itkMath.h" + +#include <cmath> +#include <string> +#include <iostream> bool math_test_helper(std::string str, bool test) { @@ -30,139 +33,329 @@ return test; } +template <typename TReturn, typename TInput> +bool itkRoundHalfIntegerUpTest( TReturn (*func)(TInput) ) +{ + bool ok = true; + + ok &= math_test_helper("rnd_halfintup(-8.4999) == -8", func(static_cast<TInput>(-8.4999)) == static_cast<TReturn>(-8)); + ok &= math_test_helper("rnd_halfintup(-8.50) == -8", func(static_cast<TInput>(-8.50)) == static_cast<TReturn>(-8)); + ok &= math_test_helper("rnd_halfintup(-8.5001) == -9", func(static_cast<TInput>(-8.5001)) == static_cast<TReturn>(-9)); + ok &= math_test_helper("rnd_halfintup(8.4999) == 8", func(static_cast<TInput>(8.4999)) == static_cast<TReturn>( 8)); + ok &= math_test_helper("rnd_halfintup(8.50) == 9", func(static_cast<TInput>(8.50)) == static_cast<TReturn>( 9)); + ok &= math_test_helper("rnd_halfintup(8.5001) == 9", func(static_cast<TInput>(8.5001)) == static_cast<TReturn>( 9)); + + ok &= math_test_helper("rnd_halfintup(-9.4999) == -9 ", func(static_cast<TInput>(-9.4999)) == static_cast<TReturn>(-9 )); + ok &= math_test_helper("rnd_halfintup(-9.50) == -9 ", func(static_cast<TInput>(-9.50)) == static_cast<TReturn>(-9 )); + ok &= math_test_helper("rnd_halfintup(-9.5001) == -10", func(static_cast<TInput>(-9.5001)) == static_cast<TReturn>(-10)); + ok &= math_test_helper("rnd_halfintup(9.4999) == 9 ", func(static_cast<TInput>(9.4999)) == static_cast<TReturn>( 9 )); + ok &= math_test_helper("rnd_halfintup(9.50) == 10", func(static_cast<TInput>(9.50)) == static_cast<TReturn>( 10)); + ok &= math_test_helper("rnd_halfintup(9.5001) == 10", func(static_cast<TInput>(9.5001)) == static_cast<TReturn>( 10)); + + if (sizeof(TReturn)>=8 && sizeof(TInput)>=8) + { + ok &= math_test_helper("rnd_halfintup(20000000000.2) == 20000000000", + func(static_cast<TInput>( 20000000000.2)) == static_cast<TReturn>(20000000000ll)); + ok &= math_test_helper("rnd_halfintup(-30000000000.2)==-30000000000", + func(static_cast<TInput>(-30000000000.2)) == static_cast<TReturn>(-30000000000ll)); + } + + if (!ok) + { + std::cout<<"Partial test failed"<<std::endl; + } + + return ok; +} + +template <typename TReturn, typename TInput> +bool itkRoundHalfIntegerToEvenTest( TReturn (*func)(TInput) ) +{ + bool ok = true; + + ok &= math_test_helper("rnd_halfinttoeven(-8.4999) == -8", func(static_cast<TInput>(-8.4999)) == static_cast<TReturn>(-8)); + ok &= math_test_helper("rnd_halfinttoeven(-8.50) == -8", func(static_cast<TInput>(-8.50)) == static_cast<TReturn>(-8)); + ok &= math_test_helper("rnd_halfinttoeven(-8.5001) == -9", func(static_cast<TInput>(-8.5001)) == static_cast<TReturn>(-9)); + ok &= math_test_helper("rnd_halfinttoeven(8.4999) == 8", func(static_cast<TInput>(8.4999)) == static_cast<TReturn>( 8)); + ok &= math_test_helper("rnd_halfinttoeven(8.50) == 8", func(static_cast<TInput>(8.50)) == static_cast<TReturn>( 8)); + ok &= math_test_helper("rnd_halfinttoeven(8.5001) == 9", func(static_cast<TInput>(8.5001)) == static_cast<TReturn>( 9)); + + ok &= math_test_helper("rnd_halfinttoeven(-9.4999) == -9 ", func(static_cast<TInput>(-9.4999)) == static_cast<TReturn>(-9 )); + ok &= math_test_helper("rnd_halfinttoeven(-9.50) == -10", func(static_cast<TInput>(-9.50)) == static_cast<TReturn>(-10)); + ok &= math_test_helper("rnd_halfinttoeven(-9.5001) == -10", func(static_cast<TInput>(-9.5001)) == static_cast<TReturn>(-10)); + ok &= math_test_helper("rnd_halfinttoeven(9.4999) == 9 ", func(static_cast<TInput>(9.4999)) == static_cast<TReturn>( 9 )); + ok &= math_test_helper("rnd_halfinttoeven(9.50) == 10", func(static_cast<TInput>(9.50)) == static_cast<TReturn>( 10)); + ok &= math_test_helper("rnd_halfinttoeven(9.5001) == 10", func(static_cast<TInput>(9.5001)) == static_cast<TReturn>( 10)); + + if (sizeof(TReturn) >= 8 && sizeof(TInput)>=8) + { + ok &= math_test_helper("rnd_halfinttoeven(20000000000.2) == 20000000000", + func(static_cast<TInput>( 20000000000.2)) == static_cast<TReturn>( 20000000000ll)); + ok &= math_test_helper("rnd_halfinttoeven(-30000000000.2)==-30000000000", + func(static_cast<TInput>(-30000000000.2)) == static_cast<TReturn>(-30000000000ll)); + } + + if (!ok) + { + std::cout<<"Partial test failed"<<std::endl; + } + + return ok; +} + +template <typename TReturn, typename TInput> +bool itkFloorTest( TReturn (*func)(TInput) ) +{ + bool ok = true; + + ok &= math_test_helper("floor(8.0) == 8", func(static_cast<TInput>(8.0)) == static_cast<TReturn>( 8)); + ok &= math_test_helper("floor(8.9999) == 8", func(static_cast<TInput>(8.9999)) == static_cast<TReturn>( 8)); + ok &= math_test_helper("floor(8.0001) == 8", func(static_cast<TInput>(8.0001)) == static_cast<TReturn>( 8)); + ok &= math_test_helper("floor(-8.0) == -8", func(static_cast<TInput>(-8.0)) == static_cast<TReturn>(-8)); + ok &= math_test_helper("floor(-8.9999) == -9", func(static_cast<TInput>(-8.9999)) == static_cast<TReturn>(-9)); + ok &= math_test_helper("floor(-8.0001) == -9", func(static_cast<TInput>(-8.0001)) == static_cast<TReturn>(-9)); + + ok &= math_test_helper("floor(9.0) == 9 ", func(static_cast<TInput>(9.0)) == static_cast<TReturn>( 9 )); + ok &= math_test_helper("floor(9.9999) == 9 ", func(static_cast<TInput>(9.9999)) == static_cast<TReturn>( 9 )); + ok &= math_test_helper("floor(9.0001) == 9 ", func(static_cast<TInput>(9.0001)) == static_cast<TReturn>( 9 )); + ok &= math_test_helper("floor(-9.0) == -9 ", func(static_cast<TInput>(-9.0)) == static_cast<TReturn>(-9 )); + ok &= math_test_helper("floor(-9.9999) == -10", func(static_cast<TInput>(-9.9999)) == static_cast<TReturn>(-10)); + ok &= math_test_helper("floor(-9.0001) == -10", func(static_cast<TInput>(-9.0001)) == static_cast<TReturn>(-10)); + + if (sizeof(TReturn) >= 8 && sizeof(TInput)>=8) + { + ok &= math_test_helper("floor(20000000000.2) == 20000000000", + func(static_cast<TInput>( 20000000000.2)) == static_cast<TReturn>( 20000000000ll)); + ok &= math_test_helper("floor(-30000000000.2)==-30000000001", + func(static_cast<TInput>(-30000000000.2)) == static_cast<TReturn>(-30000000001ll)); + } + + if (!ok) + { + std::cout<<"Partial test failed"<<std::endl; + } + + return ok; +} + +template <typename TReturn, typename TInput> +bool itkCeilTest( TReturn (*func)(TInput) ) +{ + bool ok = true; + + ok &= math_test_helper("ceil(8.0) == 8", func(static_cast<TInput>(8.0)) == static_cast<TReturn>( 8)); + ok &= math_test_helper("ceil(8.9999) == 9", func(static_cast<TInput>(8.9999)) == static_cast<TReturn>( 9)); + ok &= math_test_helper("ceil(8.0001) == 9", func(static_cast<TInput>(8.0001)) == static_cast<TReturn>( 9)); + ok &= math_test_helper("ceil(-8.0) == -8", func(static_cast<TInput>(-8.0)) == static_cast<TReturn>(-8)); + ok &= math_test_helper("ceil(-8.9999) == -8", func(static_cast<TInput>(-8.9999)) == static_cast<TReturn>(-8)); + ok &= math_test_helper("ceil(-8.0001) == -8", func(static_cast<TInput>(-8.0001)) == static_cast<TReturn>(-8)); + + ok &= math_test_helper("ceil(9.0) == 9 ", func(static_cast<TInput>(9.0)) == static_cast<TReturn>( 9 )); + ok &= math_test_helper("ceil(9.9999) == 10", func(static_cast<TInput>(9.9999)) == static_cast<TReturn>( 10)); + ok &= math_test_helper("ceil(9.0001) == 10", func(static_cast<TInput>(9.0001)) == static_cast<TReturn>( 10)); + ok &= math_test_helper("ceil(-9.0) == -9 ", func(static_cast<TInput>(-9.0)) == static_cast<TReturn>(-9 )); + ok &= math_test_helper("ceil(-9.9999) == -9 ", func(static_cast<TInput>(-9.9999)) == static_cast<TReturn>(-9 )); + ok &= math_test_helper("ceil(-9.0001) == -9 ", func(static_cast<TInput>(-9.0001)) == static_cast<TReturn>(-9 )); + + if (sizeof(TReturn) >= 8 && sizeof(TInput)>=8) + { + ok &= math_test_helper("ceil(20000000000.2) == 20000000000", + func(static_cast<TInput>( 20000000000.2)) == static_cast<TReturn>( 20000000001ll)); + ok &= math_test_helper("ceil(-30000000000.2)==-30000000001", + func(static_cast<TInput>(-30000000000.2)) == static_cast<TReturn>(-30000000000ll)); + } + + if (!ok) + { + std::cout<<"Partial test failed"<<std::endl; + } + + return ok; +} + int itkMathRoundTest( int, char *[] ) { bool ok = true; + + + //--------- + std::cout<<std::endl; + +#ifndef ITK_LEGACY_REMOVE + std::cout<<" int,float,round"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<int, float>(itk::Math::Round); + std::cout<<" int,double,round"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<int,double>(itk::Math::Round); +#endif + + std::cout<<" T,int,float,round"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<int, float>(itk::Math::Round<int, float>); + std::cout<<" T,int,double,round"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<int,double>(itk::Math::Round<int,double>); + + std::cout<<" T,short,float,round"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<short, float>(itk::Math::Round<short, float>); + std::cout<<" T,short,double,round"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<short,double>(itk::Math::Round<short,double>); + + std::cout<<" T,unsigned int,float,round"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<unsigned int, float>(itk::Math::Round<unsigned int, float>); + std::cout<<" T,unsigned int,double,round"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<unsigned int,double>(itk::Math::Round<unsigned int,double>); + + std::cout<<" T,long int,float,round"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<long int, float>(itk::Math::Round<long int, float>); + std::cout<<" T,long int,double,round"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<long int,double>(itk::Math::Round<long int,double>); + + std::cout<<" T,vxl_int_64,float,round"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<vxl_int_64, float>(itk::Math::Round<vxl_int_64, float>); + std::cout<<" T,vxl_int_64,double,round"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<vxl_int_64,double>(itk::Math::Round<vxl_int_64,double>); + + + //--------- + std::cout<<std::endl; + +#ifndef ITK_LEGACY_REMOVE + std::cout<<" int,float,roundhalfintup"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<int, float>(itk::Math::RoundHalfIntegerUp); + std::cout<<" int,double,roundhalfintup"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<int,double>(itk::Math::RoundHalfIntegerUp); +#endif + + std::cout<<" T,int,float,roundhalfintup"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<int, float>(itk::Math::RoundHalfIntegerUp<int, float>); + std::cout<<" T,int,double,roundhalfintup"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<int,double>(itk::Math::RoundHalfIntegerUp<int,double>); + + std::cout<<" T,short,float,roundhalfintup"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<short, float>(itk::Math::RoundHalfIntegerUp<short, float>); + std::cout<<" T,short,double,roundhalfintup"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<short,double>(itk::Math::RoundHalfIntegerUp<short,double>); + + std::cout<<" T,unsigned int,float,roundhalfintup"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<unsigned int, float>(itk::Math::RoundHalfIntegerUp<unsigned int, float>); + std::cout<<" T,unsigned int,double,roundhalfintup"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<unsigned int,double>(itk::Math::RoundHalfIntegerUp<unsigned int,double>); + + std::cout<<" T,long int,float,roundhalfintup"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<long int, float>(itk::Math::RoundHalfIntegerUp<long int, float>); + std::cout<<" T,long int,double,roundhalfintup"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<long int,double>(itk::Math::RoundHalfIntegerUp<long int,double>); + + std::cout<<" T,vxl_int_64,float,roundhalfintup"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<vxl_int_64, float>(itk::Math::RoundHalfIntegerUp<vxl_int_64, float>); + std::cout<<" T,vxl_int_64,double,roundhalfintup"<<std::endl; + ok &= itkRoundHalfIntegerUpTest<vxl_int_64,double>(itk::Math::RoundHalfIntegerUp<vxl_int_64,double>); + + + //--------- + std::cout<<std::endl; + +#ifndef ITK_LEGACY_REMOVE + std::cout<<" int,float,roundhalfinttoeven"<<std::endl; + ok &= itkRoundHalfIntegerToEvenTest<int, float>(itk::Math::RoundHalfIntegerToEven); + std::cout<<" int,double,roundhalfinttoeven"<<std::endl; + ok &= itkRoundHalfIntegerToEvenTest<int,double>(itk::Math::RoundHalfIntegerToEven); +#endif + + std::cout<<" T,int,float,roundhalfinttoeven"<<std::endl; + ok &= itkRoundHalfIntegerToEvenTest<int, float>(itk::Math::RoundHalfIntegerToEven<int, float>); + std::cout<<" T,int,double,roundhalfinttoeven"<<std::endl; + ok &= itkRoundHalfIntegerToEvenTest<int,double>(itk::Math::RoundHalfIntegerToEven<int,double>); + + std::cout<<" T,short,float,roundhalfinttoeven"<<std::endl; + ok &= itkRoundHalfIntegerToEvenTest<short, float>(itk::Math::RoundHalfIntegerToEven<short, float>); + std::cout<<" T,short,double,roundhalfinttoeven"<<std::endl; + ok &= itkRoundHalfIntegerToEvenTest<short,double>(itk::Math::RoundHalfIntegerToEven<short,double>); + + std::cout<<" T,unsigned int,float,roundhalfinttoeven"<<std::endl; + ok &= itkRoundHalfIntegerToEvenTest<unsigned int, float>(itk::Math::RoundHalfIntegerToEven<unsigned int, float>); + std::cout<<" T,unsigned int,double,roundhalfinttoeven"<<std::endl; + ok &= itkRoundHalfIntegerToEvenTest<unsigned int,double>(itk::Math::RoundHalfIntegerToEven<unsigned int,double>); + + std::cout<<" T,long int,float,roundhalfinttoeven"<<std::endl; + ok &= itkRoundHalfIntegerToEvenTest<long int, float>(itk::Math::RoundHalfIntegerToEven<long int, float>); + std::cout<<" T,long int,double,roundhalfinttoeven"<<std::endl; + ok &= itkRoundHalfIntegerToEvenTest<long int,double>(itk::Math::RoundHalfIntegerToEven<long int,double>); + + std::cout<<" T,vxl_int_64,float,roundhalfinttoeven"<<std::endl; + ok &= itkRoundHalfIntegerToEvenTest<vxl_int_64, float>(itk::Math::RoundHalfIntegerToEven<vxl_int_64, float>); + std::cout<<" T,vxl_int_64,double,roundhalfinttoeven"<<std::endl; + ok &= itkRoundHalfIntegerToEvenTest<vxl_int_64,double>(itk::Math::RoundHalfIntegerToEven<vxl_int_64,double>); + + + //--------- + std::cout<<std::endl; + +#ifndef ITK_LEGACY_REMOVE + std::cout<<" int,float,floor"<<std::endl; + ok &= itkFloorTest<int, float>(itk::Math::Floor); + std::cout<<" int,double,floor"<<std::endl; + ok &= itkFloorTest<int,double>(itk::Math::Floor); +#endif + + std::cout<<" T,int,float,floor"<<std::endl; + ok &= itkFloorTest<int, float>(itk::Math::Floor<int, float>); + std::cout<<" T,int,double,floor"<<std::endl; + ok &= itkFloorTest<int,double>(itk::Math::Floor<int,double>); + + std::cout<<" T,short,float,floor"<<std::endl; + ok &= itkFloorTest<short, float>(itk::Math::Floor<short, float>); + std::cout<<" T,short,double,floor"<<std::endl; + ok &= itkFloorTest<short,double>(itk::Math::Floor<short,double>); + + std::cout<<" T,unsigned int,float,floor"<<std::endl; + ok &= itkFloorTest<unsigned int, float>(itk::Math::Floor<unsigned int, float>); + std::cout<<" T,unsigned int,double,floor"<<std::endl; + ok &= itkFloorTest<unsigned int,double>(itk::Math::Floor<unsigned int,double>); + + std::cout<<" T,long int,float,floor"<<std::endl; + ok &= itkFloorTest<long int, float>(itk::Math::Floor<long int, float>); + std::cout<<" T,long int,double,floor"<<std::endl; + ok &= itkFloorTest<long int,double>(itk::Math::Floor<long int,double>); + + std::cout<<" T,vxl_int_64,float,floor"<<std::endl; + ok &= itkFloorTest<vxl_int_64, float>(itk::Math::Floor<vxl_int_64, float>); + std::cout<<" T,vxl_int_64,double,floor"<<std::endl; + ok &= itkFloorTest<vxl_int_64,double>(itk::Math::Floor<vxl_int_64,double>); + + + //--------- + std::cout<<std::endl; + +#ifndef ITK_LEGACY_REMOVE + std::cout<<" int,float,ceil"<<std::endl; + ok &= itkCeilTest<int, float>(itk::Math::Ceil); + std::cout<<" int,double,ceil"<<std::endl; + ok &= itkCeilTest<int,double>(itk::Math::Ceil); +#endif + + std::cout<<" T,int,float,ceil"<<std::endl; + ok &= itkCeilTest<int, float>(itk::Math::Ceil<int, float>); + std::cout<<" T,int,double,ceil"<<std::endl; + ok &= itkCeilTest<int,double>(itk::Math::Ceil<int,double>); + + std::cout<<" T,short,float,ceil"<<std::endl; + ok &= itkCeilTest<short, float>(itk::Math::Ceil<short, float>); + std::cout<<" T,short,double,ceil"<<std::endl; + ok &= itkCeilTest<short,double>(itk::Math::Ceil<short,double>); + + std::cout<<" T,unsigned int,float,ceil"<<std::endl; + ok &= itkCeilTest<unsigned int, float>(itk::Math::Ceil<unsigned int, float>); + std::cout<<" T,unsigned int,double,ceil"<<std::endl; + ok &= itkCeilTest<unsigned int,double>(itk::Math::Ceil<unsigned int,double>); + + std::cout<<" T,long int,float,ceil"<<std::endl; + ok &= itkCeilTest<long int, float>(itk::Math::Ceil<long int, float>); + std::cout<<" T,long int,double,ceil"<<std::endl; + ok &= itkCeilTest<long int,double>(itk::Math::Ceil<long int,double>); - ok &= math_test_helper("rnd(-8.4999) == -8", itk::Math::Round(-8.4999) == -8); - ok &= math_test_helper("rnd(-8.4999f) == -8", itk::Math::Round(-8.4999f) == -8); - ok &= math_test_helper("rnd(-8.50) == -8", itk::Math::Round(-8.50) == -8); - ok &= math_test_helper("rnd(-8.50f) == -8", itk::Math::Round(-8.50f) == -8); - ok &= math_test_helper("rnd(-8.5001) == -9", itk::Math::Round(-8.5001) == -9); - ok &= math_test_helper("rnd(-8.5001f) == -9", itk::Math::Round(-8.5001f) == -9); - ok &= math_test_helper("rnd(8.4999) == 8", itk::Math::Round(8.4999) == 8); - ok &= math_test_helper("rnd(8.4999f) == 8", itk::Math::Round(8.4999f) == 8); - ok &= math_test_helper("rnd(8.50) == 9", itk::Math::Round(8.50) == 9); - ok &= math_test_helper("rnd(8.50f) == 9", itk::Math::Round(8.50f) == 9); - ok &= math_test_helper("rnd(8.5001) == 9", itk::Math::Round(8.5001) == 9); - ok &= math_test_helper("rnd(8.5001f) == 9", itk::Math::Round(8.5001f) == 9); - - ok &= math_test_helper("rnd(-9.4999) == -9 ", itk::Math::Round(-9.4999) == -9); - ok &= math_test_helper("rnd(-9.4999f) == -9 ", itk::Math::Round(-9.4999f) == -9); - ok &= math_test_helper("rnd(-9.50) == -9 ", itk::Math::Round(-9.50) == -9); - ok &= math_test_helper("rnd(-9.50f) == -9 ", itk::Math::Round(-9.50f) == -9); - ok &= math_test_helper("rnd(-9.5001) == -10", itk::Math::Round(-9.5001) == -10); - ok &= math_test_helper("rnd(-9.5001f) == -10", itk::Math::Round(-9.5001f) == -10); - ok &= math_test_helper("rnd(9.4999) == 9 ", itk::Math::Round(9.4999) == 9); - ok &= math_test_helper("rnd(9.4999f) == 9 ", itk::Math::Round(9.4999f) == 9); - ok &= math_test_helper("rnd(9.50) == 10", itk::Math::Round(9.50) == 10); - ok &= math_test_helper("rnd(9.50f) == 10", itk::Math::Round(9.50f) == 10); - ok &= math_test_helper("rnd(9.5001) == 10", itk::Math::Round(9.5001) == 10); - ok &= math_test_helper("rnd(9.5001f) == 10", itk::Math::Round(9.5001f) == 10); - - ok &= math_test_helper("rnd_halfinttoeven(-8.4999) == -8", itk::Math::RoundHalfIntegerToEven(-8.4999) == -8); - ok &= math_test_helper("rnd_halfinttoeven(-8.4999f) == -8", itk::Math::RoundHalfIntegerToEven(-8.4999f)== -8); - ok &= math_test_helper("rnd_halfinttoeven(-8.50) == -8", itk::Math::RoundHalfIntegerToEven(-8.50) == -8); - ok &= math_test_helper("rnd_halfinttoeven(-8.50f) == -8", itk::Math::RoundHalfIntegerToEven(-8.50f) == -8); - ok &= math_test_helper("rnd_halfinttoeven(-8.5001) == -9", itk::Math::RoundHalfIntegerToEven(-8.5001) == -9); - ok &= math_test_helper("rnd_halfinttoeven(-8.5001f) == -9", itk::Math::RoundHalfIntegerToEven(-8.5001f)== -9); - ok &= math_test_helper("rnd_halfinttoeven(8.4999) == 8", itk::Math::RoundHalfIntegerToEven(8.4999) == 8); - ok &= math_test_helper("rnd_halfinttoeven(8.4999f) == 8", itk::Math::RoundHalfIntegerToEven(8.4999f) == 8); - ok &= math_test_helper("rnd_halfinttoeven(8.50) == 8", itk::Math::RoundHalfIntegerToEven(8.50) == 8); - ok &= math_test_helper("rnd_halfinttoeven(8.50f) == 8", itk::Math::RoundHalfIntegerToEven(8.50f) == 8); - ok &= math_test_helper("rnd_halfinttoeven(8.5001) == 9", itk::Math::RoundHalfIntegerToEven(8.5001) == 9); - ok &= math_test_helper("rnd_halfinttoeven(8.5001f) == 9", itk::Math::RoundHalfIntegerToEven(8.5001f) == 9); - - ok &= math_test_helper("rnd_halfinttoeven(-9.4999) == -9 ", itk::Math::RoundHalfIntegerToEven(-9.4999) == -9); - ok &= math_test_helper("rnd_halfinttoeven(-9.4999f) == -9 ", itk::Math::RoundHalfIntegerToEven(-9.4999f)== -9); - ok &= math_test_helper("rnd_halfinttoeven(-9.50) == -10", itk::Math::RoundHalfIntegerToEven(-9.50) == -10); - ok &= math_test_helper("rnd_halfinttoeven(-9.50f) == -10", itk::Math::RoundHalfIntegerToEven(-9.50f) == -10); - ok &= math_test_helper("rnd_halfinttoeven(-9.5001) == -10", itk::Math::RoundHalfIntegerToEven(-9.5001) == -10); - ok &= math_test_helper("rnd_halfinttoeven(-9.5001f) == -10", itk::Math::RoundHalfIntegerToEven(-9.5001f)== -10); - ok &= math_test_helper("rnd_halfinttoeven(9.4999) == 9 ", itk::Math::RoundHalfIntegerToEven(9.4999) == 9); - ok &= math_test_helper("rnd_halfinttoeven(9.4999f) == 9 ", itk::Math::RoundHalfIntegerToEven(9.4999f) == 9); - ok &= math_test_helper("rnd_halfinttoeven(9.50) == 10", itk::Math::RoundHalfIntegerToEven(9.50) == 10); - ok &= math_test_helper("rnd_halfinttoeven(9.50f) == 10", itk::Math::RoundHalfIntegerToEven(9.50f) == 10); - ok &= math_test_helper("rnd_halfinttoeven(9.5001) == 10", itk::Math::RoundHalfIntegerToEven(9.5001) == 10); - ok &= math_test_helper("rnd_halfinttoeven(9.5001f) == 10", itk::Math::RoundHalfIntegerToEven(9.5001f) == 10); - - ok &= math_test_helper("rnd_halfintup(-8.4999) == -8", itk::Math::RoundHalfIntegerUp(-8.4999) == -8); - ok &= math_test_helper("rnd_halfintup(-8.4999f) == -8", itk::Math::RoundHalfIntegerUp(-8.4999f)== -8); - ok &= math_test_helper("rnd_halfintup(-8.50) == -8", itk::Math::RoundHalfIntegerUp(-8.50) == -8); - ok &= math_test_helper("rnd_halfintup(-8.50f) == -8", itk::Math::RoundHalfIntegerUp(-8.50f) == -8); - ok &= math_test_helper("rnd_halfintup(-8.5001) == -9", itk::Math::RoundHalfIntegerUp(-8.5001) == -9); - ok &= math_test_helper("rnd_halfintup(-8.5001f) == -9", itk::Math::RoundHalfIntegerUp(-8.5001f)== -9); - ok &= math_test_helper("rnd_halfintup(8.4999) == 8", itk::Math::RoundHalfIntegerUp(8.4999) == 8); - ok &= math_test_helper("rnd_halfintup(8.4999f) == 8", itk::Math::RoundHalfIntegerUp(8.4999f) == 8); - ok &= math_test_helper("rnd_halfintup(8.50) == 9", itk::Math::RoundHalfIntegerUp(8.50) == 9); - ok &= math_test_helper("rnd_halfintup(8.50f) == 9", itk::Math::RoundHalfIntegerUp(8.50f) == 9); - ok &= math_test_helper("rnd_halfintup(8.5001) == 9", itk::Math::RoundHalfIntegerUp(8.5001) == 9); - ok &= math_test_helper("rnd_halfintup(8.5001f) == 9", itk::Math::RoundHalfIntegerUp(8.5001f) == 9); - - ok &= math_test_helper("rnd_halfintup(-9.4999) == -9 ", itk::Math::RoundHalfIntegerUp(-9.4999) == -9); - ok &= math_test_helper("rnd_halfintup(-9.4999f) == -9 ", itk::Math::RoundHalfIntegerUp(-9.4999f)== -9); - ok &= math_test_helper("rnd_halfintup(-9.50) == -9 ", itk::Math::RoundHalfIntegerUp(-9.50) == -9); - ok &= math_test_helper("rnd_halfintup(-9.50f) == -9 ", itk::Math::RoundHalfIntegerUp(-9.50f) == -9); - ok &= math_test_helper("rnd_halfintup(-9.5001) == -10", itk::Math::RoundHalfIntegerUp(-9.5001) == -10); - ok &= math_test_helper("rnd_halfintup(-9.5001f) == -10", itk::Math::RoundHalfIntegerUp(-9.5001f)== -10); - ok &= math_test_helper("rnd_halfintup(9.4999) == 9 ", itk::Math::RoundHalfIntegerUp(9.4999) == 9); - ok &= math_test_helper("rnd_halfintup(9.4999f) == 9 ", itk::Math::RoundHalfIntegerUp(9.4999f) == 9); - ok &= math_test_helper("rnd_halfintup(9.50) == 10", itk::Math::RoundHalfIntegerUp(9.50) == 10); - ok &= math_test_helper("rnd_halfintup(9.50f) == 10", itk::Math::RoundHalfIntegerUp(9.50f) == 10); - ok &= math_test_helper("rnd_halfintup(9.5001) == 10", itk::Math::RoundHalfIntegerUp(9.5001) == 10); - ok &= math_test_helper("rnd_halfintup(9.5001f) == 10", itk::Math::RoundHalfIntegerUp(9.5001f) == 10); - - ok &= math_test_helper("floor(8.0) == 8", itk::Math::Floor(8.0) == 8); - ok &= math_test_helper("floor(8.0f) == 8", itk::Math::Floor(8.0f) == 8); - ok &= math_test_helper("floor(8.9999) == 8", itk::Math::Floor(8.9999) == 8); - ok &= math_test_helper("floor(8.9999f) == 8", itk::Math::Floor(8.9999f) == 8); - ok &= math_test_helper("floor(8.0001) == 8", itk::Math::Floor(8.0001) == 8); - ok &= math_test_helper("floor(8.0001f) == 8", itk::Math::Floor(8.0001f) == 8); - ok &= math_test_helper("floor(-8.0) == -8", itk::Math::Floor(-8.0) == -8); - ok &= math_test_helper("floor(-8.0f) == -8", itk::Math::Floor(-8.0f) == -8); - ok &= math_test_helper("floor(-8.9999) == -9", itk::Math::Floor(-8.9999) == -9); - ok &= math_test_helper("floor(-8.9999f) == -9", itk::Math::Floor(-8.9999f) == -9); - ok &= math_test_helper("floor(-8.0001) == -9", itk::Math::Floor(-8.0001) == -9); - ok &= math_test_helper("floor(-8.0001f) == -9", itk::Math::Floor(-8.0001f) == -9); - - ok &= math_test_helper("floor(9.0) == 9 ", itk::Math::Floor(9.0) == 9); - ok &= math_test_helper("floor(9.0f) == 9 ", itk::Math::Floor(9.0f) == 9); - ok &= math_test_helper("floor(9.9999) == 9 ", itk::Math::Floor(9.9999) == 9); - ok &= math_test_helper("floor(9.9999f) == 9 ", itk::Math::Floor(9.9999f) == 9); - ok &= math_test_helper("floor(9.0001) == 9 ", itk::Math::Floor(9.0001) == 9); - ok &= math_test_helper("floor(9.0001f) == 9 ", itk::Math::Floor(9.0001f) == 9); - ok &= math_test_helper("floor(-9.0) == -9 ", itk::Math::Floor(-9.0) == -9); - ok &= math_test_helper("floor(-9.0f) == -9 ", itk::Math::Floor(-9.0f) == -9); - ok &= math_test_helper("floor(-9.9999) == -10", itk::Math::Floor(-9.9999) == -10); - ok &= math_test_helper("floor(-9.9999f) == -10", itk::Math::Floor(-9.9999f) == -10); - ok &= math_test_helper("floor(-9.0001) == -10", itk::Math::Floor(-9.0001) == -10); - ok &= math_test_helper("floor(-9.0001f) == -10", itk::Math::Floor(-9.0001f) == -10); - - ok &= math_test_helper("ceil(8.0) == 8", itk::Math::Ceil(8.0) == 8); - ok &= math_test_helper("ceil(8.0f) == 8", itk::Math::Ceil(8.0f) == 8); - ok &= math_test_helper("ceil(8.9999) == 9", itk::Math::Ceil(8.9999) == 9); - ok &= math_test_helper("ceil(8.9999f) == 9", itk::Math::Ceil(8.9999f) == 9); - ok &= math_test_helper("ceil(8.0001) == 9", itk::Math::Ceil(8.0001) == 9); - ok &= math_test_helper("ceil(8.0001f) == 9", itk::Math::Ceil(8.0001f) == 9); - ok &= math_test_helper("ceil(-8.0) == -8", itk::Math::Ceil(-8.0) == -8); - ok &= math_test_helper("ceil(-8.0f) == -8", itk::Math::Ceil(-8.0f) == -8); - ok &= math_test_helper("ceil(-8.9999) == -8", itk::Math::Ceil(-8.9999) == -8); - ok &= math_test_helper("ceil(-8.9999f) == -8", itk::Math::Ceil(-8.9999f) == -8); - ok &= math_test_helper("ceil(-8.0001) == -8", itk::Math::Ceil(-8.0001) == -8); - ok &= math_test_helper("ceil(-8.0001f) == -8", itk::Math::Ceil(-8.0001f) == -8); - - ok &= math_test_helper("ceil(9.0) == 9 ", itk::Math::Ceil(9.0) == 9); - ok &= math_test_helper("ceil(9.0f) == 9 ", itk::Math::Ceil(9.0f) == 9); - ok &= math_test_helper("ceil(9.9999) == 10", itk::Math::Ceil(9.9999) == 10); - ok &= math_test_helper("ceil(9.9999f) == 10", itk::Math::Ceil(9.9999f) == 10); - ok &= math_test_helper("ceil(9.0001) == 10", itk::Math::Ceil(9.0001) == 10); - ok &= math_test_helper("ceil(9.0001f) == 10", itk::Math::Ceil(9.0001f) == 10); - ok &= math_test_helper("ceil(-9.0) == -9 ", itk::Math::Ceil(-9.0) == -9); - ok &= math_test_helper("ceil(-9.0f) == -9 ", itk::Math::Ceil(-9.0f) == -9); - ok &= math_test_helper("ceil(-9.9999) == -9 ", itk::Math::Ceil(-9.9999) == -9); - ok &= math_test_helper("ceil(-9.9999f) == -9 ", itk::Math::Ceil(-9.9999f) == -9); - ok &= math_test_helper("ceil(-9.0001) == -9 ", itk::Math::Ceil(-9.0001) == -9); - ok &= math_test_helper("ceil(-9.0001f) == -9 ", itk::Math::Ceil(-9.0001f) == -9); + std::cout<<" T,vxl_int_64,float,ceil"<<std::endl; + ok &= itkCeilTest<vxl_int_64, float>(itk::Math::Ceil<vxl_int_64, float>); + std::cout<<" T,vxl_int_64,double,ceil"<<std::endl; + ok &= itkCeilTest<vxl_int_64,double>(itk::Math::Ceil<vxl_int_64,double>); if (!ok) { Index: Testing/Code/Common/itkMathRoundProfileTest1.cxx =================================================================== RCS file: /cvsroot/Insight/Insight/Testing/Code/Common/itkMathRoundProfileTest1.cxx,v retrieving revision 1.3 diff -u -r1.3 itkMathRoundProfileTest1.cxx --- Testing/Code/Common/itkMathRoundProfileTest1.cxx 2 Jun 2009 20:45:16 -0000 1.3 +++ Testing/Code/Common/itkMathRoundProfileTest1.cxx 30 Jul 2009 12:39:46 -0000 @@ -18,10 +18,9 @@ #pragma warning ( disable : 4786 ) #endif -#include "itkMacro.h" +#include "itkMath.h" #include "itkTimeProbesCollectorBase.h" -#include "vnl/vnl_math.h" -#include <math.h> +#include <cmath> int itkMathRoundTestHelperFunction( double x ) { | ||||||||
Relationships | ||||||
|
Relationships |
Notes | |
(0011885) mnieber (reporter) 2008-05-14 03:25 |
I noticed in the overview that my last post has been missed (no offense taken :-). It is in reply to the post starting with "let me elaborate why I am voting for a center-based coordinate system". Best regards, Maarten Hi Andreas, it seems to me that the problems you indicate are related to the question: what is the co-ordinate of a pixel? The way I see it, a pixel has no co-ordinate (but it has an area). I could rephrase your step1 one as follows: 1. For the given output index, calculate the co-ordinate >at the center< of the corresponding output pixel. Ideally, this should be performed by a helper function: IndexToPhysicalCoordinateAtPixelCenter(). Note that the output of this function depends on whether you have the origin of the image at the bottom left or center of a pixel. For a 'bottom-left' representation, the function IndexToPhysicalCoordinateAtPixelCenter(0) would return 0.5 * imageSpacing, whereas for a 'center' representation, it would be zero. However, the writer of the resample algorithm will not be concerned with this, because in both cases IndexToPhysicalCoordinateAtPixelCenter() will return the co-ordinate at the center of the pixel, and the algorithm will perform correctly. Best regards, and looking forward to your replies too, Maarten |
(0011890) Volker Daum (reporter) 2008-05-14 04:57 |
To add to Ruperts observations: itk::NearestNeighborInterpolateImageFunction uses rounding, therefore conforms to the documentation. itk::LinearInterpolateImageFunction uses floor (or something like it) to generate the base index and then generates the remaining needed indices from this (by adding +1 along the different dimensions). This also conforms to the documentation. itk::BSplineInterpolateImageFunction seems to (as far as I understood by looking at it just shortly) conform to the documentation as well. The interpolate image functions (as a quick grep shows) seem to be more widely used in the ITK source than the Transform method, which makes sense, since anyone concerned about sub-pixel accuracy will probably want to use interpolation of some kind. They are also used in the ResampleImageFilter, which is probably used in most user code that does resampling. Therefore I would urge to fix the bug in the TransformPhysicalPointToIndex method to conform with the documentation and the rest of the interpolators, as this is the solution that will affect the least other code. (I suspect this is also true for most user code. It definitly is for mine). |
(0011891) Andreas Keil (reporter) 2008-05-14 07:40 |
Another argument for center-based physical coordinates: DICOM explicitly specifies that coordinates are center-based, see e.g. the Image Position Patient tag (0020,0032) (explained in section C.7.6.2.1.1) and the section on deformable registration C.20.3.1. ITK is not DICOM but DICOM is the standard for medical imaging and I bet that DICOM tags are currently not converted to corner-based coordinates when reading DICOM with ITK (gdcm). |
(0011961) Andreas Keil (reporter) 2008-05-16 09:43 |
The discussion on this topic has moved to the following ITK Wiki page: http://www.itk.org/Wiki/Proposals:Refactoring_Index_Point_Coordinate_System [^] I'll try to compile the information from this bug report into the Wiki page. Please feel free, to add your own comments there, too. |
(0014214) Tom Vercauteren (developer) 2008-11-27 10:58 |
I have upload a preliminary patch. It allows the use of centered pixels in a consistent manner but only applies to the very core of ITK. It can be switched on or off from CMake. More work is required to make all unit tests pass. |
(0016302) Luis Ibanez (manager) 2009-05-05 16:27 |
Michel and Luis have continued fixing secondary effects of the original patch. The current cumulative patch has been uploaded in the file: CenteredPixelCoordinatesMay-5-2009.patch |
(0016304) Luis Ibanez (manager) 2009-05-05 17:59 |
An updated patch has been uploaded with the name CenteredPixelCoordinatesMay-5-2009-B.patch (Note the "-B") It contains additional fixes for the Origin of the output image in file itkGradientImageToBloxBoundaryPointImageFilter.txx |
(0016502) Luis Ibanez (manager) 2009-05-16 12:06 |
The patch itk-portable-round-2009-05-16.patch has just been committed. |
(0018149) Bradley Lowekamp (developer) 2009-10-21 16:57 |
The patch itk-templatedmathround-2009-07-30.patch has been committed with some modifications. |
(0022566) Hans Johnson (developer) 2010-10-21 11:15 |
If this is still an issue, please reopen the bug |
Notes |
Issue History | |||
Date Modified | Username | Field | Change |
2008-03-07 05:20 | Andreas Keil | New Issue | |
2008-05-14 03:25 | mnieber | Note Added: 0011885 | |
2008-05-14 04:57 | Volker Daum | Note Added: 0011890 | |
2008-05-14 07:40 | Andreas Keil | Note Added: 0011891 | |
2008-05-16 09:43 | Andreas Keil | Note Added: 0011961 | |
2008-11-27 10:54 | Tom Vercauteren | File Added: itk-bug6558.patch | |
2008-11-27 10:58 | Tom Vercauteren | Note Added: 0014214 | |
2009-04-20 16:41 | Luis Ibanez | Status | new => assigned |
2009-04-20 16:41 | Luis Ibanez | Assigned To | => MichelKitware |
2009-05-05 16:26 | Luis Ibanez | File Added: CenteredPixelCoordinatesMay-5-2009.patch | |
2009-05-05 16:27 | Luis Ibanez | Note Added: 0016302 | |
2009-05-05 17:57 | Luis Ibanez | File Added: CenteredPixelCoordinatesMay-5-2009-B.patch | |
2009-05-05 17:59 | Luis Ibanez | Note Added: 0016304 | |
2009-05-11 18:41 | Luis Ibanez | File Added: PortableRound-May-11-2009.patch | |
2009-05-12 08:46 | Tom Vercauteren | File Added: itk-portable-round-2009-05-12.patch | |
2009-05-15 12:50 | Tom Vercauteren | File Added: itk-portable-round-2009-05-15.patch | |
2009-05-16 12:06 | Luis Ibanez | Note Added: 0016502 | |
2009-05-16 12:07 | Luis Ibanez | File Added: itk-portable-round-2009-05-16.patch | |
2009-05-26 08:48 | Tom Vercauteren | File Added: itk-portable-round-2009-05-26-bis.patch | |
2009-07-27 12:48 | Tom Vercauteren | File Added: itk-templatedmathround-2009-07-27.patch | |
2009-07-30 08:41 | Tom Vercauteren | File Added: itk-templatedmathround-2009-07-30.patch | |
2009-10-21 16:57 | Bradley Lowekamp | Note Added: 0018149 | |
2010-10-21 11:15 | Hans Johnson | Sprint Status | => backlog |
2010-10-21 11:15 | Hans Johnson | Note Added: 0022566 | |
2010-10-21 11:15 | Hans Johnson | Status | assigned => closed |
2010-10-21 11:15 | Hans Johnson | Resolution | open => fixed |
2010-11-04 23:06 | Cory W Quammen | Relationship added | has duplicate 0000738 |
Issue History |
Copyright © 2000 - 2018 MantisBT Team |