Topic: Operator ~= Anyone else think it would be useful?


Author: reply-to@valid.address (Steve Rencontre)
Date: Mon, 24 Apr 2006 01:08:26 GMT
Raw View
Andrei Polushin wrote:
[...]
>> I believe that my operator ~= suggestion fits that pattern of increased
>> clarity.
>
> Well, look at code.
>
> Mine:
>
>   inexact_t<double> a(2.5, 0.5);
>
>   if (a == 2.3)
>     do_something();
>
> Yours:
>
>   CApproximatelyEqual<double> a(2.5);
>   CApproximatelyEqual<double>::SetEpsilon(0.5); // global?
>
>   if (a ~= 2.3)
>     do_something();
>
> Is the clarity increased?

That's not how I was thinking of doing it.

 namespace {

 class epsilon_t {
 public:
  static void set (double e) { epsilon = t; }
  static double get() { return epsilon; }
 private:
  static double epsilon;
 };

 double epsilon_t::epsilon;

 bool operator ~= (double t1, double t2)
  { return abs(t1-t2) < epsilon_t::get(); }

 bool operator ~= (const string& s1, const string& s1)
  { return stricmp (s1.c_str(), s2.c_str()) == 0); }

 } // end unnamed namespace

 ...

 epsilon_t::set (0.5);

 double a = 2.4;

 a -= 0.1;

 if (a == 2.3)
  cout << "Exactly equal\n";
 else if (a ~= 2.3)
  cout << "Close enough for government work\n";

 ...

 string s1 = "To be or not to be";
 string s2 = get_random_shakesperean_quote();

 if (s1 ~= s2)
 {
  cout << "Got a bit of Hamlet\n";

  if (s1 == s2)
   cout << "With desired capitalisation\n";
 }

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Tue, 25 Apr 2006 04:32:03 GMT
Raw View
Steve Rencontre ha scritto:
>
> I don't see a lot of benefit over a simple comparison function, or
> possibly a comparator function object, eg:
>
>  template <typename T>
>  class approximately_equal
>  {
>  public:
>   approximately_equal (T t) : epsilon (t) {}
>   bool operator() (T t1, T t2)
>    { return abs (t1 - t2) < epsilon: }
>  private:
>   T epsilon;
>  };
>
>  if (approximately_equal (0.5) (2.3, 2.5))
>   ...
>

You are missing the very important fact that Andrei's approach let you
specify the epsilon on a per-value basis rather than on the comparison
object. That make his class very useful in a lot of application fields.
You could even do mathematics with that class, as you can redefine other
operators like operator+. Moreover, as he redefines operator==, his
object can be used as-is in algorithms like std::find that do not allow
you to specify a comparison functor.

> There are plenty of ways to express the basic functionality, but the
> whole point of infix operator notation is that
>
>  a = b + c;
>
> is generally held to be clearer than alternatives like
>
>  a.assign (plus (b, c)):
>
> I believe that my operator ~= suggestion fits that pattern of increased
> clarity.

Well... you are seeing the expression "inexact(2.5, 0.5) == 2.3" as a
weird way to specify the epsilon. That's not the only point of view. I
see inexact() as a sort of constructor of inexact_t objects (that's what
it does, really). If you see it that way, then Andrei's solution
compares two objects (one inexact_t and one double) with infix notation
and looks very clear and elegant to me.

Just my opinion,

Ganesh

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: reply-to@valid.address (Steve Rencontre)
Date: Wed, 26 Apr 2006 01:56:40 GMT
Raw View
Alberto Ganesh Barbati wrote:
> Steve Rencontre ha scritto:
>> I don't see a lot of benefit over a simple comparison function, or
>> possibly a comparator function object, eg:
>>
>>  template <typename T>
>>  class approximately_equal
>>  {
>>  public:
>>   approximately_equal (T t) : epsilon (t) {}
>>   bool operator() (T t1, T t2)
>>    { return abs (t1 - t2) < epsilon: }
>>  private:
>>   T epsilon;
>>  };
>>
>>  if (approximately_equal (0.5) (2.3, 2.5))
>>   ...
>>
>
> You are missing the very important fact that Andrei's approach let you
> specify the epsilon on a per-value basis rather than on the comparison
> object.

It's not so much that I'm missing the point, more that it's not the idea
that I'm trying to express.

The syntax

 a ~= b

