|
From: Igor Tandetnik on 9 May 2008 13:03 3DCoderGuy <nobody(a)nospam.com> wrote: > template<typename T> > class XYZPoint > { > template<typename T> > bool const operator==(const XYZPoint<T> &xyzTest) const Do you want XYZPoint<SomeType> to be comparable to XYZPoint<SomeOtherType>? This is what your template method provides. > > bool const operator==(const XYZPoint<float> &xyzTest) const > > bool const operator==(const XYZPoint<double> &xyzTest) const > }; > > I'm new to templates so I don't understand why (and would like too if > some one can explain). But this works. This would invoke the overloads in mixed-type comparisons. For a contrived example, try XYZPoint<char*> ps; XYZPoint<float> pf; ps == pf; It's also surprisingly asymmetrical: XYZPoint<float> pf; XYZPoint<double> pd; pd == pf; // calls float overload pf == pd; // calls double overload This may lead to a situation where a==b but !(b==a) -- With best wishes, Igor Tandetnik With sufficient thrust, pigs fly just fine. However, this is not necessarily a good idea. It is hard to be sure where they are going to land, and it could be dangerous sitting under them as they fly overhead. -- RFC 1925
From: Alf P. Steinbach on 9 May 2008 13:09 * 3DCoderGuy: > I'm trying to specialize the operator== for my template, here is my code > > #define DOUBLE_EPSILON (1e-6) > #define FLOAT_EPSILON (1e-4f) > > bool const operator==(const XYZPoint<T> &xyzTest) const > { > return ( > (x == xyzTest.x) && > (y == xyzTest.y) && > (z == xyzTest.z) > ); > }; > > template<typename T> > bool const operator==(const XYZPoint<float> &xyzTest) const > { > return ( > (x - xyzTest.x < FLOAT_EPSILON) && (x - xyzTest.x > -FLOAT_EPSILON) && > (y - xyzTest.y < FLOAT_EPSILON) && (y - xyzTest.y > -FLOAT_EPSILON) && > (z - xyzTest.z < FLOAT_EPSILON) && (z - xyzTest.z > -FLOAT_EPSILON) > ); > } > > template<typename T> > bool const operator==(const XYZPoint<double> &xyzTest) const > { > return ( > (x - xyzTest.x < DOUBLE_EPSILON) && (x - xyzTest.x > -DOUBLE_EPSILON) && > (y - xyzTest.y < DOUBLE_EPSILON) && (y - xyzTest.y > -DOUBLE_EPSILON) && > (z - xyzTest.z < DOUBLE_EPSILON) && (z - xyzTest.z > -DOUBLE_EPSILON) > ); > } > > But when I do this > XYZPoint<double> pnt1(1.0,0.0,1.0); > XYZPoint<double> pnt2(1.0,0.0,2.0); > > if (pnt1 == pnt2) > { > ... > } > > the specialization for <double> is never called. > > Can this be done, and what would be the correct syntax? Others have remarked on syntax etc. However, if you really want to do this epsilon thing (note: it means you lose the important property that a==b && b==c implies a==c, which means it's really not a good idea, at least as long as you pretend that it's '==' equality), then I suggest you pick up the relevant epsilon from a template: <code> template< typename T > struct EpsilonFor { static T const value; }; template<> float const EpsilonFor<float>::value = 1.e-4f; template<> double const EpsilonFor<double>::value = 1.e-6; template< typename FloatType > bool isNearEqual( FloatType a, FloatType b ) { return (std::abs( a - b ) <= EpsilonFor<FloatType>::value); } </code> Cheers, & hth., - Alf PS: Are you aware of std::numeric_limits? If not, take a look. -- A: Because it messes up the order in which people normally read text. Q: Why is it such a bad thing? A: Top-posting. Q: What is the most annoying thing on usenet and in e-mail?
From: 3DCoderGuy on 9 May 2008 13:38 Alf P. Steinbach wrote: > * 3DCoderGuy: >> Snip... > > Others have remarked on syntax etc. > > However, if you really want to do this epsilon thing (note: it means you > lose the important property that a==b && b==c implies a==c, which means > it's really not a good idea, at least as long as you pretend that it's > '==' equality), then I suggest you pick up the relevant epsilon from a > template: > > > <code> > template< typename T > > struct EpsilonFor > { > static T const value; > }; > > template<> > float const EpsilonFor<float>::value = 1.e-4f; > > template<> > double const EpsilonFor<double>::value = 1.e-6; > > > > template< typename FloatType > > bool isNearEqual( FloatType a, FloatType b ) > { > return (std::abs( a - b ) <= EpsilonFor<FloatType>::value); > } > </code> > > > Cheers, & hth., > > - Alf > > > PS: Are you aware of std::numeric_limits? If not, take a look. > What took you so long Alf. I was wondering how to do just what you're suggesting. Thanks a ton. I wasn't aware of the std::numeric_limits. I'm very green when it comes to std. I've used std containers and only very limited. I noticed you use the abs method. Back in the day when optimization was important (and is become so again), I wouldn't use the abs because of the call which used a lot of cycles ( I really don't know if that is still true today. I haven't written assembler since 80486s). Doing the (x1 - x2 < EPSILON) && (...) would mean that the test on points that were different would fail on the first difference. Do you have any comments on this? I take from you last discussion regarding wasted copies to temp objects that optimization is important to you. Thanks again Alf. Mark
From: Alex Blekhman on 10 May 2008 09:57 "3DCoderGuy" wrote: > I'm trying to specialize the operator== for my template, here is > my code > > #define DOUBLE_EPSILON (1e-6) > #define FLOAT_EPSILON (1e-4f) > [...] > template<typename T> > bool const operator==(const XYZPoint<float> &xyzTest) const > { > return ( > (x - xyzTest.x < FLOAT_EPSILON) && (x - xyzTest.x > > -FLOAT_EPSILON) && > (y - xyzTest.y < FLOAT_EPSILON) && (y - xyzTest.y > > -FLOAT_EPSILON) && > (z - xyzTest.z < FLOAT_EPSILON) && (z - xyzTest.z > > -FLOAT_EPSILON) > ); > } Others already pointed the problematic floating point comparison. You can use an example from the following article: "Why Floating-Point Numbers May Lose Precision" http://msdn.microsoft.com/en-us/library/c151dt3s.aspx Also, there are predefined constants FLT_EPSILON and DBL_EPSILON in "float.h" header, so you don't need to define your own. HTH Alex
From: 3DCoderGuy on 12 May 2008 11:15
Alex Blekhman wrote: > "3DCoderGuy" wrote: >> I'm trying to specialize the operator== for my template, here is >> my code >> >> #define DOUBLE_EPSILON (1e-6) >> #define FLOAT_EPSILON (1e-4f) >> [...] >> template<typename T> >> bool const operator==(const XYZPoint<float> &xyzTest) const >> { >> return ( >> (x - xyzTest.x < FLOAT_EPSILON) && (x - xyzTest.x >> > -FLOAT_EPSILON) && >> (y - xyzTest.y < FLOAT_EPSILON) && (y - xyzTest.y >> > -FLOAT_EPSILON) && >> (z - xyzTest.z < FLOAT_EPSILON) && (z - xyzTest.z >> > -FLOAT_EPSILON) >> ); >> } > > Others already pointed the problematic floating point comparison. > You can use an example from the following article: > > "Why Floating-Point Numbers May Lose Precision" > http://msdn.microsoft.com/en-us/library/c151dt3s.aspx > > Also, there are predefined constants FLT_EPSILON and DBL_EPSILON > in "float.h" header, so you don't need to define your own. > > HTH > Alex > > Thanks for the suggestions Alex. The reason we don't use the predefined ones is the precision is to small. Mark |