Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

numeric_limits [lib.limits]

10 views
Skip to first unread message

Kaspar Fischer

unread,
Nov 29, 2000, 3:00:00 AM11/29/00
to
Hi everybody,

I have a simple question regarding section 18.2.1 [lib.limits] where the
traits-classes numeric_limits<T> are introduced:

4 "Non-fundamental standard types, such as complex<T>,
shall not have [numeric_limits-] specializations."

Could anybody explain to me why not? I am asking because I am writing a
template function on some number type T (float, double, 128bitInt, etc.)
and I'd like to use the numeric_limits traits-class to find the maximum
number which can represented by T. But if I am not allowed to give a
numeric_limits-specialization for my user-defined type T, I cannot find
the maximum using numeric_limits<T>::max().

I guess I am missunderstanding some important point here, so I would
really be glad to receive some help!

Thanks
Kaspar

--
Kaspar Fischer, Hochstrasse 73, CH-4053 Basel Tel. 061 331 40 35
mailto:kfis...@iiic.ethz.ch http://n.ethz.ch/student/fischerk

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]

James Kanze

unread,
Nov 30, 2000, 3:00:00 AM11/30/00
to
Kaspar Fischer wrote:

> I have a simple question regarding section 18.2.1 [lib.limits] where the
> traits-classes numeric_limits<T> are introduced:

> 4 "Non-fundamental standard types, such as complex<T>,
> shall not have [numeric_limits-] specializations."

> Could anybody explain to me why not?

Numeric limits is a funny class; some of its functions (like min) have
variable semantics (smallest possible value, smallest value > 0),
others only have meaning for certain types. Still, most, if not all,
of the functions and/or fields could have no meaning for non-scalars.

In C++, all of the fundamental standard types are scalars, and non of
the non-fundamental standard types are scalars. So the fundamental
standard types have numeric_limits, and the non-fundamental ones
don't.

This doesn't affect what you can do for non-standard types. In
practice, I would specialize it for any non-standard type that was a
scalar (like BigInteger, or Rational), although I suspect that for
cases like Rational, defining the semantics of some of the fields
would be a bit tricky.

> I am asking because I am writing a
> template function on some number type T (float, double, 128bitInt, etc.)
> and I'd like to use the numeric_limits traits-class to find the maximum
> number which can represented by T.

This is exactly what it was designed for.

> But if I am not allowed to give a
> numeric_limits-specialization for my user-defined type T, I cannot find
> the maximum using numeric_limits<T>::max().

*YOU* are allowed to provide a specialization for a user defined
type. The implementation is not allowed to provide a specialization
for a non-fundamental standard type.

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

Jani Kajala

unread,
Nov 30, 2000, 3:00:00 AM11/30/00
to
You can't compare complex numbers so for example min() doesn't make much
sense. Your 128bitInt is not standard type so feel free to specialize
numeric_limits for it.


Regards,
Jani Kajala

"Kaspar Fischer" <kfis...@iiic.ethz.ch> wrote in message
news:3A256D98...@iiic.ethz.ch...
> Hi everybody,


>
> I have a simple question regarding section 18.2.1 [lib.limits] where the
> traits-classes numeric_limits<T> are introduced:
>
> 4 "Non-fundamental standard types, such as complex<T>,
> shall not have [numeric_limits-] specializations."
>

> Could anybody explain to me why not? I am asking because I am writing a


> template function on some number type T (float, double, 128bitInt, etc.)
> and I'd like to use the numeric_limits traits-class to find the maximum

> number which can represented by T. But if I am not allowed to give a


> numeric_limits-specialization for my user-defined type T, I cannot find
> the maximum using numeric_limits<T>::max().
>

> I guess I am missunderstanding some important point here, so I would
> really be glad to receive some help!
>
> Thanks
> Kaspar
>
> --
> Kaspar Fischer, Hochstrasse 73, CH-4053 Basel Tel. 061 331 40 35
> mailto:kfis...@iiic.ethz.ch http://n.ethz.ch/student/fischerk

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Fernando Cacciola

unread,
Nov 30, 2000, 3:00:00 AM11/30/00
to