is meant to convey the meaning, "a and b are equivalent for the purpose
at hand", without regard to how that equivalence happens to be defined.
Andrei's inexact<T> object, like my functor example, both embed too much
context into the expression.

> That make his class very useful in a lot of application fields.
> You could even do mathematics with that class, as you can redefine
> other operators like operator+. Moreover, as he redefines operator==,
> his object can be used as-is in algorithms like std::find that do not
> allow you to specify a comparison functor.

That's fine, although I would argue that interval arithmetic is a better
solution to that particular problem.

Moreover, if I have to interoperate with some existing code that uses
std::find, I may well have no choice but to define some kind of wrapper
object to override operator==, but in most cases, I'd prefer to use
std::find_if if I don't want true equality testing.

> Well... you are seeing the expression "inexact(2.5, 0.5) == 2.3" as a
> weird way to specify the epsilon. That's not the only point of view. I
> see inexact() as a sort of constructor of inexact_t objects (that's what
> it does, really). If you see it that way, then Andrei's solution
> compares two objects (one inexact_t and one double) with infix notation
> and looks very clear and elegant to me.

I see it as unnecessarily introducing a new object just so we can make
== mean something different from what we would normally expect. To me,
this is wrong - I don't want to create an object with funny equality
semantics, I want to apply a user-defined comparison operator to the
objects I already have.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "thoth39" <pedro.lamarao@gmail.com>
Date: Wed, 26 Apr 2006 16:11:25 CST
Raw View
Steve Rencontre a    crit :
> It's not so much that I'm missing the point, more that it's not the idea
> that I'm trying to express.
>
> The syntax
>
>  a ~= b
>
> is meant to convey the meaning, "a and b are equivalent for the purpose
> at hand", without regard to how that equivalence happens to be defined.
> Andrei's inexact<T> object, like my functor example, both embed too much
> context into the expression.

Assuming T is the type of a and b.

So, how does the user of the library providing type T declare his
desired value for the epsilon? Is the responsibility of this user to
provide operator~= for this type?

What if he desires a different value for epsilon somewhere else in his
code? The same program can't have two definitions for this operator~=.


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: sjhoweATdialDOTpipexDOTcom@eu.uu.net ("Stephen Howe")
Date: Wed, 26 Apr 2006 23:21:46 GMT
Raw View
> The syntax
>
> a ~= b
>
> is meant to convey the meaning, "a and b are equivalent for the purpose
> at hand", without regard to how that equivalence happens to be defined.
> Andrei's inexact<T> object, like my functor example, both embed too much
> context into the expression.

Right. The problem I have with it is that transivitity may make break down.

Normally we have given objects a, b, c

a == b & b == c implies a == c

but you could easily have

a ~= b & b ~= c yet !(a ~= c) is true

Stephen Howe


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: reply-to@valid.address (Steve Rencontre)
Date: Thu, 27 Apr 2006 16:13:14 GMT
Raw View
Stephen Howe wrote:
>> The syntax
>>
>> a ~= b
>>
>> is meant to convey the meaning, "a and b are equivalent for the purpose
>> at hand", without regard to how that equivalence happens to be defined.
>> Andrei's inexact<T> object, like my functor example, both embed too much
>> context into the expression.
>
> Right. The problem I have with it is that transivitity may make break down.
>
> Normally we have given objects a, b, c
>
> a == b & b == c implies a == c
>
> but you could easily have
>
> a ~= b & b ~= c yet !(a ~= c) is true
>

That's true, but I don't see it as a problem, just a fact of life:
equivalence isn't necessarily transitive. If I want $100 I might be
prepared to take $75 and if I want $125 I might be prepared to accept
$100, but that doesn't imply that if I want $125 I'll be prepared to
accept $75.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: reply-to@valid.address (Steve Rencontre)
Date: Fri, 28 Apr 2006 01:55:55 GMT
Raw View
thoth39 wrote:
> Steve Rencontre a =E9crit :
>> It's not so much that I'm missing the point, more that it's not the id=
ea
>> that I'm trying to express.
>>
>> The syntax
>>
>>  a ~=3D b
>>
>> is meant to convey the meaning, "a and b are equivalent for the purpos=
e
>> at hand", without regard to how that equivalence happens to be defined.
>> Andrei's inexact<T> object, like my functor example, both embed too mu=
ch
>> context into the expression.
>=20
> Assuming T is the type of a and b.
>=20
> So, how does the user of the library providing type T declare his
> desired value for the epsilon? Is the responsibility of this user to
> provide operator~=3D for this type?

