Topic: complex design flaw (#1)


Author: Gabriel Dos_Reis <gdosreis@korrigan.inria.fr>
Date: 1999/03/18
Raw View
jcoffin@taeus.com (Jerry Coffin) writes:

| In article <xajn21es2aj.fsf@korrigan.inria.fr>,
| gdosreis@korrigan.inria.fr says...
|
| [ ... ]
|
| > | The reverse is NOT necessarily true -- in particular, any number in
| > | which the mantissa is zero has a value of zero, even if the exponent
| > | has non-zero bits.
| >
| > Again according to IEEE-754 that statement is untrue. For example if
| > the mantissa bits are zero and the exponent is max_exponent+1, then
| > you get what is called +/-Infinity according to the sign bit. If the
| > exponent is non-zero then you get 1.0*pow(2, exponent) beacuse of the
| > hidden bit.
|
| I was trying to be brief and presenting only a worst-case scenario.
| IEEE 754 doesn't guarantee that numbers will be normalized so there
| will BE a hidden bit.

In the scope of IEEE-754, denormalized floating points are precisely
distinguished from normalized one in their exponent bit-patterns.
Denormalized numbers have the lowest exponent so that the hidden bit
is assumed to be zero. In conclusion, if any bit -- except the sign
bit -- is nonzero, then the corresponding floating point number is NOT
0.

Notice that Standard C++ does  provide means to detect whether an
implementation has denormalized numbers or not
(std::numeric_limits<>::has_denorm).


| ... At least in the hardware of which I'm aware,
| double-extended is typically NOT implemented with a hidden bit.

IEEE-754 does NOT define in *detail* the format of extended-precision
floating points. And usually there is *no* hidden bit for
extended-double precision, partly because IEEE-754 specifies only a
minimum amount of bits in an extended precision type.
If I recall correctly, we were talking about double not long double.

| > | However, all of this is merely common practice: the C++ standard
| > | doesn't mandate that you use IEEE floating point (or anything
| > | particularly close to it), and there are still quite a few machines in
| > | the world that don't but may have C++ implementations anyway.  I
| >
| > I agree. But it's a painful task to do *reliable* scientific numerical
| > computations on those machines. I'm not saying that IEEE-754 is the
| > best floating point model. I can hardly imagine a competitive
| > commercial numerical library that chooses to ignore IEEE floating
| > point.
|
| I agree -- however, I'm not sure that was that thrust of his question.
| If his primary interest was in reliable scientific numerical
| computation, he'd probably be better off asking in a different
| newsgroup.  If his interest was in what the C++ standard guarantees
| WRT portability, this was the right place to ask, and I believe the
| answer I gave was basically correct.

The Standard provides support for numerical computations via its
subclause 18.2.1 and clause 26. IMHO it makes sense to discuss in this
group how Standard C++ dispositions are suitable for reliable
scientific computation. Notice I'm not saying this is the right place to
discuss reliable numerical computation in general.

[...]

| > | In the end, setting all bits of a floating point number to zero has
| > | only one effect according to the standard: undefined results.
| >
| > Except when you know that your C++ implementation adheres to
| > IEEE-754.
|
| Which you virtually never do

so what is std::numeric_limits<>::is_iec559 for?


| ... -- even on hardware that implements quite
| a bit of IEEE 754 (which most modern hardware does) what you get out
| of it when it's running code generated by your C or C++ compiler may
| or may not (but usually will) differ at least slightly from what it
| would when set to run exactly by IEEE rules.  In particular, quite a
| bit of hardware doesn't support denormals directly, and many compilers
| don't support them by default either.

Well, I think you miss a point in my previous assertion: I was not
talking about hardware that implements (partially or not) IEEE-754; I
said:

 Except when you know that your C++ implementation adheres to
 IEEE-754.

"C++ implementation" is the key phrase here. Standard C++ provides you
a means to detect whether your compiler adheres to IEC559  aka
IEEE-754 or not.