Kaspar Fischer <kfis...@iiic.ethz.ch> escribió en el mensaje de noticias

3A256D98...@iiic.ethz.ch...
> Hi everybody,
>
> I have a simple question regarding section 18.2.1 [lib.limits] where the
> traits-classes numeric_limits<T> are introduced:
>
> 4 "Non-fundamental standard types, such as complex<T>,
> shall not have [numeric_limits-] specializations."
>
> Could anybody explain to me why not? I am asking because I am writing a
> template function on some number type T (float, double, 128bitInt, etc.)
> and I'd like to use the numeric_limits traits-class to find the maximum
> number which can represented by T. But if I am not allowed to give a
> numeric_limits-specialization for my user-defined type T, I cannot find
> the maximum using numeric_limits<T>::max().
>
> I guess I am missunderstanding some important point here, so I would
> really be glad to receive some help!
>
> Thanks
> Kaspar
>
Others answer you on this, but as a side note:

I've been working with user defined number types for quite a while and if
you are going to write generic numerical algorithms I might give you some
advise:

1) Write a template function that can be used to convert between number
types, such as:

template<class T,class S> T cvt_n ( S const& n ) { return
static_cast<T>(n) ; }

then you can specialise this as needed for the particular number type. This
gives you a common idiom for number-to-number conversions.

(NOTE: it is possible to write an implementation that can be completely
optimized)

2) Setup a namespace and include template wrappers for the usual math
functions, such as:

namespace gmath {
template<class T>
inline T sqrt ( T const& n ) { return
t_n<T>( std::sqrt( cvt_n<double>(n) ) ) ; }
}

This gives you a common ground for usual math functions.
If your number type provides any of these functions you can specialize it.

3) Make sure all your comparisons have operands of the same type, that is:
instead of if ( var != 0.0 ) write if ( var != T(0) )

4) Of course, specialize numeric_limits<> for any user defined number type.

5) You might want to create a separate numeric_bounds<> traits as a
replacement for min/max that provides a consistent semantic, such as:

template<class T>
struct numeric_bounds
{
// smallest(): positive value closer to 0.
static N smallest() ...

// biggest(): positive value closer to positive infinity.
static N biggest () ...

// lowest(): value closer to negative infinity.
static N lowest() ...

// highest(): value closer to positive infinite.
static N highest() ...
} ;

I intentionally skipped all the implementation details no keep this article
clear. If you need it just let me know.

Regards,


--
Fernando Cacciola
Sierra s.r.l.
fcac...@fibertel.com.ar
www.gosierra.com

Ken Bloom

unread,
Dec 1, 2000, 3:00:00 AM12/1/00
to
"James Kanze" <James...@dresdner-bank.com> wrote in message
news:3A262137...@dresdner-bank.com...

> Kaspar Fischer wrote:
>
> > I have a simple question regarding section 18.2.1 [lib.limits] where the
> > traits-classes numeric_limits<T> are introduced:
>
> > 4 "Non-fundamental standard types, such as complex<T>,
> > shall not have [numeric_limits-] specializations."
>
> > Could anybody explain to me why not?
>
> Numeric limits is a funny class; some of its functions (like min) have
> variable semantics (smallest possible value, smallest value > 0),
> others only have meaning for certain types. Still, most, if not all,
> of the functions and/or fields could have no meaning for non-scalars.
>
> In C++, all of the fundamental standard types are scalars, and non of
> the non-fundamental standard types are scalars. So the fundamental
> standard types have numeric_limits, and the non-fundamental ones
> don't.
>
> This doesn't affect what you can do for non-standard types. In
> practice, I would specialize it for any non-standard type that was a
> scalar (like BigInteger, or Rational), although I suspect that for
> cases like Rational, defining the semantics of some of the fields
> would be a bit tricky.
>
> > I am asking because I am writing a
> > template function on some number type T (float, double, 128bitInt, etc.)
> > and I'd like to use the numeric_limits traits-class to find the maximum
> > number which can represented by T.
>
> This is exactly what it was designed for.
>
> > But if I am not allowed to give a
> > numeric_limits-specialization for my user-defined type T, I cannot find
> > the maximum using numeric_limits<T>::max().
>
> *YOU* are allowed to provide a specialization for a user defined
> type. The implementation is not allowed to provide a specialization
> for a non-fundamental standard type.