Yes, that's exactly the point. ~=3D is defined by the /user/ of a type,
not the /provider/ of the type.

> What if he desires a different value for epsilon somewhere else in his
> code? The same program can't have two definitions for this operator~=3D.

Yes it can: it can be declared multiple times in different namespaces,
including the unnamed namespaces of different translation units.
Alternatively, the comparison can be parameterised by means of some
additional helper function or static variable.

However, if the comparison is going to use many different criteria at
different times, especially in the same translation unit, then I don't
think ~=3D is the right way to do it. A conventional predicate function
would be the better choice then.

I think also, people are getting a bit hung up on the example of fuzzy
floating-point equality. To my mind, there are a lot of situations where
"equivalent in the circumstances" is a well defined concept distinct
from true equality. Apart from the case-insensitive string comparison I
originally mentioned, there are obvious natural-language rules such as
German "ue" ~=3D "u+umlaut", or domain-specific ones like,

 route1 ~=3D route2
iff
 route1.start =3D=3D route2.start &&
 route1.end =3D=3D route2.end &&
 route1.time_taken =3D=3D route2.time_taken

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: kuyper@wizard.net
Date: Thu, 27 Apr 2006 20:56:47 CST
Raw View
"Stephen Howe" wrote:
.
> Right. The problem I have with it is that transivitity may make break down.
>
> Normally we have given objects a, b, c
>
> a == b & b == c implies a == c
>
> but you could easily have
>
> a ~= b & b ~= c yet !(a ~= c) is true

Equality is transitive, approximate equality isn't. If an appropximate
equality operator were introduced, it would constitute a design error
to write code that assumes transitivity for that operator.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Fri, 28 Apr 2006 15:54:15 GMT
Raw View
In article <1146146249.322326.107160@u72g2000cwu.googlegroups.com>,
kuyper@wizard.net writes
>"Stephen Howe" wrote:
>.
>> Right. The problem I have with it is that transivitity may make break down.
>>
>> Normally we have given objects a, b, c
>>
>> a == b & b == c implies a == c
>>
>> but you could easily have
>>
>> a ~= b & b ~= c yet !(a ~= c) is true
>
>Equality is transitive, approximate equality isn't. If an appropximate
>equality operator were introduced, it would constitute a design error
>to write code that assumes transitivity for that operator.

Putting that aside (though without transitivity the facility seems
pretty useless to me which is one excellent reason why we do not have an
approximately equal operator) I would vehemently object to having ~= be
used for that purpose. It is already bad enough that

x op= y;

is not equivalent to

x = x op y;

if op is '!' or '='

There is enough existing irregularity in C++ without adding more
surprises and special case.

--
Francis Glassborow      ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: usenet-nospam@nmhq.net (Niklas Matthies)
Date: Fri, 28 Apr 2006 16:44:16 GMT
Raw View
On 2006-04-28 15:54, Francis Glassborow wrote:
> In article <1146146249.322326.107160@u72g2000cwu.googlegroups.com>,
> kuyper@wizard.net writes
:
>>Equality is transitive, approximate equality isn't. If an appropximate
>>equality operator were introduced, it would constitute a design error
>>to write code that assumes transitivity for that operator.
>
> Putting that aside (though without transitivity the facility seems
> pretty useless to me which is one excellent reason why we do not
> have an approximately equal operator) I would vehemently object to
> having ~= be used for that purpose.

'=~' (as in Perl) would be better, but it would break backward
compatibility.

-- Niklas Matthies

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: kuyper@wizard.net
Date: 28 Apr 2006 17:40:01 GMT
Raw View
Francis Glassborow wrote:
> In article <1146146249.322326.107160@u72g2000cwu.googlegroups.com>,
> kuyper@wizard.net writes
.
> >Equality is transitive, approximate equality isn't. If an appropximate
> >equality operator were introduced, it would constitute a design error
> >to write code that assumes transitivity for that operator.
>
> Putting that aside (though without transitivity the facility seems
> pretty useless to me which is one excellent reason why we do not have an
> approximately equal operator)

I've frequently needed to compare floating point numbers for
approximate equality; I can't remember any instance I would have wanted
the result to be transitive. Since I knew that it couldn't be
transitive, I probably instinctively avoided writing algorithms that
would have required it to be transitive - but I can't remember that
ever being a serious constraint.

