From: Igor Tandetnik on
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
* 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
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
"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
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