| In the end, it's probably fairly safe on the range of hardware that we
| usually see software being ported from/to -- I, at least, see a lot of
| software being ported from *NIX to Windows NT, and the assertions in
| questions are pretty safe with most compilers in both these cases.  I
| don't see a lot of software being ported between, say, either of these
| platforms and ancient mainframes that often have considerably...um...
| different (to use the kindest word I can think of) implementations of
| floating point.
|
| OTOH, even within this limited domain, you can run into problems in a
| hurry.  For example, switching something from double to long double is
| a fairly innocuous change in a portable program -- about the worst it
| should ever do is slow things down considerably.

Switching from double to long double is a change of problem and one
(especially a numericist) cannot expect a solution for one problem to
work for another (quite different) problem.

| ...  OTOH, if you're
| relying on the constraints he gave, your program could suddenly quit
| working instead.

It will work if the implementation adheres to IEEE-754 (what you can
always know in Standard C++).

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


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Daniel Parker" <danielp@no_spam.com>
Date: 1999/03/18
Raw View

Jerry Coffin <jcoffin@taeus.com> wrote in article
<MPG.11584ac6ea197fae989959@news.rmi.net>...
> In article <xajn21es2aj.fsf@korrigan.inria.fr>,
> gdosreis@korrigan.inria.fr says...
>
>
> OTOH, even within this limited domain, you can run into problems in a
> hurry.  For example, switching something from double to long double is
> a fairly innocuous change in a portable program -- about the worst it
> should ever do is slow things down considerably.  OTOH, if you're
> relying on the constraints he gave, your program could suddenly quit
> working instead.
> ---
I don't get it.  How

SquareMatrix<double> A(1000);

gets ininitialized says nothing whatsoever about how

SquareMatrix<long double> B(1000);

gets initialized, or

SquareMatrix<std::wstring> C(1000);

for that matter.  Any implementation I could imagine would provide a
general case that would work for everything and only optimize for selected
cases.

Regards,
Daniel Parker danielp@no_spam.anabasis.com