I have to agree, however, that ~= would be bad notation, for precisely
the reasons you mention. I doubt that the concept can be made
sufficiently context-insenstive meaning to justify special
language-level support.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Andrei Polushin" <polushin@gmail.com>
Date: Fri, 28 Apr 2006 12:59:41 CST
Raw View
Francis Glassborow wrote:
> Putting that aside (though without transitivity the facility seems
> pretty useless to me which is one excellent reason why we do not have an
> approximately equal operator) I would vehemently object to having ~= be
> used for that purpose. It is already bad enough that
>
> x op= y;
>
> is not equivalent to
>
> x = x op y;
>
> if op is '!' or '='
>
> There is enough existing irregularity in C++ without adding more
> surprises and special case.

You know that Perl uses the reverse:

  =~    for "matches"
  !~    for "not matches"

with the approximately equivalent syntax and semantics :).

Or, there might be

   ~~   for "approximately equivalent", and
   !~   for "approximately not equivalent".


--
Andrei Polushin

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Sat, 29 Apr 2006 20:33:51 GMT
Raw View
sjhoweATdialDOTpipexDOTcom@eu.uu.net ("Stephen Howe") wrote (abridged):
> Right. The problem I have with it is that transivitity may make break
> down.

That's a flaw in Andrei Polushin's suggestion, and it's why we shouldn't
reuse operator==(). Using operator~=() makes it clear that the usual
equality semantics may not hold.

-- Dave Harris, Nottingham, UK.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: reply-to@valid.address (Steve Rencontre)
Date: Fri, 21 Apr 2006 15:32:14 GMT
Raw View
I've wanted to be able to define an "approximately equal" operator on a
number of occasions, for things like case-insensitive string
comparisons, or floating-point values where limited precision makes
exact comparisons very flaky - ie, (1.0 / 3.0) * 3.0 != 1.0, etc.

To me, the perfect answer would be extending the language slightly to
make ~= an operator. I can't think of any legitimate code which would
include such a sequence, so I don't think it would break anything, and
the compiler effort to support it is trivial.

Obviously in some cases I can recycle something like ^= which doesn't
really have an existing meaning for strings or FP, but it would be nice
to have an operator that doesn't clash with anything else.

Anyone with me on this?

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "SuperKoko" <tabkannaz@yahoo.fr>
Date: Fri, 21 Apr 2006 11:37:55 CST
Raw View
Steve Rencontre wrote:
> I've wanted to be able to define an "approximately equal" operator on a
> number of occasions, for things like case-insensitive string
> comparisons, or floating-point values where limited precision makes
> exact comparisons very flaky - ie, (1.0 / 3.0) * 3.0 != 1.0, etc.
>
> To me, the perfect answer would be extending the language slightly to
> make ~= an operator. I can't think of any legitimate code which would
> include such a sequence, so I don't think it would break anything, and
> the compiler effort to support it is trivial.
I agree that backward compatibility does not matter
I can think of a ISO compliant, but stupid code, that would be broken:
A a; // assume that there is an overloaded "int& operator+(const A&, B
(B::*)())".
B b; // assume that there is an overloaded B::operator~

a + &B::operator~= 42;

>
> Obviously in some cases I can recycle something like ^= which doesn't
> really have an existing meaning for strings or FP, but it would be nice
> to have an operator that doesn't clash with anything else.
>
I agree that overloading ^= is really a bad idea.
But providing a good old member function seems simple and correct.
This type of comparison is not enough frequent to require a special
syntax.
Except perhaps with floating point numbers... But in that case, the ~=
would not be a correct solution, because the maximum variation
tolerance of the comparison depends on the number of calculations done,
and thus, I claim that the programmer must explicitly give this
"epsilon" value.
Thus, it would need a ternary operator. ;)
A simple function would be better.

And, even if there was an "ideal, universal" epsilon value, the
language should use this "epsilon" in the implementation of
operator==(double, double)

So, IMHO, the proposal is not good for floating point values.
For character strings, it makes more sense, but here too, I deem that
it is more confusing than a simple member function.
Because "approximatively" is not always intuitive, especially, because
you must define exactly what is "exactly approximatively equal".
A member function case_insensitive_compare, says well what it does (and
there may be optional parameters for the locale).