and note also that very few of the numeric limits fields are meaningful for
complex numbers because it has two components.

you can define numeric_limits<complex<T> > if you so choose.

--
Ken Bloom

-----BEGIN GEEK CODE BLOCK-----
Version: 3.12
GCS/M/AT/U d- s++:--- a--- C++ UL P++ L+ E----
W+++ N++ ?o ?K w++ !O M++>$ V- PS PE Y-- PGP- t+
5 X++ R--- tv-- b++ DI+ D-- G e- !h r--@ y?
------END GEEK CODE BLOCK------

jkau...@my-deja.com

unread,
Dec 1, 2000, 3:00:00 AM12/1/00
to
In article <9057fd$7t3$1...@nntp.teliafi.net>,

"Jani Kajala" <ja...@remedy.NOSPAMPLEASE.fi> wrote:
> You can't compare complex numbers so for example min() doesn't make
much
> sense.

You certainly can, compare their magnitudes.

In answer to the op, i think the standard is forbidding an
implementation from providing a specialisation of numeric_limits, not a
programmer.


Sent via Deja.com http://www.deja.com/
Before you buy.

James Kanze

unread,
Dec 4, 2000, 3:00:00 AM12/4/00
to
jkau...@my-deja.com wrote:
>
> In article <9057fd$7t3$1...@nntp.teliafi.net>,
> "Jani Kajala" <ja...@remedy.NOSPAMPLEASE.fi> wrote:
> > You can't compare complex numbers so for example min() doesn't
> > make much sense.

> You certainly can, compare their magnitudes.

Which doesn't give a complete ordering. And doesn't explain what
min() should return.

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

James Kanze

unread,
Dec 4, 2000, 3:00:00 AM12/4/00
to
Ken Bloom wrote:

> you can define numeric_limits<complex<T> > if you so choose.

No you can't. Not officially, at any rate. You can only define
specializations over your own types, not those defined in the
standard.

Gabriel Dos_Reis

unread,
Dec 4, 2000, 3:00:00 AM12/4/00
to
James Kanze <James...@dresdner-bank.com> writes:

| Ken Bloom wrote:
|
| > you can define numeric_limits<complex<T> > if you so choose.
|
| No you can't. Not officially, at any rate. You can only define
| specializations over your own types, not those defined in the
| standard.

This is an interesting point.

Formally it is permitted to specialize std::complex<> on a user-defined
(numerical) type, say fixed_point. But the result of such
specialization is again a user-defined type. So technically it is
permitted to define numeric_limits<complex<fixed_point> >.

--
Gabriel Dos Reis, dos...@cmla.ens-cachan.fr

James Kanze

unread,
Dec 5, 2000, 3:00:00 AM12/5/00
to
Gabriel Dos_Reis wrote:

> James Kanze <James...@dresdner-bank.com> writes:

> | Ken Bloom wrote:

> | > you can define numeric_limits<complex<T> > if you so choose.

> | No you can't. Not officially, at any rate. You can only define
> | specializations over your own types, not those defined in the
> | standard.

> This is an interesting point.

> Formally it is permitted to specialize std::complex<> on a
> user-defined (numerical) type, say fixed_point. But the result of
> such specialization is again a user-defined type. So technically it
> is permitted to define numeric_limits<complex<fixed_point> >.

26.2/2: "The effect of instantiating the template complex for any type
other than float, double or long double is unspecified."

A curious sentence. No undefined behavior, but unspecified effects.
What, exactly, are "unspecified effects", when the standard doesn't
specify a list of the allowed effects? In what does it differ from
"undefined behavior"?

At any rate, it looks like you can specialize complex<fixed_point>,
but you can't know what the resulting class does. (Maybe it formats
your hard disk.) On the other hand, as you say,
numeric_limits<complex<fixed_point> > is legal and well defined.

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

Gabriel Dos_Reis

unread,
Dec 5, 2000, 3:00:00 AM12/5/00
to
James Kanze <James...@dresdner-bank.com> writes:

| Gabriel Dos_Reis wrote:
|
| > James Kanze <James...@dresdner-bank.com> writes:
|
| > | Ken Bloom wrote:
|
| > | > you can define numeric_limits<complex<T> > if you so choose.
|
| > | No you can't. Not officially, at any rate. You can only define
| > | specializations over your own types, not those defined in the
| > | standard.
|
| > This is an interesting point.
|
| > Formally it is permitted to specialize std::complex<> on a
| > user-defined (numerical) type, say fixed_point. But the result of
| > such specialization is again a user-defined type. So technically it
| > is permitted to define numeric_limits<complex<fixed_point> >.
|
| 26.2/2: "The effect of instantiating the template complex for any type
| other than float, double or long double is unspecified."

Well, I sould have been more accurate in my wording: I meant an
*explicit* specialization.

| A curious sentence. No undefined behavior, but unspecified effects.

However the Standard defines "unspecified behaviour" to mean:

behavior, for a well-formed program construct and correct data, that
depends on the implementation. The implementation is not required
to document which behavior occurs.

| What, exactly, are "unspecified effects", when the standard doesn't
| specify a list of the allowed effects? In what does it differ from
| "undefined behavior"?

See above.

| At any rate, it looks like you can specialize complex<fixed_point>,

I meant an explicit specialization.

--
Gabriel Dos Reis, dos...@cmla.ens-cachan.fr

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

unread,
Dec 6, 2000, 3:00:00 AM12/6/00
to
Gabriel Dos_Reis wrote:

> | A curious sentence. No undefined behavior, but unspecified effects.

> However the Standard defines "unspecified behaviour" to mean:

> behavior, for a well-formed program construct and correct data, that
> depends on the implementation. The implementation is not required
> to document which behavior occurs.

How does this differ from undefined behavior? What actually happens
in a case of undefined behavior depends on the implementation. And
the implementation is not required to document it.

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

Gabriel Dos_Reis

unread,
Dec 6, 2000, 3:00:00 AM12/6/00
to
James Kanze <James...@dresdner-bank.com> writes:

| Gabriel Dos_Reis wrote:
|
| > | A curious sentence. No undefined behavior, but unspecified effects.
|
| > However the Standard defines "unspecified behaviour" to mean:
|
| > behavior, for a well-formed program construct and correct data, that
| > depends on the implementation. The implementation is not required
| > to document which behavior occurs.
|
| How does this differ from undefined behavior?

Unless I'm mistaken, an undefined behaviour occurs upon use of invalid
constructs or wrong data or use of program constructs not described in
the Standard.

Whether the net effects differ is a matter of debate :-).
However I perceive the two behaviours as being philosophically
distinct even though in practice both may just reformat your hard
drive. (An unspecified behaviour should be less severe than an
undefined bahaviour :-).

--
Gabriel Dos Reis, dos...@cmla.ens-cachan.fr

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

John Potter

unread,
Dec 7, 2000, 3:00:00 AM12/7/00
to
On 6 Dec 2000 09:37:40 -0500, Gabriel Dos_Reis
<gdos...@sophia.inria.fr> wrote:

> James Kanze <James...@dresdner-bank.com> writes:
>
> | Gabriel Dos_Reis wrote:
> |
> | > | A curious sentence. No undefined behavior, but unspecified effects.
> |
> | > However the Standard defines "unspecified behaviour" to mean:
> |
> | > behavior, for a well-formed program construct and correct data, that
> | > depends on the implementation. The implementation is not required
> | > to document which behavior occurs.
> |
> | How does this differ from undefined behavior?
>
> Unless I'm mistaken, an undefined behaviour occurs upon use of invalid
> constructs or wrong data or use of program constructs not described in
> the Standard.
>
> Whether the net effects differ is a matter of debate :-).
> However I perceive the two behaviours as being philosophically
> distinct even though in practice both may just reformat your hard
> drive. (An unspecified behaviour should be less severe than an
> undefined bahaviour :-).

Consider:

f(++x, ++x);

If x is of a user defined type, the order of evaluation is unspecified.

t1 = ++ x;
t2 = ++ x;
f(t1, t2) or f(t2, t1)