[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Daniel Parker" <danielp@no_spam.com>
Date: 1999/03/14
Raw View
Gabriel Dos_Reis <gdosreis@korrigan.inria.fr> wrote in article
<xaj3e3be4pu.fsf@korrigan.inria.fr>...
>
> nbecker@fred.net writes:
>
> So initialiation of a vector or
> a valarray of complex<double> may be result in a memset().

Incidently, I'm a little rusty on the bit layout of a floating point
number; can I rely on

double x = 0.0;
double y;

memset( &y, 0, sizeof(double) );

x == y ?
memcmp( &x, &y, sizeof(double) ) == 0 ?

Regards,
Daniel Parker danielp@no_spam.anabasis.com
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James Kuyper <kuyper@wizard.net>
Date: 1999/03/15
Raw View
Gabriel Dos_Reis wrote:
> "Daniel Parker" <danielp@no_spam.com> writes:
....
> | through to achieve that goal.  Being handed unnecessary favors like _FLT r
> | = 0, _FLT i = 0 is not what the numerical programmer wants.  And the
> | original point is valid:  if that's not how double or int behaves, why
> | should it be how complex behaves?
>
> Because it is not int nor double?

By that same argument, there's no reason for double to be treated the
same as int, since it's not an int. In many ways double is more similar
to complex than it is to int.

complex<> is defined as an implementation-defined class, but that's not
the only way it could have been done. In Fortran and in C9X, it's a
fundamental type. In C9x, complex will obey the same initialization
rules as the other built-in types. Even as a class type, the default
constructor for complex<> could have been defined to leave it's members
uninitialized, just like the built-in types.

> See -- C compitibility.

Could you be more specific? I didn't find any reference to complex in
the "C compatibility" Annex.


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Larry Brasfield" <larrybr@seanet.com>
Date: 1999/03/15
Raw View
Daniel Parker wrote in message <01be6e30$aeae59e0$7d9cd4c7@danielp.interlog.com>...
>Gabriel Dos_Reis <gdosreis@korrigan.inria.fr> wrote in article
><xaj3e3be4pu.fsf@korrigan.inria.fr>...
>>
>> nbecker@fred.net writes:
>>
>> So initialiation of a vector or
>> a valarray of complex<double> may be result in a memset().

"May" is the operative word here.

>Incidently, I'm a little rusty on the bit layout of a floating point
>number; can I rely on
>
>double x = 0.0;
>double y;
>
>memset( &y, 0, sizeof(double) );
>
>x == y ?
>memcmp( &x, &y, sizeof(double) ) == 0 ?

The representation of floating point numbers is not
specified by the C++ standard.  However, in the
IEEE Standard 754, the representation of double
(and float) is specified such that setting all bits to 0
is equivalent to setting the value to +0.0 (or +0.0f)
and the above two equalities would be true.

For IEEE 754 details, see:
http://www.sns.ias.edu/Main/computing/
compilers_html/common-tools/numerical_comp_guide/index.html
(URL split into two lines)

--Larry Brasfield
Above opinions may be mine alone.
(Humans may reply at unundered larry_br@sea_net.com )



[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James Kuyper <kuyper@wizard.net>
Date: 1999/03/15
Raw View
Daniel Parker wrote:
....
> Incidently, I'm a little rusty on the bit layout of a floating point
> number; can I rely on
>
> double x = 0.0;
> double y;
>
> memset( &y, 0, sizeof(double) );
>
> x == y ?
> memcmp( &x, &y, sizeof(double) ) == 0 ?

For IEEE formats, yes, but those aren't required by the C++ standard.


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: ark@research.att.com (Andrew Koenig)
Date: 1999/03/15
Raw View
In article <01be6e30$aeae59e0$7d9cd4c7@danielp.interlog.com>,
Daniel Parker <danielp@no_spam.com> wrote:

> Incidently, I'm a little rusty on the bit layout of a floating point
> number; can I rely on

> double x = 0.0;
> double y;

> memset( &y, 0, sizeof(double) );

> x == y ?

No.

> memcmp( &x, &y, sizeof(double) ) == 0 ?

Also no.
--
    Andrew Koenig
    ark@research.att.com
    http://www.research.att.com/info/ark



[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Gabriel Dos_Reis <gdosreis@korrigan.inria.fr>
Date: 1999/03/15
Raw View
"Daniel Parker" <danielp@no_spam.com> writes:

| Gabriel Dos_Reis <gdosreis@korrigan.inria.fr> wrote in article
| <xaj3e3be4pu.fsf@korrigan.inria.fr>...
| >
| > nbecker@fred.net writes:
| >
| > So initialiation of a vector or
| > a valarray of complex<double> may be result in a memset().
|
| Incidently, I'm a little rusty on the bit layout of a floating point
| number; can I rely on
|
| double x = 0.0;
| double y;
|
| memset( &y, 0, sizeof(double) );
|
| x == y ?

On most plateforms and with serious C++ implementations (for example those
that adhere to IEEE-754), the answer is unambiguously *yes*.
IEEE-754 and LIA-1 require (-0 == +0) to evaluate to true.

| memcmp( &x, &y, sizeof(double) ) == 0 ?

yes (again under the previous assumptions).

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


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Gabriel Dos_Reis <gdosreis@korrigan.inria.fr>
Date: 1999/03/15
Raw View
James Kuyper <kuyper@wizard.net> writes:

| Gabriel Dos_Reis wrote:
| > "Daniel Parker" <danielp@no_spam.com> writes:
| ....
| > | through to achieve that goal.  Being handed unnecessary favors like _FLT r
| > | = 0, _FLT i = 0 is not what the numerical programmer wants.  And the
| > | original point is valid:  if that's not how double or int behaves, why
| > | should it be how complex behaves?
| >
| > Because it is not int nor double?
|
| By that same argument, there's no reason for double to be treated the
| same as int, since it's not an int. In many ways double is more similar
| to complex than it is to int.

Fair enough. But, if C++ were to be designed from scratch, I for one,
would advocate for zero-initilisation of objects of fundamental types
when declared without initializers.

| complex<> is defined as an implementation-defined class, but that's not
| the only way it could have been done.

I agree.

| ... In Fortran and in C9X, it's a
| fundamental type. In C9x, complex will obey the same initialization
| rules as the other built-in types. Even as a class type, the default
| constructor for complex<> could have been defined to leave it's members
| uninitialized, just like the built-in types.

Personnally I don't much like the actual rule for built-in types.
I don't think the current dissymmetry between built-in types and
user-defined types contributes to make user-defined types look like
built-in ones. Notice that I'm not advocating to transmute built-in
types into clases.

Consider:
 struct X {};

 int i;
 X x;

x's rvalue is defined to be X() whereas i's isn't int() -- it is
undefined.

|
| > See -- C compitibility.
|
| Could you be more specific? I didn't find any reference to complex in
| the "C compatibility" Annex.

My point was that one reason why C++ has the current rule for built-in
types is (probably) for C compatibility.

--
Gabriel Dos Reis, dosreis@cmla.ens-cahcan.fr


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: jcoffin@taeus.com (Jerry Coffin)
Date: 1999/03/15
Raw View
In article <01be6e30$aeae59e0$7d9cd4c7@danielp.interlog.com>,
danielp@no_spam.com says...

[ ... ]

> Incidently, I'm a little rusty on the bit layout of a floating point
> number; can I rely on
>
> double x = 0.0;
> double y;
>
> memset( &y, 0, sizeof(double) );
>
> x == y ?
> memcmp( &x, &y, sizeof(double) ) == 0 ?

No, to both questions.  If you were restricting things to IEEE
floating point, I _believe_ (though I'd have to do some looking to be
sure) that setting all bits to zero will result in a value of zero.
The reverse is NOT necessarily true -- in particular, any number in
which the mantissa is zero has a value of zero, even if the exponent
has non-zero bits.  Likewise, floating point will fairly frequently
use 1's complement for the mantissa, and a bias representation for the
exponent.  This means that all bits set to one in the mantissa is
really a zero.  All bits set to zero in the exponent is an exponent of
-128, and a zero exponent is what would normally be viewed as the
value 128.

However, all of this is merely common practice: the C++ standard
doesn't mandate that you use IEEE floating point (or anything
particularly close to it), and there are still quite a few machines in
the world that don't but may have C++ implementations anyway.  I
haven't tried to figure out for sure, but I believe you could do a
perfectly legal implementation of C++ using something like BCD, and
(for example) use the value zero in a nibble to represent "Negative",
"NaN" or something similar.

In the end, setting all bits of a floating point number to zero has
only one effect according to the standard: undefined results.  You
typically won't see floating-point traps simply by declaring something
as floating point and setting it to an invalid bit-pattern, but
there's nothing to stop the machine from doing this if it wants to.


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: hinnant@_anti-spam_lightlink.com (Howard Hinnant)
Date: 1999/03/16
Raw View
In article <xaj1zirszf9.fsf@korrigan.inria.fr>, Gabriel Dos_Reis
<gdosreis@korrigan.inria.fr> wrote:

> Fair enough. But, if C++ were to be designed from scratch, I for one,
> would advocate for zero-initilisation of objects of fundamental types
> when declared without initializers.

Well, I guess it's time to add my $0.02:

I hardily disagree with zero-initialization of fundamental types.  It goes
against the grain of C/C++.  If I want zero-initialized stuff, there is an
easy way to get it with the current design.  But if we turned on the
automatic transmission, it would not be convenient to get
non-zero-initialized stuff when we needed that performance edge.

And since I've dragged myself into this one.  I must agree with the
original poster:  complex default constructor should leave stuff
uninitialized:

template<class T>
class complex
{
public:
   complex() {}
   complex(const T& re, const T& im = T()) : re_(re), im_(im) {}
....
};

If you want zero-initialized stuff, then it is easy enough to say
complex<double>(0), or vector<complex<double> >(100, complex<double>(0)).

I don't see this as a major desgin flaw, just irritating.

I can always build automatic transmissions out of well designed,
efficient, fundamental building blocks.  But it is much more difficult to
extract performance from a pre-packaged notion of someone else's
"convenience package".

Along the same train of thought, I'd of much preferred double() to mean
uninitialized than double(0).  That way I could easily choose the right
model for my vector<double>.  But that's water under the bridge now...

-Howard
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Gabriel Dos_Reis <gdosreis@korrigan.inria.fr>
Date: 1999/03/16
Raw View
jcoffin@taeus.com (Jerry Coffin) writes:

| In article <01be6e30$aeae59e0$7d9cd4c7@danielp.interlog.com>,
| danielp@no_spam.com says...
|
| [ ... ]
|
| > Incidently, I'm a little rusty on the bit layout of a floating point
| > number; can I rely on
| >
| > double x = 0.0;
| > double y;
| >
| > memset( &y, 0, sizeof(double) );
| >
| > x == y ?
| > memcmp( &x, &y, sizeof(double) ) == 0 ?
|
| No, to both questions.  If you were restricting things to IEEE
| floating point, I _believe_ (though I'd have to do some looking to be
| sure) that setting all bits to zero will result in a value of zero.

According to IEEE-754, if all bits (probably except the sign bit) are
set to zero then the value is zero.

| The reverse is NOT necessarily true -- in particular, any number in
| which the mantissa is zero has a value of zero, even if the exponent
| has non-zero bits.

Again according to IEEE-754 that statement is untrue. For example if
the mantissa bits are zero and the exponent is max_exponent+1, then
you get what is called +/-Infinity according to the sign bit. If the
exponent is non-zero then you get 1.0*pow(2, exponent) beacuse of the
hidden bit.

| ...  Likewise, floating point will fairly frequently
| use 1's complement for the mantissa, and a bias representation for the
| exponent.  This means that all bits set to one in the mantissa is
| really a zero.  All bits set to zero in the exponent is an exponent of
| -128, and a zero exponent is what would normally be viewed as the
| value 128.

I suggest

 http://www.validgh.com/

particulary, paying attention to the paper by Goldberg:

 What Every Computer Scientist Should Know about Floating-Point
 Arithmetic

| However, all of this is merely common practice: the C++ standard
| doesn't mandate that you use IEEE floating point (or anything
| particularly close to it), and there are still quite a few machines in
| the world that don't but may have C++ implementations anyway.  I

I agree. But it's a painful task to do *reliable* scientific numerical
computations on those machines. I'm not saying that IEEE-754 is the
best floating point model. I can hardly imagine a competitive
commercial numerical library that chooses to ignore IEEE floating
point.

| haven't tried to figure out for sure, but I believe you could do a
| perfectly legal implementation of C++ using something like BCD, and
| (for example) use the value zero in a nibble to represent "Negative",
| "NaN" or something similar.

Based on IEEE-854?

| In the end, setting all bits of a floating point number to zero has
| only one effect according to the standard: undefined results.

Except when you know that your C++ implementation adheres to
IEEE-754.

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


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Gabriel Dos_Reis <gdosreis@korrigan.inria.fr>
Date: 1999/03/16
Raw View
ark@research.att.com (Andrew Koenig) writes:

| In article <xaj1zirszf9.fsf@korrigan.inria.fr>,
| Gabriel Dos_Reis  <gdosreis@korrigan.inria.fr> wrote:
|
| > Fair enough. But, if C++ were to be designed from scratch, I for one,
| > would advocate for zero-initilisation of objects of fundamental types
| > when declared without initializers.
|
| The committee discussed this issue, actually, and there's a problem:
| Often, one wants to allocate a large arran and fill a part of it;
| how large a part is unknown until execution time.
|
| it would be unfortunate if the cost of doing so always had to be
| proportional to the size of the array, rather than the size of
| the portion that's actually used.

Indeed. But does that point still hold under the "as-if" rule?

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


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Daniel Parker" <danielp@no_spam.com>
Date: 1999/03/16
Raw View
Jerry Coffin <jcoffin@taeus.com> wrote in article
<MPG.115705178a5dc0198994f@news.rmi.net>...
>
> In article <01be6e30$aeae59e0$7d9cd4c7@danielp.interlog.com>,
> danielp@no_spam.com says...
>
> > double x = 0.0;
> > double y;
> >
> > memset( &y, 0, sizeof(double) );
> >
> > x == y ?
> > memcmp( &x, &y, sizeof(double) ) == 0 ?
>
> No, to both questions.  If you were restricting things to IEEE
> floating point, I _believe_ (though I'd have to do some looking to be
> sure) that setting all bits to zero will result in a value of zero.

OK, but in the spirit of Gabriel Dos_Reis's post, would it be sensible
(stupid?) to do the following.  In the system dependency library (that's
the - hopefully small - one with all the #ifdef's) provide an
implementation of an allocator such that if one were to write something
like

SquareMatrix< std::complex<double> > A(10000);

on systems that supported IEEE, the allocation of the data would proceed as
follows: allocate 10000*10000*sizeof(std::complex<double>) of raw memory,
memset it to zero, and skip the step of calling placement new.

Regards,
Daniel Parker danielp@no_spam.anabasis.com



[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/03/16
Raw View
Gabriel Dos_Reis wrote:
>
> ark@research.att.com (Andrew Koenig) writes:
>
> | In article <xaj1zirszf9.fsf@korrigan.inria.fr>,
> | Gabriel Dos_Reis  <gdosreis@korrigan.inria.fr> wrote:
> |
> | > Fair enough. But, if C++ were to be designed from scratch, I for one,
> | > would advocate for zero-initilisation of objects of fundamental types
> | > when declared without initializers.
> |
> | The committee discussed this issue, actually, and there's a problem:
> | Often, one wants to allocate a large arran and fill a part of it;
> | how large a part is unknown until execution time.
> |
> | it would be unfortunate if the cost of doing so always had to be
> | proportional to the size of the array, rather than the size of
> | the portion that's actually used.
>
> Indeed. But does that point still hold under the "as-if" rule?

How clever wpould a compiler have to be to determine which parts
of an array will be used?

#include <some/system/header/xy.h>

void bar(int*); // defined somewhere else

void foo()
{
  int* pi = new int[_MAX_XY_HANDLES];
  _get_current_xy_handles(pi);
           // how many ints will it fill? 10? 100? 500?
  bar(pi); // which ints will this function read?
  delete[] pi;
}
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: jcoffin@taeus.com (Jerry Coffin)
Date: 1999/03/18
Raw View
In article <xajn21es2aj.fsf@korrigan.inria.fr>,
gdosreis@korrigan.inria.fr says...

[ ... ]

> | The reverse is NOT necessarily true -- in particular, any number in
> | which the mantissa is zero has a value of zero, even if the exponent
> | has non-zero bits.
>
> Again according to IEEE-754 that statement is untrue. For example if
> the mantissa bits are zero and the exponent is max_exponent+1, then
> you get what is called +/-Infinity according to the sign bit. If the
> exponent is non-zero then you get 1.0*pow(2, exponent) beacuse of the
> hidden bit.

I was trying to be brief and presenting only a worst-case scenario.
IEEE 754 doesn't guarantee that numbers will be normalized so there
will BE a hidden bit.  At least in the hardware of which I'm aware,
double-extended is typically NOT implemented with a hidden bit.

> | However, all of this is merely common practice: the C++ standard
> | doesn't mandate that you use IEEE floating point (or anything
> | particularly close to it), and there are still quite a few machines in
> | the world that don't but may have C++ implementations anyway.  I
>
> I agree. But it's a painful task to do *reliable* scientific numerical
> computations on those machines. I'm not saying that IEEE-754 is the
> best floating point model. I can hardly imagine a competitive
> commercial numerical library that chooses to ignore IEEE floating
> point.

I agree -- however, I'm not sure that was that thrust of his question.
If his primary interest was in reliable scientific numerical
computation, he'd probably be better off asking in a different
newsgroup.  If his interest was in what the C++ standard guarantees
WRT portability, this was the right place to ask, and I believe the
answer I gave was basically correct.

> | haven't tried to figure out for sure, but I believe you could do a
> | perfectly legal implementation of C++ using something like BCD, and
> | (for example) use the value zero in a nibble to represent "Negative",
> | "NaN" or something similar.
>
> Based on IEEE-854?

You could base it on IEEE 854 (or 954 IIRC), or you could implementing
C++ on some ancient design that predates 854 or even 754, but 20 years
or more...

> | In the end, setting all bits of a floating point number to zero has
> | only one effect according to the standard: undefined results.
>
> Except when you know that your C++ implementation adheres to
> IEEE-754.

Which you virtually never do -- even on hardware that implements quite
a bit of IEEE 754 (which most modern hardware does) what you get out
of it when it's running code generated by your C or C++ compiler may
or may not (but usually will) differ at least slightly from what it
would when set to run exactly by IEEE rules.  In particular, quite a
bit of hardware doesn't support denormals directly, and many compilers
don't support them by default either.

In the end, it's probably fairly safe on the range of hardware that we
usually see software being ported from/to -- I, at least, see a lot of
software being ported from *NIX to Windows NT, and the assertions in
questions are pretty safe with most compilers in both these cases.  I
don't see a lot of software being ported between, say, either of these
platforms and ancient mainframes that often have considerably...um...
different (to use the kindest word I can think of) implementations of
floating point.

OTOH, even within this limited domain, you can run into problems in a
hurry.  For example, switching something from double to long double is
a fairly innocuous change in a portable program -- about the worst it
should ever do is slow things down considerably.  OTOH, if you're
relying on the constraints he gave, your program could suddenly quit
working instead.
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Gabriel Dos_Reis <gdosreis@korrigan.inria.fr>
Date: 1999/03/18
Raw View
"Daniel Parker" <danielp@no_spam.com> writes:

| Jerry Coffin <jcoffin@taeus.com> wrote in article
| <MPG.115705178a5dc0198994f@news.rmi.net>...
| >
| > In article <01be6e30$aeae59e0$7d9cd4c7@danielp.interlog.com>,
| > danielp@no_spam.com says...
| >
| > > double x = 0.0;
| > > double y;
| > >
| > > memset( &y, 0, sizeof(double) );
| > >
| > > x == y ?
| > > memcmp( &x, &y, sizeof(double) ) == 0 ?
| >
| > No, to both questions.  If you were restricting things to IEEE
| > floating point, I _believe_ (though I'd have to do some looking to be
| > sure) that setting all bits to zero will result in a value of zero.
|
| OK, but in the spirit of Gabriel Dos_Reis's post, would it be sensible
| (stupid?) to do the following.  In the system dependency library (that's
| the - hopefully small - one with all the #ifdef's) provide an
| implementation of an allocator such that if one were to write something
| like
|
| SquareMatrix< std::complex<double> > A(10000);
|
| on systems that supported IEEE, the allocation of the data would proceed as
| follows: allocate 10000*10000*sizeof(std::complex<double>) of raw memory,
| memset it to zero, and skip the step of calling placement new.

There is nothing wrong with it.
That is in essence what I was saying: an implementation is free to do
that optimization. In fact, I would expect amoderatly mature C++
implementation to  perform similar optimization.

--
Gabriel Dos Reis, dosreis@cmla.ens-cachan.fr
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: nbecker@fred.net
Date: 1999/03/11
Raw View
I believe that std complex has serious design flaws that preclude
(unnecessarily) it's use in high performance computing.

The worst (and most unnecessary) is

  complex (_FLT r = 0, _FLT i = 0): re (r), im (i) { }

Because of this, construction of containers of complex are expensive.

I can hardly think of a good rational behind requiring the
initialization to be with a zero value.  This is completely
unsymmetrical with respect to the behavior of the other primitive
numerical types, like int or double.

I hope this flaw can somehow be fixed.


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Gabriel Dos_Reis <gdosreis@korrigan.inria.fr>
Date: 1999/03/12
Raw View
nbecker@fred.net writes:

| I believe that std complex has serious design flaws that preclude
| (unnecessarily) it's use in high performance computing.
|
| The worst (and most unnecessary) is
|
|   complex (_FLT r = 0, _FLT i = 0): re (r), im (i) { }
|
| Because of this, construction of containers of complex are expensive.
|
| I can hardly think of a good rational behind requiring the
| initialization to be with a zero value.  This is completely
| unsymmetrical with respect to the behavior of the other primitive
| numerical types, like int or double.
|
| I hope this flaw can somehow be fixed.

Unless I'm mistaken, we've already discussed this issue on the EGCS
mainling list and I've told you that an implementation has special
knowledge of entities declared/defined in the C++ standard library and
can do some magic behind the scene. So initialiation of a vector or
a valarray of complex<double> may be result in a memset(). If you were
going to do number crunching I doubt you'll notice the initialization
overhead (with an optmizing compiler).

And optimization is a quality of implementation issue.

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


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Daniel Parker" <danielp@no_spam.com>
Date: 1999/03/13
Raw View
Gabriel Dos_Reis <gdosreis@korrigan.inria.fr> wrote in article
<xaj3e3be4pu.fsf@korrigan.inria.fr>...
>
> nbecker@fred.net writes:
>
> | I believe that std complex has serious design flaws that preclude
> | (unnecessarily) it's use in high performance computing.
> |
> | The worst (and most unnecessary) is
> |
> |   complex (_FLT r = 0, _FLT i = 0): re (r), im (i) { }
> |
> Unless I'm mistaken, we've already discussed this issue on the EGCS
> mainling list and I've told you

I've no doubt this is true, but

> that an implementation has special
> knowledge of entities declared/defined in the C++ standard library and
> can do some magic behind the scene. So initialiation of a vector or
> a valarray of complex<double> may be result in a memset().

isn't this somewhat irrelevent to the original poster's concern?  vector
and valarray are not all that useful for numerical work insofar as much
numerical work requires matrix, tensor, or n-dimensional array classes.

> And optimization is a quality of implementation issue.

Perfomance depends more on how well basic principles have been thought
through to achieve that goal.  Being handed unnecessary favors like _FLT r
= 0, _FLT i = 0 is not what the numerical programmer wants.  And the
original point is valid:  if that's not how double or int behaves, why
should it be how complex behaves?

Regards,
Daniel Parker danielp@no_spam.anabasis.com
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Gabriel Dos_Reis <gdosreis@korrigan.inria.fr>
Date: 1999/03/14
Raw View
"Daniel Parker" <danielp@no_spam.com> writes:

[...]

| > that an implementation has special
| > knowledge of entities declared/defined in the C++ standard library and
| > can do some magic behind the scene. So initialiation of a vector or
| > a valarray of complex<double> may be result in a memset().
|
| isn't this somewhat irrelevent to the original poster's concern?

No. IMNSHO.

| ... vector
| and valarray are not all that useful for numerical work insofar as much
| numerical work requires matrix, tensor, or n-dimensional array classes.

The point I was making wasn't whether or not vector or valarray are
useful for numerical work. Mr. Becker stated that because of the way
the class complex is declared

> construction of containers of complex are expensive.


And again, I don't buy his claim for reasons I stated above.

| > And optimization is a quality of implementation issue.
|
| Perfomance depends more on how well basic principles have been thought
| through to achieve that goal.  Being handed unnecessary favors like _FLT r
| = 0, _FLT i = 0 is not what the numerical programmer wants.  And the
| original point is valid:  if that's not how double or int behaves, why
| should it be how complex behaves?

Because it is not int nor double?

See -- C compitibility.

--
Gabriel Dos Reis, dosreis@cmla.ens-cachan.fr
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]