Operators have (ideally) always the same semantic, so it is easier to
use (or read code written with) a library that uses operator
overloading, because operators are self-documented.
But if there were a ~= operator, a code reader would need to look at
the parameters (to know the type on which this is defined) read the
doc, and then he will know exactly what it does...

So, except if you provide a clear description of the general semantics
of "approximatively equal", I can't see any benefit of that proposal.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: eric_backus@alum.mit.edu ("Eric Backus")
Date: Fri, 21 Apr 2006 18:04:45 GMT
Raw View
"Steve Rencontre" <reply-to@valid.address> wrote in message
news:t4ydnT3qYKO-SNXZRVny2g@pipex.net...
> I've wanted to be able to define an "approximately equal" operator on a
> number of occasions, for things like case-insensitive string
> comparisons, or floating-point values where limited precision makes
> exact comparisons very flaky - ie, (1.0 / 3.0) * 3.0 != 1.0, etc.
>
> To me, the perfect answer would be extending the language slightly to
> make ~= an operator. I can't think of any legitimate code which would
> include such a sequence, so I don't think it would break anything, and
> the compiler effort to support it is trivial.

I remember once thinking that ~= should be similar to +=, in that it applies
the ~ operator to the lhs, and then assigns back to the lhs.  So you'd have:

a = 0x3;
a += 2;    /* Now a equals 0x5 */
a ~= ;    /* Now a is the one's complement of 0x5 */

OK, I didn't seriously think this was a good idea...


> Obviously in some cases I can recycle something like ^= which doesn't
> really have an existing meaning for strings or FP, but it would be nice
> to have an operator that doesn't clash with anything else.
>
> Anyone with me on this?

I'm with you that recycling ^= for floating point comparison seems like a
bad idea.

For floating point, ~= might be nice, but the details of how to properly
compare floating-point values can get complicated.  Sometimes you'd want to
be able to specify an epsilon value, and ~= wouldn't work for that.

--
Eric Backus
R&D Design Engineer
Agilent Technologies, Inc.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Alan McKenney" <alan_mckenney1@yahoo.com>
Date: Fri, 21 Apr 2006 15:02:27 CST
Raw View
Steve Rencontre wrote:
> I've wanted to be able to define an "approximately equal" operator on a
> number of occasions, for things like case-insensitive string
> comparisons, or floating-point values where limited precision makes
> exact comparisons very flaky - ie, (1.0 / 3.0) * 3.0 != 1.0, etc.
>
> To me, the perfect answer would be extending the language slightly to
> make ~= an operator. ....

This operator is a bad idea, regardless of what character/character
sequence
you use.

The problem is that you can't come up with a generally useful
definition
of what an "approximately equal" operator is supposed to return, given
two floating point numbers.  Depending on how you came up with the
numbers,
you may have   1.0  not being approximately equal to 0.999999, or you
may
have 1.0 being approximately equal to 0.0.

You might be able to define an operator such that

    ( 1.0 / 3.0 )*3.0 ~= 1.0

but what about

      ( 3.14159*3.14159 + 0.07 ) / 3.14159 - 3.14159 ~= 0.07 / 3.14159

Now make these numbers variables, whose value is known only at run
time.

You may ask, where did this formula come from?
That's a good question, but one a compiler can't ask.
The compiler -- and the computer -- have to figure it out at
run time, with no knowledge of the problem requirements
or understanding of the algorithm.

In real life, of course the expressions end up being a lot more
complicated.

-- Alan McKenney

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Zara <yozara@terra.es>
Date: Fri, 21 Apr 2006 15:15:11 CST
Raw View
On Fri, 21 Apr 2006 15:32:14 GMT, reply-to@valid.address (Steve
Rencontre) wrote:

>I've wanted to be able to define an "approximately equal" operator on a
>number of occasions, for things like case-insensitive string
>comparisons, or floating-point values where limited precision makes
>exact comparisons very flaky - ie, (1.0 / 3.0) * 3.0 != 1.0, etc.
>
>To me, the perfect answer would be extending the language slightly to
>make ~= an operator. I can't think of any legitimate code which would
>include such a sequence, so I don't think it would break anything, and
>the compiler effort to support it is trivial.
>
>Obviously in some cases I can recycle something like ^= which doesn't
>really have an existing meaning for strings or FP, but it would be nice
>to have an operator that doesn't clash with anything else.
>
>Anyone with me on this?
>