For a built-in type we modify a variable twice without a sequence point
giving undefined behavior.

John

James Kanze

unread,
Dec 7, 2000, 10:27:44 AM12/7/00
to
Gabriel Dos_Reis wrote:

> James Kanze <James...@dresdner-bank.com> writes:

> | Gabriel Dos_Reis wrote:

> | > | A curious sentence. No undefined behavior, but unspecified effects.

> | > However the Standard defines "unspecified behaviour" to mean:

> | > behavior, for a well-formed program construct and correct data, that
> | > depends on the implementation. The implementation is not required
> | > to document which behavior occurs.

> | How does this differ from undefined behavior?

> Unless I'm mistaken, an undefined behaviour occurs upon use of invalid
> constructs or wrong data or use of program constructs not described in
> the Standard.

> Whether the net effects differ is a matter of debate :-). However I
> perceive the two behaviours as being philosophically distinct even
> though in practice both may just reformat your hard drive. (An
> unspecified behaviour should be less severe than an undefined
> bahaviour :-).

I agree with the philosophical point. But practically? According to
a note in the definition, "usually, the range of possible behaviors is
delineated by this International Standard." Presumably, the intend is
that nothing untoward happens, since the program is well-formed and
the data correct. But formally, the only difference I see between
unspecified behavior and undefined behavior is that in the first case,
the program is said to be legal, and in the second it is said to be
illegal.

I've been trying, without too much success, to find another example of
unspecified behavior. The one case I remember from the C standard,
converting to a signed integer when the initial value wasn't
representable, has been changed to implementation defined both in C++
and in C99. (The initial text said that the result was unspecified.
This was interpreted as forbidding trapping implementations, since
there would be no result if the operation trapped. So C99
specifically states that a signal may be raised.)

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

Mark Williams

unread,
Dec 7, 2000, 1:01:47 PM12/7/00
to
In article <3A2F62AC...@dresdner-bank.com>,

James Kanze <James...@dresdner-bank.com> wrote:
> Gabriel Dos_Reis wrote:
>
> > James Kanze <James...@dresdner-bank.com> writes:
>

> > Whether the net effects differ is a matter of debate :-). However I
> > perceive the two behaviours as being philosophically distinct even
> > though in practice both may just reformat your hard drive. (An
> > unspecified behaviour should be less severe than an undefined
> > bahaviour :-).
>
> I agree with the philosophical point. But practically? According to
> a note in the definition, "usually, the range of possible behaviors is
> delineated by this International Standard." Presumably, the intend is
> that nothing untoward happens, since the program is well-formed and
> the data correct. But formally, the only difference I see between
> unspecified behavior and undefined behavior is that in the first case,
> the program is said to be legal, and in the second it is said to be
> illegal.
>

I think one difference is that the standard imposes no requirements
whatsoever on a program which invokes undefined behavior at any time
during its run. Presumably, for unspecified behavior, all observable
side-effects that are required to have taken place before the
unspecified behavior ocurrs are still guaranteed by the standard.

-------------
Mark Williams


Sent via Deja.com http://www.deja.com/
Before you buy.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

unread,
Dec 8, 2000, 10:48:37 AM12/8/00
to
John Potter wrote:

> On 6 Dec 2000 09:37:40 -0500, Gabriel Dos_Reis
> <gdos...@sophia.inria.fr> wrote:

> Consider:

> f(++x, ++x);

> If x is of a user defined type, the order of evaluation is unspecified.

Right. But there is a finite set of possibilities. The standard may
not enumerate them explicitly, but the limit is there. In the case in
question, it doesn't seem as if there is a limit. Which, of course,
makes it very much like undefined behavior.

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

James Kanze

unread,
Dec 8, 2000, 10:48:55 AM12/8/00
to
Mark Williams wrote:

> I think one difference is that the standard imposes no requirements
> whatsoever on a program which invokes undefined behavior at any time
> during its run. Presumably, for unspecified behavior, all observable
> side-effects that are required to have taken place before the
> unspecified behavior ocurrs are still guaranteed by the standard.

