 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Sebastian Moleski Guest
|
Posted: Sat Aug 09, 2003 11:37 pm Post subject: Re: Extending the functionality of built-in types |
|
|
"Laszlo G." <laszloga (AT) hotmail (DOT) com> wrote
| Quote: | Hello,
I'd like to know if there is a general approach to take when extending
the functionality of built-in types. For example, comparing two
floating-point numbers is unreliable using the normal <, !=, etc.
operators. However, I'm thinking that using operator overloading, one
can change the meaning of these comparisons, to provide a better
implementation of floating-point comparisons. However, I only want to
overload a selected number of operators, such as <, <=, >, >=, !=, and
==, since the rest are "fine" as they are (as far as comparisons
go)... Is there a way to create a type MyDouble that behaves exactly
like double, except for these 6 operations?
|
No, not like that. What you can do though is create a class MyDouble that
implements all the operators double does and just reimplement the relational
operators as you see fit. That will get you a very close approximation to the
double type.
On another note, I'm not sure how you can generically write relational operators
for floating types (assuming you want to use the epsilong method): the value of
epsilon is dependant on the values of the operands in the comparison expression.
What did you have in mind in terms of how to implement that?
sm
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Heinz Ozwirk Guest
|
Posted: Sun Aug 10, 2003 9:43 am Post subject: Re: Extending the functionality of built-in types |
|
|
"Laszlo G." <laszloga (AT) hotmail (DOT) com> schrieb im Newsbeitrag news:475e2890.0308081745.27727983 (AT) posting (DOT) google.com...
: Hello,
:
: I'd like to know if there is a general approach to take when extending
: the functionality of built-in types. For example, comparing two
: floating-point numbers is unreliable using the normal <, !=, etc.
: operators. However, I'm thinking that using operator overloading, one
: can change the meaning of these comparisons, to provide a better
: implementation of floating-point comparisons. However, I only want to
: overload a selected number of operators, such as <, <=, >, >=, !=, and
: ==, since the rest are "fine" as they are (as far as comparisons
: go)... Is there a way to create a type MyDouble that behaves exactly
: like double, except for these 6 operations?
You could define a simple class MyDouble like this:
class MyDouble
{
double value;
public:
MyDouble(double v = 0.0): value(v) {}
operator double() const { return value; }
};
This class behaves like double. Now you can modify the operators you are
interested in, for example operator!= (assuming you have already modified operator==)
bool operator!=(MyDouble lhs, MyDouble rhs)
{
return !(lhs == rhs);
}
bool operator!=(MyDouble lhs, double rhs)
{
return lhs != MyDouble(rhs);
}
bool operator!=(double lhs, MyDouble rhs)
{
return MyDouble(lhs) != rhs;
}
For each operator you'll have to define versions for MyDouble op
MyDouble, MyDouble op double and double op MyDouble, and if you want to
be able to write something like
MyDouble x;
if (x != 0) ...
you'll also have to provide operators (perhaps a constructor may be
enough?) accepting one int argument.
You can save a lot of work, when you are willing to invoke the conversion
from MyDouble to double explicitly, write something like
double d = myDouble.Value();
instead of
double d = myDouble;
The you don't need the MyDouble op double and double op MyDouble
versions, but you'll have no implicit conversion to double, but you will
avoid a lot of trouble without the implicit conversion.
Regards
Heinz
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Laszlo G. Guest
|
Posted: Mon Aug 11, 2003 12:31 am Post subject: Re: Extending the functionality of built-in types |
|
|
"Sebastian Moleski" <sebmol (AT) yahoo (DOT) com> wrote
| Quote: | "Laszlo G." <laszloga (AT) hotmail (DOT) com> wrote in message
news:475e2890.0308081745.27727983 (AT) posting (DOT) google.com...
Hello,
I'd like to know if there is a general approach to take when extending
the functionality of built-in types. For example, comparing two
floating-point numbers is unreliable using the normal <, !=, etc.
operators. However, I'm thinking that using operator overloading, one
can change the meaning of these comparisons, to provide a better
implementation of floating-point comparisons. However, I only want to
overload a selected number of operators, such as <, <=, >, >=, !=, and
==, since the rest are "fine" as they are (as far as comparisons
go)... Is there a way to create a type MyDouble that behaves exactly
like double, except for these 6 operations?
No, not like that. What you can do though is create a class MyDouble that
implements all the operators double does and just reimplement the relational
operators as you see fit. That will get you a very close approximation to the
double type.
|
I actually wanted to avoid overloading other operators...
| Quote: | On another note, I'm not sure how you can generically write relational operators
for floating types (assuming you want to use the epsilong method): the value of
epsilon is dependant on the values of the operands in the comparison expression.
What did you have in mind in terms of how to implement that?
sm
|
Actually, my reference to generality was meant in regards to making
these sort of changes to ANY built-in type...
However, since I know what sort of errors can creep into my
calculations and the precision that I'd like to have in the values I'm
generating, I believe that I can fine-tune the epsilon...
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Laszlo G. Guest
|
Posted: Mon Aug 11, 2003 12:31 am Post subject: Re: Extending the functionality of built-in types |
|
|
Pete Becker <petebecker (AT) acm (DOT) org> wrote
| Quote: | "Laszlo G." wrote:
Hello,
I'd like to know if there is a general approach to take when extending
the functionality of built-in types. For example, comparing two
floating-point numbers is unreliable using the normal <, !=, etc.
operators.
This is a common misunderstanding. The relational operators work just
fine. Most programmers don't know enough about the characteristics of
floating point math to use it correctly, though.
The issue in both cases is the same. Integral types aren't real numbers.
We all learn this pretty early on, and learn how to compensate. Floating
point types also aren't real numbers. The differences are much more
|
I realize that they work as they should. However, I will modify them,
one way or another, to work as I want them to... Just compensating...
;)
Laszlo.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Laszlo G. Guest
|
Posted: Mon Aug 11, 2003 12:32 am Post subject: Re: Extending the functionality of built-in types |
|
|
"Heinz Ozwirk" <wansor42 (AT) gmx (DOT) de> wrote
| Quote: | "Laszlo G." <laszloga (AT) hotmail (DOT) com> schrieb im Newsbeitrag news:475e2890.0308081745.27727983 (AT) posting (DOT) google.com...
: Hello,
:
: I'd like to know if there is a general approach to take when extending
: the functionality of built-in types. For example, comparing two
: floating-point numbers is unreliable using the normal <, !=, etc.
: operators. However, I'm thinking that using operator overloading, one
: can change the meaning of these comparisons, to provide a better
: implementation of floating-point comparisons. However, I only want to
: overload a selected number of operators, such as <, <=, >, >=, !=, and
: ==, since the rest are "fine" as they are (as far as comparisons
: go)... Is there a way to create a type MyDouble that behaves exactly
: like double, except for these 6 operations?
You could define a simple class MyDouble like this:
class MyDouble
{
double value;
public:
MyDouble(double v = 0.0): value(v) {}
operator double() const { return value; }
};
For each operator you'll have to define versions for MyDouble op
MyDouble, MyDouble op double and double op MyDouble, and if you want to
|
This is what I started doing, except that I made one member function
for each operator I was interested in overloading, and then I ran into
compiler errors due to ambiguity...
| Quote: | be able to write something like
MyDouble x;
if (x != 0) ...
you'll also have to provide operators (perhaps a constructor may be
enough?) accepting one int argument.
|
It worked without providing any operators or constructor for int,
perhaps due to the implicit conversion the compiler does from int to
double...
| Quote: | You can save a lot of work, when you are willing to invoke the conversion
from MyDouble to double explicitly, write something like
double d = myDouble.Value();
instead of
double d = myDouble;
The you don't need the MyDouble op double and double op MyDouble
versions, but you'll have no implicit conversion to double, but you will
avoid a lot of trouble without the implicit conversion.
Regards
Heinz
|
I'll think I'll opt for the explicit method, because I'd like to avoid
relying on the implicit conversions...
Or I'll just might do
bool IsNotEqual(double lhs, double rhs);
;)
Thanks,
Laszlo.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Pete Becker Guest
|
Posted: Mon Aug 11, 2003 12:34 am Post subject: Re: Extending the functionality of built-in types |
|
|
Francis Glassborow wrote:
| Quote: |
In message <3F35AAEF.8A112626 (AT) acm (DOT) org>, Pete Becker
writes
This is a common misunderstanding. The relational operators work just
fine. Most programmers don't know enough about the characteristics of
floating point math to use it correctly, though.
int a = 4 / 3;
int b = 4 * (1 / 3);
We all know that a == b is false, and we don't blame the equality
operator.
Note that a == b is required to be false by the rules of the language.
There is absolutely no choice.
|
Irrelevant.
| Quote: |
double c = 4.0 / 3.0;
double d = 4.0 * (1.0 / 3.0);
It is also true that c == d is false. Don't blame the equality operator.
But c==d is not required to be false even if it is on many platforms.
There is nothing in the specification of floating point types that
requires c==d to be either true or false. That is what makes so very
difficult to learn. It isn't just the calculations but the platform on
which they are executed that determines the truth value.
|
Yup, that's one of the usual excuses. "It's too hard, so we shouldn't
even try."
| Quote: |
The issue in both cases is the same. Integral types aren't real numbers.
We all learn this pretty early on, and learn how to compensate. Floating
point types also aren't real numbers. The differences are much more
subtle, and they're mostly not taught.
Even when they are taught they are often not learnt. This is because
there is no convenient real world model which can help the student
understand and remember.
|
It's impossible, so let's give up before we start.
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Francis Glassborow Guest
|
Posted: Mon Aug 11, 2003 4:47 pm Post subject: Re: Extending the functionality of built-in types |
|
|
In message <3F36DA9C.BB9C48F7 (AT) acm (DOT) org>, Pete Becker <petebecker (AT) acm (DOT) org>
writes
| Quote: | But c==d is not required to be false even if it is on many platforms.
There is nothing in the specification of floating point types that
requires c==d to be either true or false. That is what makes so very
difficult to learn. It isn't just the calculations but the platform on
which they are executed that determines the truth value.
Yup, that's one of the usual excuses. "It's too hard, so we shouldn't
even try."
|
I do not understand your response. I cannot see how you get from what I
said to what you say. Thinks that always work the same way are
relatively easy to learn. Things that apparently behave whimsically are
much harder because we have to delve deeper. Being harder does not mean
we should not try, but we should recognise that it is harder and so try
harder.
Fore example you made a statement about comparing two floating point
numbers that is not universally true. Such statements actually make
understanding harder for those who are learning because they do not
agree with experience. Some will ask further, most will just take it as
evidence that the respondent either does not understand the question or
does not know the answer.
| Quote: |
The issue in both cases is the same. Integral types aren't real numbers.
We all learn this pretty early on, and learn how to compensate. Floating
point types also aren't real numbers. The differences are much more
subtle, and they're mostly not taught.
Even when they are taught they are often not learnt. This is because
there is no convenient real world model which can help the student
understand and remember.
It's impossible, so let's give up before we start.
|
Your words not mine. The burden is on the teacher to find clear examples
that support their statements and be very careful if their statements
are falsifiable.
--
ACCU Spring Conference 2003 April 2-5
The Conference you should not have missed
ACCU Spring Conference 2004 Late April
Francis Glassborow ACCU
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
llewelly Guest
|
Posted: Tue Aug 12, 2003 1:08 am Post subject: Re: Extending the functionality of built-in types |
|
|
[email]laszloga (AT) hotmail (DOT) com[/email] (Laszlo G.) writes:
| Quote: | "Heinz Ozwirk" <wansor42 (AT) gmx (DOT) de> wrote
"Laszlo G." <laszloga (AT) hotmail (DOT) com> schrieb im Newsbeitrag news:475e2890.0308081745.27727983 (AT) posting (DOT) google.com...
: Hello,
:
: I'd like to know if there is a general approach to take when extending
: the functionality of built-in types. For example, comparing two
: floating-point numbers is unreliable using the normal <, !=, etc.
: operators. However, I'm thinking that using operator overloading, one
: can change the meaning of these comparisons, to provide a better
: implementation of floating-point comparisons. However, I only want to
: overload a selected number of operators, such as <, <=, >, >=, !=, and
: ==, since the rest are "fine" as they are (as far as comparisons
: go)... Is there a way to create a type MyDouble that behaves exactly
: like double, except for these 6 operations?
You could define a simple class MyDouble like this:
class MyDouble
{
double value;
public:
MyDouble(double v = 0.0): value(v) {}
operator double() const { return value; }
};
For each operator you'll have to define versions for MyDouble op
MyDouble, MyDouble op double and double op MyDouble, and if you want to
This is what I started doing, except that I made one member function
for each operator I was interested in overloading, and then I ran into
compiler errors due to ambiguity...
[snip] |
Relational operators should never be member operators. member
operators treat their operands asymetricly with respect const, and
also w.r.t. implicit conversions.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Pete Becker Guest
|
Posted: Tue Aug 12, 2003 6:19 pm Post subject: Re: Extending the functionality of built-in types |
|
|
Francis Glassborow wrote:
| Quote: |
Even when they are taught they are often not learnt. This is because
there is no convenient real world model which can help the student
understand and remember.
It's impossible, so let's give up before we start.
Your words not mine. The burden is on the teacher to find clear examples
that support their statements and be very careful if their statements
are falsifiable.
|
Your words are: "there is no convenient real world model which can help
the student understand and remember." Seems to me that that should be a
challenge to educators, as it was to Knuth:
[E]very well-rounded programmer ought to have a
knowledge of what goes on during the elementary
steps of floating point arithmetic. This subject
is not at all as trivial as most people think, and
it involves a surprising amount of interesting
information.
-- The Art of Computer Programming, vol. 2,
Seminumerical Algorithms, 3rd ed.,p. 214.
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Bruce Wheeler Guest
|
Posted: Wed Aug 13, 2003 4:09 pm Post subject: Re: Extending the functionality of built-in types |
|
|
Pete Becker <petebecker (AT) acm (DOT) org> wrote
| Quote: | "Laszlo G." wrote:
Hello,
I'd like to know if there is a general approach to take when extending
the functionality of built-in types. For example, comparing two
floating-point numbers is unreliable using the normal <, !=, etc.
operators.
This is a common misunderstanding. The relational operators work just
fine. Most programmers don't know enough about the characteristics of
floating point math to use it correctly, though.
int a = 4 / 3;
int b = 4 * (1 / 3);
We all know that a == b is false, and we don't blame the equality
operator.
double c = 4.0 / 3.0;
double d = 4.0 * (1.0 / 3.0);
It is also true that c == d is false. Don't blame the equality operator.
The issue in both cases is the same. Integral types aren't real numbers.
We all learn this pretty early on, and learn how to compensate. Floating
point types also aren't real numbers. The differences are much more
subtle, and they're mostly not taught.
|
Actually, that's a bad example. In a well-behaved binary
floating-point implementation, I would expect c == d to be true, since
4.0 == 2**2, ie multiplying by 4.0 will have no effect on the
mantissa, and will only affect the exponent. This will be an exact
integer operation in this case, since no overflow/underflow of
exponent occurs.
mantissa(d) == mantissa(c), and exponent(d) == 2 + exponent(c)-2.
Of course, C++ and C do not guarantee binary floating point, or even
that 4.0/3.0 provides a useful result.
Your point is well taken that floating-point operations and
comparisons are very tricky and subtle. The general case of your
example may depend on the rounding mode of the floating-point
implementation.
For reference, VC++ 6.0 evaluates c == d to be true, as I would
expect. Are you aware of any binary floating-point implementations
where this is not the case?
Regards,
Bruce Wheeler
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Pete Becker Guest
|
Posted: Thu Aug 14, 2003 9:11 am Post subject: Re: Extending the functionality of built-in types |
|
|
Bruce Wheeler wrote:
| Quote: |
Pete Becker <petebecker (AT) acm (DOT) org> wrote in message
news:<3F35AAEF.8A112626 (AT) acm (DOT) org>...
"Laszlo G." wrote:
Hello,
I'd like to know if there is a general approach to take when extending
the functionality of built-in types. For example, comparing two
floating-point numbers is unreliable using the normal <, !=, etc.
operators.
This is a common misunderstanding. The relational operators work just
fine. Most programmers don't know enough about the characteristics of
floating point math to use it correctly, though.
int a = 4 / 3;
int b = 4 * (1 / 3);
We all know that a == b is false, and we don't blame the equality
operator.
double c = 4.0 / 3.0;
double d = 4.0 * (1.0 / 3.0);
It is also true that c == d is false. Don't blame the equality operator.
The issue in both cases is the same. Integral types aren't real numbers.
We all learn this pretty early on, and learn how to compensate. Floating
point types also aren't real numbers. The differences are much more
subtle, and they're mostly not taught.
Actually, that's a bad example. In a well-behaved binary
floating-point implementation, I would expect c == d to be true, since
4.0 == 2**2, ie multiplying by 4.0 will have no effect on the
mantissa, and will only affect the exponent. This will be an exact
integer operation in this case, since no overflow/underflow of
exponent occurs.
mantissa(d) == mantissa(c), and exponent(d) == 2 + exponent(c)-2.
|
Could be.
| Quote: |
Of course, C++ and C do not guarantee binary floating point, or even
that 4.0/3.0 provides a useful result.
Your point is well taken that floating-point operations and
comparisons are very tricky and subtle.
|
Actually, my point is that they're not. At least, not as much as most
programmers seem to think.
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Balog Pal Guest
|
Posted: Sun Sep 07, 2003 10:56 am Post subject: Re: Extending the functionality of built-in types |
|
|
"Francis Glassborow" <francis.glassborow (AT) ntlworld (DOT) com> wrote
| Quote: | We have a similar problem with understanding the potential problems when
multiplying two signed ints (that the result may be undefined)
|
What problems you mean here?
Paul
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|