I think this is not the right way to do it.
 I think you should cretae some object or functor that should do the
comparison, because the defintion of "approximately equal" should be
trimmed for every particular use.

It might be an absolute value, a percentage, the greater of both, some
kind of analysis based on ortoghraphic and/or semantic similarities
between words... ahtever happens to coros  the mind of a designer or
marketing engineer.

Such a great bunch of work should not be standarised before passing a
lot of analysis and testing by lots of people. It might be a good
addition to boost libraries (if t is not already there!).

regards,

Zara

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: reply-to@valid.address (Steve Rencontre)
Date: Fri, 21 Apr 2006 21:02:52 GMT
Raw View
I'm replying to this specific message, but it's a point that has been
made by everyone so far, and shows that I wasn't clear enough in my
original statement.

Zara wrote:
> On Fri, 21 Apr 2006 15:32:14 GMT, reply-to@valid.address (Steve
> Rencontre) wrote:
>
>> I've wanted to be able to define an "approximately equal" operator on a
>> number of occasions, for things like case-insensitive string
>> comparisons, or floating-point values where limited precision makes
>> exact comparisons very flaky - ie, (1.0 / 3.0) * 3.0 != 1.0, etc.
[ ...]
> I think this is not the right way to do it.
>  I think you should cretae some object or functor that should do the
> comparison, because the defintion of "approximately equal" should be
> trimmed for every particular use.

I'm not asking for a /definition/ of "approximately equal". My idea was
for an operator which is /only/ user-defined, with no default if the
programmer does not explicitly create it.

IOW, the expression "a ~= b" means "a is /deemed/ equal to b in the
current context that I, the programmer, have established."

What I deem equal is not what you might deem equal, or what I will deem
equal on a different occasion.

It is perfectly valid to say that floating-point epsilon is not a fixed
quantity, but I never imagined it was. I had in mind that the method of
determining "close enough" equality would be defined explicitly for the
calculation at hand. Where several different contexts need different
epsilons or comparison procedures, that could be done with namespaces or
with helper functions. For example,

 CApproximatelyEqual<double>::SetEpsilon (1e-9);

 if (a ~= b)
  do_something();

 CApproximatelyEqual<double>::SetEpsilon (1e-12);

 if (x ~= y)
  do_something_else();

I think it is legitimate to dissociate the intrinsic notion of "equal
for present purposes" from the definition of precisely what that
equality constitutes, which is what the notation I suggested offers.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Andrei Polushin" <polushin@gmail.com>
Date: Sat, 22 Apr 2006 00:12:18 CST
Raw View
Steve Rencontre wrote:
> Zara wrote:
>> Steve Rencontre wrote:
>>> I've wanted to be able to define an "approximately equal" operator
>>> on a number of occasions, for things like case-insensitive string
>>> comparisons, or floating-point values where limited precision makes
>>> exact comparisons very flaky - ie, (1.0 / 3.0) * 3.0 != 1.0, etc.
>> I think this is not the right way to do it.
>> I think you should cretae some object or functor that should do the
>> comparison, because the defintion of "approximately equal" should be
>> trimmed for every particular use.
>
> I'm not asking for a /definition/ of "approximately equal". My idea was
> for an operator which is /only/ user-defined, with no default if the
> programmer does not explicitly create it.
>
> IOW, the expression "a ~= b" means "a is /deemed/ equal to b in the
> current context that I, the programmer, have established."
>
> What I deem equal is not what you might deem equal, or what I will deem
> equal on a different occasion.
>
> It is perfectly valid to say that floating-point epsilon is not a fixed
> quantity, but I never imagined it was. I had in mind that the method of
> determining "close enough" equality would be defined explicitly for the
> calculation at hand. Where several different contexts need different
> epsilons or comparison procedures, that could be done with namespaces or
> with helper functions. For example,
>
>  CApproximatelyEqual<double>::SetEpsilon (1e-9);
>
>  if (a ~= b)
>   do_something();
>
>  CApproximatelyEqual<double>::SetEpsilon (1e-12);
>
>  if (x ~= y)
>   do_something_else();

Global helpers are unacceptable in general.