Good point. In the case in question, I'm pretty sure that one of the
possible unspecified effects is to cause an error during compilation.
(I can hardly imagine anything else occuring if I tried to instantiate
complex< GB_FFmt >, for example, where GB_FFmt is a user defined
manipulator for iostream.)

And of course, if the only side effects were to write to a disk file,
and the unspecified behavior crashes the system before the system
buffer was physically flushed to disk, or reformats the disk, I
certainly willl never be able to see them.

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

Mark Williams

unread,
Dec 8, 2000, 8:36:03 PM12/8/00
to
In article <3A30D41D...@dresdner-bank.com>,

James Kanze <James...@dresdner-bank.com> wrote:
> Mark Williams wrote:
>
> > I think one difference is that the standard imposes no requirements
> > whatsoever on a program which invokes undefined behavior at any time
> > during its run. Presumably, for unspecified behavior, all observable
> > side-effects that are required to have taken place before the
> > unspecified behavior ocurrs are still guaranteed by the standard.
>
> Good point. In the case in question, I'm pretty sure that one of the
> possible unspecified effects is to cause an error during compilation.
> (I can hardly imagine anything else occuring if I tried to instantiate
> complex< GB_FFmt >, for example, where GB_FFmt is a user defined
> manipulator for iostream.)

The same is true of (almost) any template... there will be types for
which it cannot be instantiated.

>
> And of course, if the only side effects were to write to a disk file,
> and the unspecified behavior crashes the system before the system
> buffer was physically flushed to disk, or reformats the disk, I
> certainly willl never be able to see them.

The standard makes no guarantee that you will actually be able to
observe the observable behavior [:-)]... after all, another process
could erase the file before you get the chance to see it.

In this case, suppose you write a program which produces its observable
effects, then solves the halting problem, then invokes
unspecified/undefined behavior. In the unspecified case, you can observe
the observable effects at your leisure, but in the undefined case you
cannot.

It may not, in practice, be a big difference, but it _is_ a difference.

-------------
Mark Williams


Sent via Deja.com http://www.deja.com/
Before you buy.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

unread,
Dec 11, 2000, 7:17:26 AM12/11/00
to
Mark Williams wrote:

> In article <3A30D41D...@dresdner-bank.com>,
> James Kanze <James...@dresdner-bank.com> wrote:
> > Mark Williams wrote:

> > > I think one difference is that the standard imposes no
> > > requirements whatsoever on a program which invokes undefined
> > > behavior at any time during its run. Presumably, for unspecified
> > > behavior, all observable side-effects that are required to have
> > > taken place before the unspecified behavior ocurrs are still
> > > guaranteed by the standard.

> > Good point. In the case in question, I'm pretty sure that one of
> > the possible unspecified effects is to cause an error during
> > compilation. (I can hardly imagine anything else occuring if I
> > tried to instantiate complex< GB_FFmt >, for example, where
> > GB_FFmt is a user defined manipulator for iostream.)

> The same is true of (almost) any template... there will be types for
> which it cannot be instantiated.

True. But in the other cases in the standard, trying to instantiate
the template over an invalid type is undefined behavior. The whole
question is why it is only unspecified behavior here, and what is the
significance of this difference.

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

jkau...@my-deja.com

unread,
Dec 11, 2000, 9:49:23 AM12/11/00
to
In article <3A2B5F71...@dresdner-bank.com>,

James Kanze <James...@dresdner-bank.com> wrote:
> jkau...@my-deja.com wrote:
> >
> > In article <9057fd$7t3$1...@nntp.teliafi.net>,
> > "Jani Kajala" <ja...@remedy.NOSPAMPLEASE.fi> wrote:
> > > You can't compare complex numbers so for example min() doesn't
> > > make much sense.
>
> > You certainly can, compare their magnitudes.
>
> Which doesn't give a complete ordering. And doesn't explain what
> min() should return.
>

class Complex
{
public:
double Modulus() const {return sqrt((m_real*m_real)+
(m_complex*m_complex));}

const Complex &operator < (const Complex &rhs)
{
return Modulus() < rhs.Modulus() ? *this : rhs;
}

private:
double m_real;
double m_complex;
};

or did i miss something?

