MantisBT - ITK
View Issue Details
0002078ITKpublic2005-07-26 11:042009-07-07 05:23
Nicolas Savoire 
user390 
highmajoralways
closedfixed 
 
 
0002078: BSplineFloor in itkBSplineInterpolationWeightFunction.txx is incorrect
fast floor function BSplineFloor is incorrect:
it casts an int pointer to an double pointer, which is forbidden by ISO C standard: the standard says that two different pointers may not point to the same location, as a result when optimizing the BSplineFloor function, the dereferencement and assignement of the double pointer is optimized away.
A solution would be to use an union...
No tags attached.
duplicate of 0005692closed Andinet small problem with BSplineFloor 
Issue History
2007-09-21 15:56Luis IbanezStatusresolved => closed
2007-09-21 15:56Luis IbanezNote Added: 0009206
2007-09-24 02:44Nicolas SavoireStatusclosed => feedback
2007-09-24 02:44Nicolas SavoireResolutionfixed => reopened
2007-09-24 02:44Nicolas SavoireNote Added: 0009269
2007-09-24 08:34Luis IbanezNote Added: 0009270
2007-09-24 08:46Nicolas SavoireNote Added: 0009272
2007-09-24 20:35dbrussakNote Added: 0009279
2007-10-08 08:21Luis IbanezRelationship addedrelated to 0005692
2007-12-16 09:34Aviv HurvitzNote Added: 0009942
2009-06-16 04:04Tom VercauterenNote Added: 0016727
2009-06-16 04:04Tom VercauterenRelationship replacedduplicate of 0005692
2009-06-16 04:04Tom VercauterenDuplicate ID0 => 5692
2009-06-16 04:04Tom VercauterenStatusfeedback => resolved
2009-06-16 04:04Tom VercauterenResolutionreopened => fixed
2009-07-07 05:23Tom VercauterenStatusresolved => closed

Notes
(0002729)
Nicolas Savoire   
2005-07-27 11:55   
A similarly incorrect function is used in BilateralImageFilter.
(0002771)
Lydia Ng   
2005-08-05 15:02   
Triaged 8/5/05 tcon.
Jim will look at it.
(0002810)
Nicolas Savoire   
2005-08-08 03:45   
I forgot to add that the bug affects only the i386 platform.

Replacing
  unsigned int hilo[2];
  *((double *)hilo) = x + 103079215104.0;
  return (int)((hilo[1]<<16)|(hilo[0]>>16));
by
  union { unsigned int hilo[2]; double d; } u;
  u.d = x + 103079215104.0;
  return (int)((u.hilo[1]<<16)|(u.hilo[0]>>16));
seems to fix the problem.
 
(0002917)
Nicolas Savoire   
2005-08-18 08:12   
Another thing: the bug seems to appear only with gcc 3.4 and flag -O2/-O3
(0003285)
user390   
2005-11-20 23:34   
Committed to the Main branch.
http://www.itk.org/cgi-bin/viewcvs.cgi/Code/Common/itkBSplineInterpolationWeightFunction.txx?rev=1.10&root=Insight&view=log [^]
http://www.itk.org/cgi-bin/viewcvs.cgi/Code/BasicFilters/itkBilateralImageFilter.txx?rev=1.25&root=Insight&view=log [^]
(0009206)
Luis Ibanez   
2007-09-21 15:56   
correcting 'resolved' status to 'closed'
(0009269)
Nicolas Savoire   
2007-09-24 02:44   
It seems that the returned value is wrong for inputs really close but smaller than a given integer:
BSplineFloor(0.999999) returns 1 instead of 0.

I think the issue is the addition of a large constant value which triggers a loss of precision.
(0009270)
Luis Ibanez   
2007-09-24 08:34   
Nicos,

Can you please provide a test program that illustrate this problem ?
We need a test in order to track the issue.

Also, is it still the case that this error is only observed
in gcc 3.4 with flags -O2/O3 ?

For the long term maintenance it seems better to use vcl_floor().

Whether this is a performance issue or not, is something that we
have to verify by using a profiling test. Are we saving 1% of the
computation time ?
is it 10% ?
is it 50% ?

For 1% of computation time savings, we probably shouldn't sacrifice
portability and maintainability...


  Thanks


     Luis
(0009272)
Nicolas Savoire   
2007-09-24 08:46   
The problem appears on i386 (linux and OSX) platform. Compilation flags and gcc version have no influence on the result.

Test case:
#include <assert.h>

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
}

int main ()
{
  assert(BSplineFloor(0.999999)==0);
}
(0009279)
dbrussak   
2007-09-24 20:35   
Hi,
  This particular BSplineFloor() precision issue is the one I reported here in issue 0005692:
http://www.itk.org/Bug/view.php?id=5692 [^]
  
I'm happy to delete/rescind my issue and just wait for resolution of this one. Is that possible?

  Daniel R.
(0009942)
Aviv Hurvitz   
2007-12-16 09:34   
I've also run into the problem where BSplineFloor returns an incorrect result. This caused BSPlineDeformableTransform ::TransformPoint() to SEGFAULT.

Tested on a Pentium 4. Compiled with:
- gcc version 4.1.3 20070629 (prerelease) (Debian 4.1.2-13)
- MS Visual C++ 2005

A sample program:

>>>>>>>>>>>>>>>>>>>>>>>>>

#include <iostream>
#include <math.h>

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
}


int main(int argc, char *argv[])
{
    double x = 16.999995;

    int bsplineFloorResult = BSplineFloor(x);
    int standardFloor = static_cast<int>( floor(x) );
    
    std::cout.precision(20);
    std::cout << "x = " << x << std::endl;
    std::cout << "BSspline_floor = " << bsplineFloorResult << std::endl;
    std::cout << "Standard floor = " << standardFloor << std::endl;

    /* Prints:
       x = 16.999994999999998413
       BSspline_floor = 17
       Standard floor = 16
    */
    return 0;
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
(0016727)
Tom Vercauteren   
2009-06-16 04:04   
Fixed in HEAD:
http://www.itk.org/cgi-bin/viewcvs.cgi/Code/Common/itkBSplineInterpolationWeightFunction.txx?root=Insight&r1=1.15&r2=1.16&sortby=date [^]
http://www.itk.org/cgi-bin/viewcvs.cgi/Code/BasicFilters/itkBilateralImageFilter.txx?root=Insight&r1=1.29&r2=1.30&sortby=date [^]