But you can define an `approximately comparable' object:

  template<class doubleT> class inexact_t {
    doubleT value;
    doubleT epsylon;
  public:
    inexact_t(doubleT value, doubleT epsylon)
      : value(value), epsylon(epsylon) {}

    bool operator==(doubleT v) {
      return value - epsylon <= v && v <= value + epsylon;
    }
    bool operator!=(doubleT v) {
      return !operator==(v);
    }
  };

  template<class doubleT> inexact_t<doubleT> inexact(
    doubleT value,
    doubleT epsylon = std::numeric_limits<doubleT>::epsylon())
  {
    return inexact_t<doubleT>(value, epsylon);
  }

  void test()
  {
    if (inexact(2.5, 0.5) == 2.3) {
      cout << "equal" << endl;
    }
    if (inexact(2.5, 0.1) != 2.3) {
      cout << "not equal" << endl;
    }
  }

The same could be defined for

* case-insensitive string comparison, which can use std::collate for
  parameter, defaulting to use_facet<collate<char> >(locale());

* regular expression matching object, parameterized by regex with its
  options, and holding the match_results for later use.

By the way, operators == and != can be used directly in various
algorithms, such as std::find().

Would that be enough?

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Alberto Ganesh Barbati <AlbertoBarbati@libero.it>
Date: 23 Apr 2006 04:50:01 GMT
Raw View
Zara ha scritto:
> Such a great bunch of work should not be standarised before passing a
> lot of analysis and testing by lots of people. It might be a good
> addition to boost libraries (if t is not already there!).

That's a very good idea. I'm going to post on the boost newsgroup about it.

Ganesh

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: reply-to@valid.address (Steve Rencontre)
Date: Sun, 23 Apr 2006 17:39:50 GMT
Raw View
Andrei Polushin wrote:

[...]
>>  CApproximatelyEqual<double>::SetEpsilon (1e-12);
>>
>>  if (x ~= y)
>>   do_something_else();
>
> Global helpers are unacceptable in general.
>
> But you can define an `approximately comparable' object:
>
[...]
>
>     if (inexact(2.5, 0.5) == 2.3) {
>       cout << "equal" << endl;
>     }
>     if (inexact(2.5, 0.1) != 2.3) {
>       cout << "not equal" << endl;
>     }
>   }
>

I don't see a lot of benefit over a simple comparison function, or
possibly a comparator function object, eg:

 template <typename T>
 class approximately_equal
 {
 public:
  approximately_equal (T t) : epsilon (t) {}
  bool operator() (T t1, T t2)
   { return abs (t1 - t2) < epsilon: }
 private:
  T epsilon;
 };

 if (approximately_equal (0.5) (2.3, 2.5))
  ...

There are plenty of ways to express the basic functionality, but the
whole point of infix operator notation is that

 a = b + c;

is generally held to be clearer than alternatives like

 a.assign (plus (b, c)):

I believe that my operator ~= suggestion fits that pattern of increased
clarity.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Andrei Polushin" <polushin@gmail.com>
Date: 23 Apr 2006 19:20:08 GMT
Raw View
Steve Rencontre wrote:
> Andrei Polushin wrote:
>> Steve Rencontre wrote:
>> [...]
>>>  CApproximatelyEqual<double>::SetEpsilon (1e-12);
>>>
>>>  if (x ~= y)
>>>   do_something_else();
>>
>> Global helpers are unacceptable in general.
>> But you can define an `approximately comparable' object:
>> [...]
>>     if (inexact(2.5, 0.5) == 2.3) {
>>       cout << "equal" << endl;
>>     }
>>     if (inexact(2.5, 0.1) != 2.3) {
>>       cout << "not equal" << endl;
>>     }
>>   }
>
> I don't see a lot of benefit over a simple comparison function, or
> possibly a comparator function object, eg:
> [...]
>  if (approximately_equal (0.5) (2.3, 2.5))
>   ...
>
> There are plenty of ways to express the basic functionality, but the
> whole point of infix operator notation is that
>
>  a = b + c;
>
> is generally held to be clearer than alternatives like
>
>  a.assign (plus (b, c)):
>
> I believe that my operator ~= suggestion fits that pattern of increased
> clarity.

Well, look at code.

Mine:

  inexact_t<double> a(2.5, 0.5);

  if (a == 2.3)
    do_something();

Yours:

  CApproximatelyEqual<double> a(2.5);
  CApproximatelyEqual<double>::SetEpsilon(0.5); // global?

  if (a ~= 2.3)
    do_something();

Is the clarity increased?


--
Andrei Polushin

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]