Sent via Deja.com http://www.deja.com/
Before you buy.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

unread,
Dec 12, 2000, 11:52:15 AM12/12/00
to
jkau...@my-deja.com wrote:

> In article <3A2B5F71...@dresdner-bank.com>,
> James Kanze <James...@dresdner-bank.com> wrote:
> > jkau...@my-deja.com wrote:

> > > In article <9057fd$7t3$1...@nntp.teliafi.net>,
> > > "Jani Kajala" <ja...@remedy.NOSPAMPLEASE.fi> wrote:
> > > > You can't compare complex numbers so for example min() doesn't
> > > > make much sense.

> > > You certainly can, compare their magnitudes.

> > Which doesn't give a complete ordering. And doesn't explain what
> > min() should return.

> class Complex
> {
> public:
> double Modulus() const {return sqrt((m_real*m_real)+
> (m_complex*m_complex));}

> const Complex &operator < (const Complex &rhs)
> {
> return Modulus() < rhs.Modulus() ? *this : rhs;
> }

> private:
> double m_real;
> double m_complex;
> };

> or did i miss something?

Yes. What should min( complex( 1.0, 0.0 ) , complex( 0.0 , 1.0 ) )
return? What about numeric_limits< complex >::min(). More general,
with the < you have defined, the axiom:

! ( a < b ) && ! ( b < a ) <==> a == b

is false. Since many of the standard algorithms count on this, you
can't use this < in the standard algorithms.

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

Ben Liddicott

unread,
Dec 14, 2000, 4:32:59 AM12/14/00
to
"James Kanze" <James...@dresdner-bank.com> wrote in message
news:3A3603EB...@dresdner-bank.com...

> jkau...@my-deja.com wrote:
>
> > In article <3A2B5F71...@dresdner-bank.com>,
> > James Kanze <James...@dresdner-bank.com> wrote:
> > > jkau...@my-deja.com wrote:
>
> > > > In article <9057fd$7t3$1...@nntp.teliafi.net>,
> > > > "Jani Kajala" <ja...@remedy.NOSPAMPLEASE.fi> wrote:
> > > > > You can't compare complex numbers so for example min() doesn't
> > > > > make much sense.
>
> > > > You certainly can, compare their magnitudes.
>
> > > Which doesn't give a complete ordering. And doesn't explain what
> > > min() should return.

There are at least two obvious strict weak orderings for complex.

1) Order by real part, then magnitude of complex part if the real parts
are equal, then if magnitudes of complex parts are equal, the positive one
is greater.
bool operator<(const complex<double>& a, const complex<double>& b)
{
if(a.r<b.r)return true;
if(a.r == b.r){
if(fabs(a.i) < fabs(b.i)) return true;
if(fabs(a.i) == fabs(b.i) && a.i<b.i) return true;
}
return false;
}

2) Order by magnitude, then inversely by magnitude of argument, then if
magnitudes of arguments are equal, the positive imaginary part is greater.
bool operator<(const complex<double>& a, const complex<double>& b)
{
/*there are ways to avoid overflow*/
if(a.i*a.i+a.r*a.r<b.i*b.i+b.r*b.r)return true;
/* magnitudes are equal, so agument ordering is given by real part
ordering */
if(a.r < b.r)return true;
if(a.i < b.i) return true;
return false;
}

I favour the first. Of course there are many more, perhaps less obvious.

> Yes. What should min( complex( 1.0, 0.0 ) , complex( 0.0 , 1.0 ) )
> return? What about numeric_limits< complex >::min(). More general,
> with the < you have defined, the axiom:
>
> ! ( a < b ) && ! ( b < a ) <==> a == b
>
> is false. Since many of the standard algorithms count on this, you
> can't use this < in the standard algorithms.

The question, as so often, is "What do you *want* it to do?". I.e., what
do you want min to return?

Well, make it return that then.

Oh, and for numeric_limits<complex<double> >::min(), you can return
whatever the least value is by the chosen ordering, i.e., for
complex<double> it would be either (numeric_limits<double>::min(), 0.0) or
(0.0,0.0).

Cheers,
Ben Liddicott

0 new messages