Topic: int overflow gives UB
Author: kanze@gabi-soft.fr
Date: Wed, 15 Sep 2004 12:40:19 CST Raw View
alfps@start.no (Alf P. Steinbach) wrote in message
news:<41473dcd.1001356453@news.individual.net>...
[...]
> > And that implementations should be allowed to catch that error.
> That is something that can be fruitfully discussed (note that common
> implementations do not give error-signaling functionality today), and
> I think that's just about where we started, no?
Yep.
I know you're a competent programmer, and I think I am, so either the
issue is something two competent people can reasonably disagree on, or
we've failed to communicate. Anyway, I've presented my arguments, as
best I could, and I've failed to convince you (and vice versa).
Realistically, I don't think that there is much chance of the standard
(nor the current implementations) changing here anyway, so it probably
doesn't matter.
One interesting side effect is that I read the specifications for
clock() a lot more closely, and it appears that the standard actually
forbids wrap around, and requires -1 if the value wraps. I don't think
that this was the intent, and it certainly isn't what any
implementations I know of do, so maybe someone should notify the C
standards group that there may be a problem in their specification of
clock().
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.fr
Date: Mon, 13 Sep 2004 16:52:26 GMT Raw View
francis@robinton.demon.co.uk (Francis Glassborow) wrote in message
news:<la224CD3ZsQBFwac@robinton.demon.co.uk>...
> In article <d6652001.0409100427.71a557d3@posting.google.com>,
> kanze@gabi-soft.fr writes
> >One last remark concerning your use of clock(). If you accept that
> >clock() can wrap, it can also return -1. How do you distinguish this
> >case from an error?
> clock_t is only required to be an arithmetic type. What -1 is when
> cast to clock_t entirely depends on which type is selected by the
> implementation. The cast is well-defined for all types.
True. But if you write your code so that clock_t never wraps, you won't
ever see it. Whereas if you count on wrapping, you have to be prepared
for it.
> However undefined behaviour on overflow is not an option for unsigned
> integer types, though it is for all other arithmetic types. In the
> case of floating point types overflow problems are only a theoretical
> issue because your computer will be dust long before overflow
> occurs. That is not the case for signed integer types.
> Perhaps we should be raising a DR with WG14 because the current
> requirements on clock() are impractical to implement using any
> standard integer type if the tick rate is sufficiently small.
So what solution do you propose?
In practice, a 64 bit (long long) clock_t should be usable for any tick
rates we're likely to see in the near future. In the meantime,
apparently some implementers feel that limiting the use of clock() to
the first 35 minutes of the program is acceptable. And a lot of people
are using such systems, so maybe it is. (I've never called clock() in a
program which ran for more than 35 minutes, so it doesn't bother me.
But I'm not everybody.)
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Mon, 13 Sep 2004 18:32:38 GMT Raw View
Uhm, the kind moderators returned my original response where I
simply pointed out the main error.
Perhaps that seemed too harsh, or perhaps the connection to the C++ standard
(standardization of signed overflow behavior) was unclear.
So for the benefit of new readers & moderators: this concerns a common example
of practical usage of signed integer overflow which James Kanze denies even
exists as such -- said denial being in favor of non-standardization of the
behavior of signed integer overflow which is currently UB.
* kanze@gabi-soft.fr:
> alfps@start.no (Alf P. Steinbach) wrote in message
> news:<41391287.72776296@news.individual.net>...
> > * kanze@gabi-soft.fr:
> > > If there is overflow, regardless of how it is handled by the system,
> > > the results are wrong.
>
> > That is incorrect.
>
> No it isn't.
I guess with short quotes like above anybody could be confused as to what
"wrong" and "incorrect" and "it isn't" really means, so, original context:
* Alf:
> Why do you think [the recommended usage of clock()] don't test for
> overflow?
* James:
> Because there is no easy way of doing it, and because in practice, it is
> pretty easy to avoid. If there is overflow, regardless of how it is
> handled by the system, the results are wrong.
Perhaps you meant to write that obtaining the correct result would be
wrong with respect to the C standard, due to the -1 error return
requirement (not used by common implementations)? But if so it was not
evident from the context. However, if the intended point was that the C
standard should be improved to allow correct results, then I agree with that,
but it's a bit off-topic for this group which is about the C++ standard.
Now, error by small error:
"there is no easy way of doing it" is incorrect. One easy and formally
correct way is to check for -1. The main problem with that is that it
doesn't work in practice, for common implementations. One easy way
that is both formally correct and works in practice is to check whether
the return value of clock() is negative: for the in-practice part it
works for clock_t = double because you don't get overflow there, and it
works for clock_t = long because you get signed wrap-around there.
"because in practice, it is pretty easy to avoid" is incorrect: it is
only _possible_ to avoid overlow by not using clock() for anything else
than a single simple measurement of a time period ending within a
sufficiently short time span from the beginning of the process, disregarding
that there is _no_ formally correct way of determining what is sufficiently
short since the standard does not and can not require completion of any
statement within any specific period of time.
"If there is overflow, regardless of how it is handled by the system, the
results are wrong" is incorrect because it has been shown repeatedly that the
common way of handling overflow does yield the correct result when the result
is representable by clock_t -- regardless of when the measurement is made.
> You seem to be stubornly missing the point.
Yes, I'm stubborn... :-)
And yes, I'm missing the point: what on Earth _is_ the point?
> The results are well defined only in the absense of overflow.
Here it would be nice if you could clarify whether you're referring
to the standard or the in-practice.
For the standard's behavior the statement is incorrect: it is incorrect
because the standard requires the well-defined -1 in case of overflow.
For the in-practice the statement is incorrect: it is incorrect because in
practice signed integer overflow gives two's complement wraparound, on all
currently used machines that I know of, and that wraparound produces correct
final result when the result is representable by clock_t.
> If overflow occurs,
> they may be correct, some of the time, on some machines, but you have no
> way of knowing when they are correct, and when they are not.
Here it would be nice if you could clarify whether you're referring
to the standard or the in-practice.
For the standard's behavior the statement is incorrect because it's
easy to check for -1 (or more practically, negative values).
For the in-practice the statement is incorrect because any period of time that
is "safe" to measure at the start of the process can involve overflow in the
substraction of start time from end time when measured later in the process,
where a just as "safe" correct result is obtained, but involving overflow.
> For all practical purposes, there is a limited interval of time in which
> you can use clock().
Here it seems clear that in-practice is referred to, and with that
interpretation the statement is incorrect: the time interval you can safely
measure using clock() is limited, but there is no limited interval in which
clock() can safely be used.
[...]
> > Consider clock_t = int for 16 bit two's complement, first call of
> > clock() giving 32760, and elapsed time in clock ticks before second
> > call of clock() as 200 ticks, say.
>
> You now have undefined behavior.
Yes.
> In practice, if the first call to clock() returns such a high value,
> there is no point in continuing.
In practice, you obtain the correct result (the sought time interval)
by continuing -- so yes, I'd say there is very much point in that!
> > If you do this correctly, as per the recommendations cited earlier,
> > you should obtain the correct result of 200 ticks.
>
> For this one particular example. Not necessarily in general.
Right.
I add in passing that this statement contradicts the previous statement about
"no point in continuing".
> In general, clock() is good for a certain period of time. Beyond that,
> you can't use it.
Here it would be nice if you could clarify whether you're referring
to the standard or the in-practice.
For the standard's behavior this is a _correct_ statement.
For the in-practice the statement is incorrect, and that's partly why we need
standardization of signed integer overflow.
[...]
> > For use of clock() on current machines & implementations the only
> > requirement is (as has now been stated how many times?) that the
> > elapsed tick count is is within the range of clock_t.
>
> And how do you know it is within the range of clock_t? You know it only
> because the total values have never overflowed; because the total
> runtime is small enough so that overflow cannot occur.
No, I know it because the period to be measured is decidedly within the span
representable by a clock_t.
That cannot be formally determined because even a simple assignment might take
an hour on a system where the OS is trashing.
But that's just the same as whether clock() is useful _at all_.
> Do you know of any real programs which count on the difference between
> two calls to clock() giving correct results, even though the program has
> been running for hours? The *only* programs I know which use clock()
> are benchmark harnesses, which call clock() very near the beginning of
> the program, and which terminate before it has had the time to wrap.
Such programs have been mentioned earlier in the tread, by someone, in
direct response to you.
I might add that of course I've seen this in others' code, and also used it
myself.
And earlier a number of references to recommended usage of clock() was listed,
and it would surprise me greatly if only I, people I know and have known, and
those participating in this thread, do it the recommended way.
> I won't say that you cannot invent programs which do count on some
> specific behavior in the case of overflow. But such programs don't
> exist in real life -- in every real case of overflow I've seen, it has
> been a program error, and it would have been better to abort the program
> immediately.
>
> > As long the tick count is representable an overflow can occur as much
> > as it wants, and it does occur.
>
> Except that if overflow can occur, you have to deal with the case that
> the tick count might not be representable.
You either have to deal with that in _any_ case, or know that the code
will never exceed the representable time.
Here's one scenario: I want an event-loop to time out after a certain
interval. The in-practice code might go like this:
clock_t const startTime = std::clock();
while( doEvents() )
{
double const elapsedTime = std::clock() - startTime;
if( elapsedTime < 0 || elapsedTime > maxTime ) { break; }
sleepMilliseconds( 100 );
}
The check for <0 detects a non-representable interval under the assumptions
that doEvents() + 100 msec is representable and that signed arithmetic is
two's complement with wraparound.
To be standard-conforming the code should also check whether clock()
returns a negative value, but if the implementation unlike common
implementations today followed the standard, the code would have little point
and clock() would be of little practical utility.
> > But the overflow doesn't affect anything. The recommended way of
> > using clock() still produces the correct answer (and that's why it is
> > the recommended way).
>
> The reason that it is the recommended way is because it is the only way
> to obtain the correct answer, even without overflow.
That is incorrect because with a clock() that returns -1 on overflow, as per
the C standard, the recommended usage produces an _incorrect_ answer when
there is overflow. It only produces a correct answer when there is no
possibility of overflow, OR when the overflow is signed integer wraparound and
the result is representable by clock_t. It would be easy to insert a check
for negative number, but that check isn't there: presumably for good reason.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.fr
Date: Tue, 14 Sep 2004 18:23:58 GMT Raw View
alfps@start.no (Alf P. Steinbach) wrote in message
news:<4145b19a.899929328@news.individual.net>...
> * kanze@gabi-soft.fr:
> > alfps@start.no (Alf P. Steinbach) wrote in message
> > news:<41391287.72776296@news.individual.net>...
> > > * kanze@gabi-soft.fr:
> > > > If there is overflow, regardless of how it is handled by the
> > > > system, the results are wrong.
> > > That is incorrect.
> > No it isn't.
> I guess with short quotes like above anybody could be confused as to
> what "wrong" and "incorrect" and "it isn't" really means, so, original
> context:
> * Alf:
> > Why do you think [the recommended usage of clock()] don't test for
> > overflow?
> * James:
> > Because there is no easy way of doing it, and because in practice,
> > it is pretty easy to avoid. If there is overflow, regardless of how
> > it is handled by the system, the results are wrong.
> Perhaps you meant to write that obtaining the correct result would be
> wrong with respect to the C standard, due to the -1 error return
> requirement (not used by common implementations)? But if so it was
> not evident from the context.
I wasn't really thinking of the -1 in this case. I was simply thinking
of the general context. Strictly speaking, of course, you really have
no formel way of every knowing that the results of clock() are usable --
it could have wrapped twenty times, for all you can tell from what the
interface officially tells you. In practice, of course, if you stay
away from the limits of the function, you're OK. Well away from the
limits: because you have no reliable way of detecting when you cross the
limits, you have to have to count on being far enough away that no
reasonable amount jitter could push you over.
As to what the limits are, that is implementation defined. The man page
under Solaris says the first 36 minutes after the first call to clock().
(It also guarantees that the first call to clock() will return 0. Even
if the program has been running for hours.) I suspect that in many
cases, however, they aren't documented.
My point is simply that once you start considering the possibility of
wrapping, you are too close to the limits. Even if we accepted the
legitimacy of wrapping, at the most, it can double the limit -- I think
you'd agree that if we wrap more than once, we really have no idea where
we are. And a factor of two really isn't really sufficient when we are
counting to stay well away from the limit.
The one possible exception is that mentionned by James Kuyper, where it
takes hours to set things up, then you measure once a relatively short
span of time. Of course, there's no need for this to be portable, it's
a one of measure. And on some machines, at least in theory, it won't
work, because wrapping is currently undefined behavior. (Arguably, on
any machine which correctly implements the standard, it might not work,
because the standard requires clock() to return -1 if it cannot
represent the correct value. Pratically, I don't know of any
implementation which conforms in this regard, so despite the fact that
we are in comp.std.c++, and should be mainly concerned with the
standard -- and the fact that it would be an absolute clincher to my
argument:-), I'll ignore it.)
Anyway, whether it works or not depends on the implementation. Under
Solaris, it should work, because Solaris guarantees that the first call
to clock() always returns 0. (I've done a couple of trials, and the
first call always does return 0. Regardless of how much CPU I've used
before.)
> However, if the intended point was that the C standard should be
> improved to allow correct results, then I agree with that, but it's a
> bit off-topic for this group which is about the C++ standard.
> Now, error by small error:
> "there is no easy way of doing it" is incorrect. One easy and
> formally correct way is to check for -1. The main problem with that
> is that it doesn't work in practice, for common implementations. One
> easy way that is both formally correct and works in practice is to
> check whether the return value of clock() is negative: for the
> in-practice part it works for clock_t = double because you don't get
> overflow there, and it works for clock_t = long because you get signed
> wrap-around there.
> "because in practice, it is pretty easy to avoid" is incorrect: it is
> only _possible_ to avoid overlow by not using clock() for anything
> else than a single simple measurement of a time period ending within a
> sufficiently short time span from the beginning of the process,
Which is the only case where clock() is defined, and the only cases
where I've actually seen it used. I've since found out that at least
one person has used it, in a very controlled way, later in his program.
He admitted, however, that he did so fully aware that this use wasn't
portable.
I wonder what his platform was. I also wonder if other Unix's besides
Solaris guarantee 0 for the first call (in which case, his use didn't
count on overflow wrapping) -- much of Solaris is common System V code,
also present in HP-UX or AIX. And it seems like a reasonable compromize
if you really want to use some outrageously large CLOCKS_PER_SEC value.
> disregarding that there is _no_ formally correct way of determining
> what is sufficiently short since the standard does not and can not
> require completion of any statement within any specific period of
> time.
That is, of course, a general problem. If your program terminates in
five minutes of wall clock time, however, and CLOCKS_PER_SEC is less
than or equal to a million, on a 32 bit (or larger) machine, you're
probably safe.
> "If there is overflow, regardless of how it is handled by the system,
> the results are wrong" is incorrect because it has been shown
> repeatedly that the common way of handling overflow does yield the
> correct result when the result is representable by clock_t --
> regardless of when the measurement is made.
You claim to have shown it. You show one or two exceptional cases where
it happens to work. You miss completely the essential point: you don't
know that you can count on the results. Code which counts on this today
is simply incorrect. According to the standard, and according to all
the documentation I can find concerning concrete implementations. It
may work sometime, but that doesn't make the code any more correct.
Your argument is that the standard should be changed to make it
correct. Until now, however, the only advantage you have been able to
show is that it might make some additional uses of clock() possible, on
some platforms. You've not pointed out any real advantage of such uses;
they don't occur if clock() is used as it was designed to be used.
> > You seem to be stubornly missing the point.
> Yes, I'm stubborn... :-)
> And yes, I'm missing the point: what on Earth _is_ the point?
The point is that no programmer in his right mind knowing writes code
today which counts on signed arithmetic wrapping. The point is that
when signed arithmetic overflows, it is a programming error. And that
implementations should be allowed to catch that error.
> > The results are well defined only in the absense of overflow.
> Here it would be nice if you could clarify whether you're referring to
> the standard or the in-practice.
Both. Working in practice doesn't mean that it just happens to give the
correct results in one particular case. It means that I can count on it
giving the correct results, always.
At least, that's the definition of "working in practice" that I use.
> For the standard's behavior the statement is incorrect: it is
> incorrect because the standard requires the well-defined -1 in case of
> overflow.
> For the in-practice the statement is incorrect: it is incorrect
> because in practice signed integer overflow gives two's complement
> wraparound, on all currently used machines that I know of, and that
> wraparound produces correct final result when the result is
> representable by clock_t.
Ever used a Unisys 2200? (1's complement -- I don't know what happens
in the case of overflow, but I doubt that it is the 2's complement
results. Particularly because the result you get with 2's complement
when you overflow by exactly 1 isn't even representable in 1's
complement.) Other examples have existed, and maybe still do. If we
want to consider this route, we should probably start by saying that
int's are always 32 bits. That would probably be a lot more useful to a
lot more people than defining what happens in the case of overflow.
Note too that this would be yet another divergence from C. The C
committee reconsidered the question of conversions (not arithmetic) in
C99, and decided explicitly to allow a system defined signal.
> > If overflow occurs, they may be correct, some of the time, on some
> > machines, but you have no way of knowing when they are correct, and
> > when they are not.
> Here it would be nice if you could clarify whether you're referring to
> the standard or the in-practice.
Both. Again -- if you know that there is no wrap around, because you
are well within the envelope, then you are safe. Once you approch the
limits of the envelope, even without wrap around, you are no longer
sure. And once you admit wrap around, you have no way of knowing how
many times you've wrapped.
> For the standard's behavior the statement is incorrect because it's
> easy to check for -1 (or more practically, negative values).
But if you throw out all negative return values from clock(), how does a
defined wrap around help you? I thought the whole point of wanting wrap
around is so that negative values would have a defined behavior.
> For the in-practice the statement is incorrect because any period of
> time that is "safe" to measure at the start of the process can involve
> overflow in the substraction of start time from end time when measured
> later in the process, where a just as "safe" correct result is
> obtained, but involving overflow.
> > For all practical purposes, there is a limited interval of time in
> > which you can use clock().
> Here it seems clear that in-practice is referred to, and with that
> interpretation the statement is incorrect: the time interval you can
> safely measure using clock() is limited, but there is no limited
> interval in which clock() can safely be used.
That's not what the documentation of the function says. That's not what
any recommended use I've seen says either. And it's not what happens in
practice, because you may accidentally see a -1 if you allow wrap
around.
> [...]
> > > Consider clock_t = int for 16 bit two's complement, first call of
> > > clock() giving 32760, and elapsed time in clock ticks before
> > > second call of clock() as 200 ticks, say.
> > You now have undefined behavior.
> Yes.
> > In practice, if the first call to clock() returns such a high value,
> > there is no point in continuing.
> In practice, you obtain the correct result (the sought time interval)
> by continuing -- so yes, I'd say there is very much point in that!
In practice, you don't know whether the results are correct or not.
> > > If you do this correctly, as per the recommendations cited
> > > earlier, you should obtain the correct result of 200 ticks.
> > For this one particular example. Not necessarily in general.
> Right.
> I add in passing that this statement contradicts the previous
> statement about "no point in continuing".
How? Are you saying that it is OK to continue because you might get
lucky and get the right results anyway? We must have different
standards of quality.
> > In general, clock() is good for a certain period of time. Beyond
> > that, you can't use it.
> Here it would be nice if you could clarify whether you're referring to
> the standard or the in-practice.
Both.
> For the standard's behavior this is a _correct_ statement.
> For the in-practice the statement is incorrect, and that's partly why
> we need standardization of signed integer overflow.
You say it is incorrect, but you cannot present any evidence to show it
is so.
Note that for it to be correct, you need more than just wrapping. You
need an implementations of clock() that is non-conforming (rather
frequent, I'll admit), and one which guarantees the lack of conformity,
so that you can be sure that they don't fix the bug (and that, I've
never seen).
> [...]
> > > For use of clock() on current machines & implementations the only
> > > requirement is (as has now been stated how many times?) that the
> > > elapsed tick count is is within the range of clock_t.
> > And how do you know it is within the range of clock_t? You know it
> > only because the total values have never overflowed; because the
> > total runtime is small enough so that overflow cannot occur.
> No, I know it because the period to be measured is decidedly within
> the span representable by a clock_t.
I repeat, how?
In practice, I think that some techniques exist. If you encadre the
calls to clock() with calls to time(), and verify that the total elapsed
wall clock time is less than, say, five minutes, I'd guess that you'd be
safe. But in this case, we're wandering considerably away from your
original point, which claimed that there was a recommended practice
involving clock() which counted on integral arithmetic wrapping.
Because the recommended practice that you cited didn't involve any such
checking. (Of course, the recommended practice didn't involve integral
arithmetic wrapping, either.)
Note that while you cannot manually verify that any particular part of a
program has executed in some limited time, you can usually control that
the entire program has run in a limited time. As I said, if your entire
program finishes in, say, less that five minutes, on a 32 bit machine,
you can probably be pretty confident that the values returned by clock()
are significant (for some definition of significant -- the values
returned by the Windows implementation do signify something considerably
different from those returned by Unix).
> That cannot be formally determined because even a simple assignment
> might take an hour on a system where the OS is trashing.
> But that's just the same as whether clock() is useful _at all_.
> > Do you know of any real programs which count on the difference
> > between two calls to clock() giving correct results, even though the
> > program has been running for hours? The *only* programs I know
> > which use clock() are benchmark harnesses, which call clock() very
> > near the beginning of the program, and which terminate before it has
> > had the time to wrap.
> Such programs have been mentioned earlier in the tread, by someone, in
> direct response to you.
The programmer in question also mentioned that it was for a single
measurement, in a particular case, where he was counting on some
implementation specific behavior. What I would qualify as a hack. And
having investigated further, I'm not sure that he was counting on
integer arithmetic wrapping, although he may not have been aware of the
fact.
It's a misuse of the function.
> I might add that of course I've seen this in others' code, and also
> used it myself.
In production code?
> And earlier a number of references to recommended usage of clock() was
> listed, and it would surprise me greatly if only I, people I know and
> have known, and those participating in this thread, do it the
> recommended way.
The references which you cited do NOT recommend counting on integral
arithmetic wrapping. My impression is that you have misunderstood the
references.
> > I won't say that you cannot invent programs which do count on some
> > specific behavior in the case of overflow. But such programs don't
> > exist in real life -- in every real case of overflow I've seen, it
> > has been a program error, and it would have been better to abort the
> > program immediately.
> > > As long the tick count is representable an overflow can occur as
> > > much as it wants, and it does occur.
> > Except that if overflow can occur, you have to deal with the case
> > that the tick count might not be representable.
> You either have to deal with that in _any_ case, or know that the code
> will never exceed the representable time.
That's exactly what I've been saying. And the only way to know that the
code will never exceed the representable time is if the program
terminates before the representable time has been exceeded. In
practice, I don't use clock() in programs that run over about ten
minutes. And if the program runs longer, I presume that the results are
not reliable, and modify the program to shorten the time it runs.
> Here's one scenario: I want an event-loop to time out after a certain
> interval. The in-practice code might go like this:
> clock_t const startTime = std::clock();
> while( doEvents() )
> {
> double const elapsedTime = std::clock() - startTime;
> if( elapsedTime < 0 || elapsedTime > maxTime ) { break; }
> sleepMilliseconds( 100 );
> }
> The check for <0 detects a non-representable interval under the
> assumptions that doEvents() + 100 msec is representable and that
> signed arithmetic is two's complement with wraparound.
I'll just say that I've never heard of timing out on an undefined unit
of time. I'll suppose that you forgot a division by CLOCKS_PER_SEC in
there somewhere. But you've also forgotten that the standard doesn't
really say what clock() measures, and that IN PRACTICE, this varies from
one system to the next. For timeout's, I'll stick to time(), or some
system specific more precise equivalent.
> To be standard-conforming the code should also check whether clock()
> returns a negative value, but if the implementation unlike common
> implementations today followed the standard, the code would have
> little point and clock() would be of little practical utility.
For such a use, clock() is of little practical utility. Clock() is
designed for profiling and benchmarking, not for timeout's. If you are
using for timeouts, you haven't understood the restrictions of the
function.
> > > But the overflow doesn't affect anything. The recommended way of
> > > using clock() still produces the correct answer (and that's why it
> > > is the recommended way).
> > The reason that it is the recommended way is because it is the only
> > way to obtain the correct answer, even without overflow.
> That is incorrect because with a clock() that returns -1 on overflow,
> as per the C standard, the recommended usage produces an _incorrect_
> answer when there is overflow.
The recommended usage isn't designed to prevent errors in cases where
clock() is not the appropriate function. It is designed to give correct
results when clock() is the appropriate function. It is the only
correct way to use clock, but it is only correct in the absense of
overflow.
> It only produces a correct answer when there is no possibility of
> overflow, OR when the overflow is signed integer wraparound and the
> result is representable by clock_t.
It only produces a correct answer when there is no possibility of
overflow. Period.
> It would be easy to insert a check for negative number, but that check
> isn't there: presumably for good reason.
Because normally, programs using clock() don't run long enough for it to
be necessary.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Tue, 14 Sep 2004 20:06:17 GMT Raw View
I'm removing most of the article I'm responding to because.
* kanze@gabi-soft.fr:
> * alfps@start.no (Alf P. Steinbach) wrote in message
>
> > "If there is overflow, regardless of how it is handled by the system,
> > the results are wrong" is incorrect because it has been shown
> > repeatedly that the common way of handling overflow does yield the
> > correct result when the result is representable by clock_t --
> > regardless of when the measurement is made.
>
> You claim to have shown it.
I claim that I and others have shown it in this very thread.
Here it is, yet again: assume n-bit signed integer clock_t, further
assume 2's complement wrapping behavior (as is the case on all machines I know
are in use today). Let call 1 of clock() return a result A in the inclusive
range 0 through 2^(n-1)-1, which comprises all non-negative numbers in the
range of clock_t, and thus all possible values for a forward time interval.
Let the elapsed tick count before call 2 be k, where k is representable by
clock_t, i.e. in the inclusive range 0 through 2^(n-1)-1. If k = 0 then call
2 returns B = A and then B-A = 0 is correct. If k>0 then call 2 returns
B = A + k - 2^n (by definition of 2's complement), and B-A = k - 2^n which
is congruent to k modulo 2^n, hence the value obtained will be k, correct.
Second case, let result A be in the inclusive range -(2^(n-1)) through -1.
Let k as before. Then B = A + k, and then B - A = k, correct.
This covers all possible cases where the time k to be measured is
representable by clock_t.
QED.
> You show one or two exceptional cases where it happens to work.
I'm a great fan of simple-to-understand concrete examples, but I have also
given the general explanation repeated above (in a shorter form), resorting to
the simple examples when it seemed the general form was not understood.
> You miss completely the essential point: you don't
> know that you can count on the results. Code which counts on this today
> is simply incorrect. According to the standard, and according to all
> the documentation I can find concerning concrete implementations. It
> may work sometime, but that doesn't make the code any more correct.
Most of the text after the ":" is correct wrt. to the C standard.
> Your argument is that the standard should be changed to make it
> correct.
Nope.
I'm not arguing anything on the basis of the behavior of clock().
You _asked_ for an example of commonly used signed integer wraparound, and I
gave it.
The reason we want the behavior standardized isn't that it's very common to
rely on it, nor that it would automatically "fix" clock() -- it wouldn't.
We want the wrapping behavior for signed ints standardized so that it _can_ be
relied on, both for applications where it's used to _ignore_ overflow, and for
applications where it's used to _detect_ overflow -- and it would be a case
of standardizing existing practice, with no known counter-examples.
[...]
> The point is that no programmer in his right mind knowing writes code
> today which counts on signed arithmetic wrapping.
Well, if true that would mean that there's a lot of insane programmers around,
and that standardization of the behavior could _increase_ that percentage!
However, I'm not sure if I'm convinced by that.
On reflection, no, I don't think so.
> The point is that when signed arithmetic overflows, it is a
> programming error
Nor am I convinced by this assertion.
> And that implementations should be allowed to catch that error.
That is something that can be fruitfully discussed (note that common
implementations do not give error-signaling functionality today), and I think
that's just about where we started, no?
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kmarkw65@yahoo.com (Mark Williams)
Date: Sat, 11 Sep 2004 04:19:34 GMT Raw View
kanze@gabi-soft.fr wrote in message news:<d6652001.0409030154.1c68db9f@posting.google.com>...
> case of multiplication. (Of course, integral division can never
> overflow.)
INT_MIN/-1 is allowed to overflow (and does on most C++
implementations).
Which incidentally, is why the original code to test whether a*b
overflows is way too simple.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.fr
Date: Sat, 11 Sep 2004 04:20:55 GMT Raw View
kuyper@wizard.net (James Kuyper) wrote in message
news:<8b42afac.0409081923.4ddb5be2@posting.google.com>...
> kanze@gabi-soft.fr wrote in message
> news:<d6652001.0409080708.2fec56ce@posting.google.com>...
> > kuyper@wizard.net (James Kuyper) wrote in message
> > news:<8b42afac.0409021851.2ea6f4f5@posting.google.com>...
> > > kanze@gabi-soft.fr wrote in message
> > > news:<d6652001.0409020256.6d0c079c@posting.google.com>...
> > > > kuyper@wizard.net (James Kuyper) wrote in message
> > > > news:<8b42afac.0409010444.23a87c64@posting.google.com>...
> ..
[...]
> > How is using clock() after it might have wrapped any different than
> > using a typical Unix 32 bit time_t, but setting the epoch to Jan. 1,
> > 1900?
> I'm not sure what Unix guarantees about time_t.
Unix (Posix) *guarantees* no more than what the C standard guarantees.
Traditionally (and market preasure) say that it will be an integral
type, containing the number of seconds since midnight GMT, Jan. 1, 1970.
> If it guarantees that a time_t number is a linear function of the time
> value that it represents, and that time_t overflows by wrapping, then
> precisely the same technique can be used with time_t.
Then it might be useful for dates after 2038. In practice, the general
philosophy seems to be that we should have moved to a 64 bit time_t long
before then. That puts the cut-off date far enough in the future that
I'm not going to worry about it.
I've never seen a program which tried to use time_t for anything but
"nearby" times. Most programs concerned with times more than a month or
so before or after the current time don't need the precision of a
second, and so use some representation of a date (without time
information). Some recent proposals have also involved a unified Julian
datetime, expressed in milliseconds on a 64 bit value.
[...]
> The fact that the standard doesn't define the results of signed
> integer overflow makes it non-portable code. Oddly enough, most of my
> timing measurements are intended to cover a particular platform, so
> portability isn't an issue.
> The issue under discussion is whether the standard should define the
> behavior of signed integer overflow. If it did, this code would be
> portable, except in one detail. The standard never puts a lower limit
> on the amount of time any statement takes to execute. Therefore,
> there's no portable way to make sure that a time interval you're
> measuring is small enough enough to fit in a clock_t. However, that
> issue applies to all uses of clock(). There's no guarantee in the
> standard that "clock()-clock()" won't involve overflow, even if it's
> the very first and only statement in the program.
The issue under discussion really concerns the advantages of 1) leaving
the behavior undefined, 2) defining it to wrap or 3) defining it to
cause an implementation defined signal. The real question is whether it
is worth standardizing for this particular use (which doesn't occur in
production code, as far as I can tell), and in the process banning an
implementation which could be used to detect errors (which I contend is
the usual cause of overflow).
[...]
> > I'll admit that for anything other than simple, low level
> > benchmarks, I use time(), or if that isn't precise enough, system
> > specific routines which are. Mainly because clock() doesn't offer
> > enough guarantees -- it's good for quicky benchmarks, but not for
> > much else.
> Unfortunately, time() measures the wrong quantity. I wanted CPU time,
> not wall clock time.
Which is another way you weren't portable:-). The standard doesn't
really say what clock() actually measures. With VC++, for example, it
measures wall clock time, exactly as does time(). If you want to be
sure of measuring just CPU time, you need something platform specific.
(The standard Unix function for this is times().)
There's an interesting requirement in the C standard: "If the processor
time used is not available OR ITS VALUE CANNOT BE REPRESENTED, the
function shall return the value (clock_t)-1." That would seem to say
that the implementation should return -1 if the value overflows, and not
wrap. That's not the behavior of the function under Solaris, however.
The footnote to the function also says that clock() should be called at
the start of the program. Footnotes aren't normative, of course, but
that would suggest that the author's of the C standard imagined its use
more along the lines that I had always imagined it.
Finally, the documentation (man pages) for clock() under Solaris warn
that the value will wrap after only 2147 seconds; the language used
seems (to me, at least) to suggest that the function shouldn't be used
after this.
The whole issue bothers me some. Generally speaking, I like to have a
large margin with regards to the limits. If my application requires
that a variable hold values up to 10000, I won't use short, nor int on a
16 bit machine. The variable is large enough, but it's been my
experience that if the application needs 10000 today, it will need 20000
tomorrow, and possibly 50000 a week from now. If I'm within a factor of
10, I worry about it. In this case, however, some of the benchmarks
where I use clock() run for up to 10 minutes. And that doesn't give me
much margin compared to 36 minutes.
One last remark concerning your use of clock(). If you accept that
clock() can wrap, it can also return -1. How do you distinguish this
case from an error?
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Sun, 12 Sep 2004 00:02:44 GMT Raw View
* kanze@gabi-soft.fr:
>
> These functions return -1 in case of error. If you accept that they can
> overflow, and that the value in such cases is significant, then -1 is a
> possible value, and it cannot be used as an error value. That, if
> nothing else, would seem an absolute proof that they are not intented to
> be used with overflow.
I think that is likely to be true (although we do not _know_ intentions)
with respect to those who penned this part of the C standard.
But does their (presumed) intention, sensible or not, affect anything?
If clock() were implemented somewhere as returning -1 in some situation
then the subtraction in the recommended usage would still be UB for the
case of INT_MAX - (-1).
> There's also a history concerning integer overflow. The reason it is
> undefined behavior is because it has always been considered a
> programming error. Always.
The specific case under discussion is one counter-example.
But that is rather general and abstract.
Consider then, those participating in this thread that do not consider it
an error in and of itself: so many counter-examples are not logically needed
to refute "always" but perhaps it helps to have more than one counter-example.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Sun, 12 Sep 2004 00:03:24 GMT Raw View
In article <d6652001.0409100427.71a557d3@posting.google.com>,
kanze@gabi-soft.fr writes
>One last remark concerning your use of clock(). If you accept that
>clock() can wrap, it can also return -1. How do you distinguish this
>case from an error?
clock_t is only required to be an arithmetic type. What -1 is when cast
to clock_t entirely depends on which type is selected by the
implementation. The cast is well-defined for all types.
However undefined behaviour on overflow is not an option for unsigned
integer types, though it is for all other arithmetic types. In the case
of floating point types overflow problems are only a theoretical issue
because your computer will be dust long before overflow occurs. That is
not the case for signed integer types.
Perhaps we should be raising a DR with WG14 because the current
requirements on clock() are impractical to implement using any standard
integer type if the tick rate is sufficiently small.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.fr
Date: Wed, 8 Sep 2004 18:05:13 GMT Raw View
alfps@start.no (Alf P. Steinbach) wrote in message
news:<413775ff.432037703@news.individual.net>...
> * kanze@gabi-soft.fr:
> > kuyper@wizard.net (James Kuyper) wrote in message
> > news:<8b42afac.0409010444.23a87c64@posting.google.com>...
> > > kanze@gabi-soft.fr wrote in message
> > > news:<d6652001.0408310441.66f7d105@posting.google.com>
> > > ..
> > > > Which recommendations? The only thing I can remember seeing was
> > > > an example of the typical use of clock() -- you take the
> > > > starting time, the ending time, and the difference. These
> > > > recommendations have nothing to do with whether the clock_t has
> > > > some defined behavior on overflow.
> > > The difference can overflow. The recommended code produces the
> > > correct result even if it does, as long as overflow wraps around,
> > > and as long as clock() has wrapped around no more than once since
> > > the first call.
> > Does it? On my machine, if the difference overflows, the results
> > are a generally a negative number. That's not what I'd call a
> > correct result.
> Are you using an implementation where 'clock_t' is 'double', so that
> this factual tidbit is irrelevant?
I'm using Sun CC under Solaris, on a Sparc. Where clock_t is a typedef
for long.
> If not, have you checked that this statement is a true statement of
> what actually happens?
Yes. Try it yourself, on any Posix conformant 32 bit machine. Call
clock(). Let the program run for, say, 40 minutes, so that you have
overflow. Call clock() again, and check the difference.
> If it is, then I (and I gather, many others also!) would be interested
> in more details about machine and implementation, e.g., is it 1's
> complement?
> > If the actual difference is not representable in a clock_t, e.g. if
> > it is greater than about 35 minutes on my machine
> Not 'double', then, I think.
> > then the example code will not give the correct results. It cannot,
> > regardless of what other assumptions hold.
> Correct, that's what the other James K. and earlier I wrote.
So where's the argument? If the results cannot be correct, then they
aren't correct.
> > In practice, this means that you can use clock()
> > reliably for about the first 35 minutes of program execution
> > -- after than, the results are meaningless.
> Incorrect.
> > Do you know of any reasonable applications of clock() where you
> > would want to use it beyond the first 35 minutes?
> For example, terminating a loop after a certain elapsed time.
You mean, with alarm(). As far as I know, alarm() doesn't depend on
clock.
> Or timing a certain piece of code and logging results.
That's the only use I've seen for clock. And in order for it to be
valid, the program doing the timing has to run less than that maximum
time that clock() can time. Otherwise, you don't really know the
answer.
Or are you suggesting that you use clock for obtaining the low order
bits (more or less), and time for the high order bits?
> Or whatever (there does not even have to be a reason).
Well, if you are arguing that the behavior should be defined in the
standard, there should be some reason. The reason I argue that the only
acceptable defined behavior is an implementation defined signal is
because all of the cases of overflow I have seen have been due to
programming errors. Unless there are serious and important uses for
some other behavior, this would seem to be the only reasonable one to
impose.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Wed, 8 Sep 2004 18:05:54 GMT Raw View
In article <d6652001.0409080650.75e6a3c6@posting.google.com>,
kanze@gabi-soft.fr writes
>No it isn't. You seem to be stubornly missing the point. The results
>are well defined only in the absense of overflow. If overflow occurs,
>they may be correct, some of the time, on some machines, but you have no
>way of knowing when they are correct, and when they are not.
Because we decided that integer overflow results in undefined behaviour.
We had, and still have a choice. Integer overflow is not inherently
undefined behaviour (as is demonstrated by our decision to define the
behaviour for unsigned integer overflow). It is a cost/benefit decision,
one that seems motivated in this case by portability (because the cost
depends on the representation of negative values). What the clock() and
time() examples show is that part of the cost is making these functions
have little utility.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.fr
Date: Wed, 8 Sep 2004 18:21:29 GMT Raw View
kuyper@wizard.net (James Kuyper) wrote in message
news:<8b42afac.0409021851.2ea6f4f5@posting.google.com>...
> kanze@gabi-soft.fr wrote in message
> news:<d6652001.0409020256.6d0c079c@posting.google.com>...
> > kuyper@wizard.net (James Kuyper) wrote in message
> > news:<8b42afac.0409010444.23a87c64@posting.google.com>...
> ..
> > > The difference can overflow. The recommended code produces the
> > > correct result even if it does, as long as overflow wraps around,
> > > and as long as clock() has wrapped around no more than once since
> > > the first call.
> > Does it? On my machine, if the difference overflows, the results
> > are a generally a negative number. That's not what I'd call a
> > correct result.
> The situations where the overflowing difference is negative involve a
> total time between the two clock() calls that is too large to be
> represented in clock_t.
Quite. Of course, just because the result is too large to be
represented in a clock_t doesn't guarantee a negative result. In fact,
once a program has run long enough for overflow to have occured, you
have no reliable way to distinguish when and if it has occured. Even
plausible results may be false. In sum, the function becomes unsable.
Note that this is a property of almost all non-periodic functions. On a
lot of machines (including mine), the results of time() also become
unusable after the program has run for a certain time (about 68 years).
In fact, they may become unusable far sooner, since the "clock" used
doesn't start at 0 when I start the program.
How is using clock() after it might have wrapped any different than
using a typical Unix 32 bit time_t, but setting the epoch to Jan. 1,
1900?
> If the time between those two calls is small enough to be represented,
> then the recommended code calculates a positive difference, and the
> correct one, even if the clock overflowed between the two calls.
> Consider, to keep the numbers small, a system with
> #define INT_MAX 32767
> #define INT_MIN (-32767-1)
> typedef int clock_t
> Think about the case where the first call to clock() occurs after
> 30000 clock ticks, and the second one occurs after 40000 clock ticks.
> Then start==30000 and end==-25536. In this case, (end-start) is
> mathematically -55536, which overflows clock_t. If the overflow wraps
> around, it will give the correct answer: 10000. The recommended code
> depends upon that behavior, and fails if overflow is handled by one of
> the other suggested mechanisms.
I know what happens. I understand the basics of 2's complement
arithmetic. But do you consider this correct code? Do you know of any
serious, robust applications which count on it? (I guess that's a
loaded question, since IMHO, if an application counts on such things, it
is by definition not robust. Or serious.)
> > Do you know of any reasonable applications of clock() where you
> > would want to use it beyond the first 35 minutes? The only ones I
> > can think of would also require my being able to successfully and
> > correctly obtain a difference of more than 35 minutes. And they
> > don't work on my machine, despite the fact that signed overflow
> > wraps.
> I know of applications where it would be unreasonable only because it
> wouldn't work, not because I didn't have a need for it to work.
OK. I can accept that.
> I had a program that took two hours to reach the point I was
> interested in. After reaching that point, I wanted timing information
> on a piece of code that in itself took much less than 35 minutes to
> run.
That's interesting. I find it hard to conceive of such a thing -- do
you mean you had a benchmark which took two hours to set up?
I'll admit that for anything other than simple, low level benchmarks, I
use time(), or if that isn't precise enough, system specific routines
which are. Mainly because clock() doesn't offer enough guarantees --
it's good for quicky benchmarks, but not for much else.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.fr
Date: Wed, 8 Sep 2004 18:22:05 GMT Raw View
Francis Glassborow <francis@robinton.demon.co.uk> wrote in message
news:<m5GGweENtuOBFwJB@robinton.demon.co.uk>...
> However that would be to miss the point which is that the original
> standardisers of C actually did not think that signed integer overflow
> would normally do anything bad (had they done so, the limitations
> applied to various standard typedefs would have to have been written
> differently).
What makes you think that? Allowing undefined behavior would seem to me
a means of saying that you are explicitly allowing core dumps and the
like. (In fact, the C standard is even clearer about it -- an
implementation defined signal is *explicitly* one of the possibilities
when casting to a smaller type. So apparently some people on the C
standards committee don't agree with your interpretation.)
I think that the original standardizers of C actually thought that
signed integer overflow didn't occur in correct programs, so it was
acceptable to leave it as undefined behavior -- any requirements would
have caused extra overhead on some machines.
This is, as far as I can tell, a general philosophy in C. If checking
for an error condition involves added overhead, leave the behavior
undefined, so that programmers who don't write code with the error don't
pay for the checking they don't need. Trust the programmer, in sum.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net (James Kuyper)
Date: Thu, 9 Sep 2004 06:34:38 GMT Raw View
kanze@gabi-soft.fr wrote in message news:<d6652001.0409080658.45ae087a@posting.google.com>...
> alfps@start.no (Alf P. Steinbach) wrote in message
> news:<413775ff.432037703@news.individual.net>...
> > * kanze@gabi-soft.fr:
..
> > > then the example code will not give the correct results. It cannot,
> > > regardless of what other assumptions hold.
>
> > Correct, that's what the other James K. and earlier I wrote.
>
> So where's the argument? If the results cannot be correct, then they
> aren't correct.
I think I'll need to define some quantities to clarify the issue.
We're concerned with two calls to clock(). Let t0 and t1 represent the
time values that would have been returned by those calls if clock_t
had infinite range, so overflow would not be problem. Let x0 and x1
represent the values actually returned.
We have argued that if (t1-t0) is small enough to be represented in a
clock_t, then on machines where clock_t overflows by wrapping around,
(x1-x0) gives the same value that (t1-t0) would have given, and that
it doesn't matter how large t0 and t1 are.
If I understand you correctly, you seem to be arguing that, even on
such machines, (x1-x0) doesn't give a meaningful result if t1 is too
large to be represented in clock_t, no matter how small t1-t0 is.
> > > Do you know of any reasonable applications of clock() where you
> > > would want to use it beyond the first 35 minutes?
>
> > For example, terminating a loop after a certain elapsed time.
>
> You mean, with alarm(). As far as I know, alarm() doesn't depend on
> clock.
No - by making repeated calls to clock() until the desired amount of
CPU time is found to have elapsed.
> > Or timing a certain piece of code and logging results.
>
> That's the only use I've seen for clock. And in order for it to be
> valid, the program doing the timing has to run less than that maximum
> time that clock() can time. Otherwise, you don't really know the
> answer.
You can know the answer if the time you are measuring is small enough
to fit in clock_t, regardless of how long it is after the start of the
program, before you start measuring it.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net (James Kuyper)
Date: Thu, 9 Sep 2004 06:34:42 GMT Raw View
kanze@gabi-soft.fr wrote in message news:<d6652001.0409080650.75e6a3c6@posting.google.com>...
> alfps@start.no (Alf P. Steinbach) wrote in message
> news:<41391287.72776296@news.individual.net>...
> > * kanze@gabi-soft.fr:
> > > If there is overflow, regardless of how it is handled by the system,
> > > the results are wrong.
>
> > That is incorrect.
>
> No it isn't. You seem to be stubornly missing the point. The results
> are well defined only in the absense of overflow. If overflow occurs,
> they may be correct, some of the time, on some machines, but you have no
> way of knowing when they are correct, and when they are not.
>
> For all practical purposes, there is a limited interval of time in which
> you can use clock().
You can't use clock to reliably measure time periods that are too long
to fit in clock_t. However, if integer overflow wraps on a a given
platform, the recommended way of using clock() produces the right
result, up to that limit, no matter when it's used.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: rtw@freenet.co.uk (Rob Williscroft)
Date: Thu, 9 Sep 2004 15:27:51 GMT Raw View
James Kuyper wrote in
news:8b42afac.0409081926.e2d3a05@posting.google.com in comp.std.c++:
>> For all practical purposes, there is a limited interval of time in
>> which you can use clock().
>
> You can't use clock to reliably measure time periods that are too long
> to fit in clock_t. However, if integer overflow wraps on a a given
> platform, the recommended way of using clock() produces the right
> result, up to that limit, no matter when it's used.
>From the C Draft (couldn't find an affordable PDF):
1 #include <time.h>
clock_t clock(void);
Description
2 The clock function determines the processor time used.
Returns
3 The clock function returns the implementation s best approximation
to the processor time used by the program since the beginning of an
implementation-defined era related only to the program invocation.
To determine the time in seconds, the value returned by the clock
function should be divided by the value of the macro CLOCKS_PER_SEC.
If the processor time used is not available or its value cannot be
represented, the function returns the value (clock_t)-1.
As I read that the *function* return's (clock_t)-1 on overflow:
#include <limits>
#include <utility>
#include <ctime>
std::pair< double, bool >
elapsed_seconds( std::clock_t start, std::clock_t end )
{
std::pair< double, bool > nrv( -1, false );
static std::clock_t const dead = -1;
if ( start == dead ) return nrv;
if ( end == dead )
{
nrv.first = std::numeric_limits< std::clock_t >::max();
}
else
{
nrv.first = end;
nrv.second = true;
}
nrv.first -= start;
nrv.first /= CLOCKS_PER_SEC;
return nrv;
}
Unfortunatly I can't test this as on my machine clock() will
take 25 days to overflow (though I have 1 implementation
where it's 68 years).
I did check one implementation's source though and it dosen't
check for overflow, but who cares 24 days is long enough :).
Rob.
--
http://www.victim-prime.dsl.pipex.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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Thu, 9 Sep 2004 19:41:19 GMT Raw View
In article <d6652001.0409080716.3a05589f@posting.google.com>,
kanze@gabi-soft.fr writes
>Francis Glassborow <francis@robinton.demon.co.uk> wrote in message
>news:<m5GGweENtuOBFwJB@robinton.demon.co.uk>...
>
>> However that would be to miss the point which is that the original
>> standardisers of C actually did not think that signed integer overflow
>> would normally do anything bad (had they done so, the limitations
>> applied to various standard typedefs would have to have been written
>> differently).
>
>What makes you think that?
Because in the case of clock_t and time_t they could have required that
these not be typedefs for signed integer types and thereby avoided much
of the problem.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net (James Kuyper)
Date: Thu, 9 Sep 2004 19:41:39 GMT Raw View
kanze@gabi-soft.fr wrote in message news:<d6652001.0409080708.2fec56ce@posting.google.com>...
> kuyper@wizard.net (James Kuyper) wrote in message
> news:<8b42afac.0409021851.2ea6f4f5@posting.google.com>...
> > kanze@gabi-soft.fr wrote in message
> > news:<d6652001.0409020256.6d0c079c@posting.google.com>...
> > > kuyper@wizard.net (James Kuyper) wrote in message
> > > news:<8b42afac.0409010444.23a87c64@posting.google.com>...
> ..
> > > > The difference can overflow. The recommended code produces the
> > > > correct result even if it does, as long as overflow wraps around,
> > > > and as long as clock() has wrapped around no more than once since
> > > > the first call.
>
> > > Does it? On my machine, if the difference overflows, the results
> > > are a generally a negative number. That's not what I'd call a
> > > correct result.
>
> > The situations where the overflowing difference is negative involve a
> > total time between the two clock() calls that is too large to be
> > represented in clock_t.
>
> Quite. Of course, just because the result is too large to be
> represented in a clock_t doesn't guarantee a negative result. In fact,
> once a program has run long enough for overflow to have occured, you
> have no reliable way to distinguish when and if it has occured.
Sure there is: call clock() repeatedly. When the value jumps from a
large positive number to a large negative number, at least one
overflow has occurred between those two calls. If you can be sure that
your sampling interval is much smaller than the overflow time, you can
be sure that there's exactly one overflow in that time interval.
> ... Even
> plausible results may be false. In sum, the function becomes unsable.
As long as you have other reasons to believe that the time interval
you're measuring is small enough to fit in a clock_t, you can measure
it by taking the difference of two consecutive calls to clock(),
regardless of whether the clock() counter overflows before, during, or
after the measurement. All that's required to insure this is that
clock_t must overflow by wrapping around.
> Note that this is a property of almost all non-periodic functions. On a
> lot of machines (including mine), the results of time() also become
> unusable after the program has run for a certain time (about 68 years).
> In fact, they may become unusable far sooner, since the "clock" used
> doesn't start at 0 when I start the program.
>
> How is using clock() after it might have wrapped any different than
> using a typical Unix 32 bit time_t, but setting the epoch to Jan. 1,
> 1900?
I'm not sure what Unix guarantees about time_t. If it guarantees that
a time_t number is a linear function of the time value that it
represents, and that time_t overflows by wrapping, then precisely the
same technique can be used with time_t. It will give accurate results
for any time interval small enough to be represented by time_t,
regardless of when the starting and ending times are.
> > If the time between those two calls is small enough to be represented,
> > then the recommended code calculates a positive difference, and the
> > correct one, even if the clock overflowed between the two calls.
>
> > Consider, to keep the numbers small, a system with
>
> > #define INT_MAX 32767
> > #define INT_MIN (-32767-1)
> > typedef int clock_t
>
> > Think about the case where the first call to clock() occurs after
> > 30000 clock ticks, and the second one occurs after 40000 clock ticks.
> > Then start==30000 and end==-25536. In this case, (end-start) is
> > mathematically -55536, which overflows clock_t. If the overflow wraps
> > around, it will give the correct answer: 10000. The recommended code
> > depends upon that behavior, and fails if overflow is handled by one of
> > the other suggested mechanisms.
>
> I know what happens. I understand the basics of 2's complement
> arithmetic. But do you consider this correct code? Do you know of any
> serious, robust applications which count on it? (I guess that's a
> loaded question, since IMHO, if an application counts on such things, it
> is by definition not robust. Or serious.)
The fact that the standard doesn't define the results of signed
integer overflow makes it non-portable code. Oddly enough, most of my
timing measurements are intended to cover a particular platform, so
portability isn't an issue.
The issue under discussion is whether the standard should define the
behavior of signed integer overflow. If it did, this code would be
portable, except in one detail. The standard never puts a lower limit
on the amount of time any statement takes to execute. Therefore,
there's no portable way to make sure that a time interval you're
measuring is small enough enough to fit in a clock_t. However, that
issue applies to all uses of clock(). There's no guarantee in the
standard that "clock()-clock()" won't involve overflow, even if it's
the very first and only statement in the program.
> > I had a program that took two hours to reach the point I was
> > interested in. After reaching that point, I wanted timing information
> > on a piece of code that in itself took much less than 35 minutes to
> > run.
>
> That's interesting. I find it hard to conceive of such a thing -- do
> you mean you had a benchmark which took two hours to set up?
I could have written special test code to set up the situation faster,
but then I couldn't have been sure the timing measurements were
meaningful, since it would no longer be the same program as the one I
wanted to take measurements of. In priciple, inserting the clock()
statements themselves made it a different program, but it's possible
to keep the effects of such insertions fairly small.
I knew that the situation I wanted to get timing information about,
occurred naturally when I ran the unmodified program on a particular
data set, so long as I waited until it reached a particular point in
that data set. It didn't reach that point until two hours into the
run.
> I'll admit that for anything other than simple, low level benchmarks, I
> use time(), or if that isn't precise enough, system specific routines
> which are. Mainly because clock() doesn't offer enough guarantees --
> it's good for quicky benchmarks, but not for much else.
Unfortunately, time() measures the wrong quantity. I wanted CPU time,
not wall clock time.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.fr
Date: Fri, 10 Sep 2004 19:39:40 GMT Raw View
francis@robinton.demon.co.uk (Francis Glassborow) wrote in message
news:<jOW396BLx4PBFwiu@robinton.demon.co.uk>...
> In article <d6652001.0409080716.3a05589f@posting.google.com>,
> kanze@gabi-soft.fr writes
> >Francis Glassborow <francis@robinton.demon.co.uk> wrote in message
> >news:<m5GGweENtuOBFwJB@robinton.demon.co.uk>...
> >> However that would be to miss the point which is that the original
> >> standardisers of C actually did not think that signed integer
> >> overflow would normally do anything bad (had they done so, the
> >> limitations applied to various standard typedefs would have to have
> >> been written differently).
> >What makes you think that?
> Because in the case of clock_t and time_t they could have required that
> these not be typedefs for signed integer types and thereby avoided much
> of the problem.
How does that avoid the problem? The problem is present as long as the
interval which can be represented is finite. Using an unsigned type,
rather than a signed type, only doubles the interval -- it doesn't
otherwise make a significant difference.
Traditionally, on Unix machines (which is where this all started),
time_t was a signed long. Way back then, this didn't cause any
problems -- it was never the intent that time_t could represent
arbitrary dates.
The (C) standard requires clock() to return (clock_t)-1 on overflow.
None of the implementations I know respect this requirement, but that
doesn't seem to bother anyone. Sun warns in its man pages that the
results of clock() are only good for about 36 minutes. A footnote in
the C standard says clearly that the correct way of using clock() is to
call it AT THE START OF THE PROGRAM. And so on. There's a long history
concerning these functions.
These functions return -1 in case of error. If you accept that they can
overflow, and that the value in such cases is significant, then -1 is a
possible value, and it cannot be used as an error value. That, if
nothing else, would seem an absolute proof that they are not intented to
be used with overflow.
There's also a history concerning integer overflow. The reason it is
undefined behavior is because it has always been considered a
programming error. Always. How have other languages defined it, when
they haven't left it undefined? Always either an exception or a trap
(e.g. Ada), or to switch to some sort of big integer, so that the
results are correct (some Lisps, I believe).
In the case of C, it was recognized that requiring a signal would be
expensive on many architectures, and that correct programs would never
see that signal, and so pay for something they didn't use. The decision
was to leave it undefined; the intent was that you get what the hardware
gives you. And that generating a signal or some sort of hardware trap
should be legal.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Thu, 2 Sep 2004 20:17:55 GMT Raw View
* kanze@gabi-soft.fr:
> kuyper@wizard.net (James Kuyper) wrote in message
> news:<8b42afac.0409010444.23a87c64@posting.google.com>...
> > kanze@gabi-soft.fr wrote in message
> > news:<d6652001.0408310441.66f7d105@posting.google.com>
> > ..
> > > Which recommendations? The only thing I can remember seeing was an
> > > example of the typical use of clock() -- you take the starting time,
> > > the ending time, and the difference. These recommendations have
> > > nothing to do with whether the clock_t has some defined behavior on
> > > overflow.
>
> > The difference can overflow. The recommended code produces the correct
> > result even if it does, as long as overflow wraps around, and as long
> > as clock() has wrapped around no more than once since the first call.
>
> Does it? On my machine, if the difference overflows, the results are a
> generally a negative number. That's not what I'd call a correct result.
Are you using an implementation where 'clock_t' is 'double', so that
this factual tidbit is irrelevant?
If not, have you checked that this statement is a true statement of what
actually happens?
If it is, then I (and I gather, many others also!) would be interested in
more details about machine and implementation, e.g., is it 1's complement?
> If the actual difference is not representable in a clock_t, e.g. if it
> is greater than about 35 minutes on my machine
Not 'double', then, I think.
> then the example code will not give the correct results.
> It cannot, regardless of what other assumptions hold.
Correct, that's what the other James K. and earlier I wrote.
> In practice, this means that you can use clock()
> reliably for about the first 35 minutes of program execution
> -- after than, the results are meaningless.
Incorrect.
> Do you know of any reasonable applications of clock() where you would
> want to use it beyond the first 35 minutes?
For example, terminating a loop after a certain elapsed time.
Or timing a certain piece of code and logging results.
Or whatever (there does not even have to be a reason).
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net (James Kuyper)
Date: Fri, 3 Sep 2004 16:18:57 GMT Raw View
kanze@gabi-soft.fr wrote in message news:<d6652001.0409020256.6d0c079c@posting.google.com>...
> kuyper@wizard.net (James Kuyper) wrote in message
> news:<8b42afac.0409010444.23a87c64@posting.google.com>...
..
> > The difference can overflow. The recommended code produces the correct
> > result even if it does, as long as overflow wraps around, and as long
> > as clock() has wrapped around no more than once since the first call.
>
> Does it? On my machine, if the difference overflows, the results are a
> generally a negative number. That's not what I'd call a correct result.
The situations where the overflowing difference is negative involve a
total time between the two clock() calls that is too large to be
represented in clock_t. If the time between those two calls is small
enough to be represented, then the recommended code calculates a
positive difference, and the correct one, even if the clock overflowed
between the two calls.
Consider, to keep the numbers small, a system with
#define INT_MAX 32767
#define INT_MIN (-32767-1)
typedef int clock_t
Think about the case where the first call to clock() occurs after
30000 clock ticks, and the second one occurs after 40000 clock ticks.
Then start==30000 and end==-25536. In this case, (end-start) is
mathematically -55536, which overflows clock_t. If the overflow wraps
around, it will give the correct answer: 10000. The recommended code
depends upon that behavior, and fails if overflow is handled by one of
the other suggested mechanisms.
> Do you know of any reasonable applications of clock() where you would
> want to use it beyond the first 35 minutes? The only ones I can think
> of would also require my being able to successfully and correctly obtain
> a difference of more than 35 minutes. And they don't work on my
> machine, despite the fact that signed overflow wraps.
I know of applications where it would be unreasonable only because it
wouldn't work, not because I didn't have a need for it to work. I had
a program that took two hours to reach the point I was interested in.
After reaching that point, I wanted timing information on a piece of
code that in itself took much less than 35 minutes to run.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.fr
Date: Thu, 2 Sep 2004 19:07:15 GMT Raw View
alfps@start.no (Alf P. Steinbach) wrote in message
news:<4134eed0.266363484@news.individual.net>...
> * James Kanze:
> > * Alf P. Steinbach:
> > > * James Kanze:
> > > > In practice, on all the implementations I know of, the clock_t
> > > > value starts at 0. So any program which uses clock_t in the
> > > > first couple of minutes doesn't rely on wrapping whatsoever.
> > > > Just as obviously, any program which runs for hours and still
> > > > expects to be able to use the results from clock() reliably is
> > > > broken. But I don't know of any programs which do this -- as I
> > > > said, the only use I've seen of clock() has been for quicky
> > > > benchmarks.
> > > AFAIK there is no guarantee that clock() starts at 0.
> > In general, there's no guarantee that an implementation will be
> > usable. Do you know of any implementations where the clock()
> > doesn't start at 0? (There could be, of course, but I've never seen
> > them.)
> I don't know of any implementation where it does start at 0.
Windows (at least with VC++), Solaris (with both Sun CC and g++). I
rather suspect that it is almost universal, in fact.
> > > And there is no guarantee any measurement starts at process
> > > startup.
> > > The recommendations cited earlier would be meaningless if such
> > > guarantees existed, even just in practice; are you saying these
> > > recommendations are meaningless?
> > Which recommendations?
> As I wrote, "cited earlier".
> Two steps up the thread I gave the <url:
> http://www.cs.utah.edu/dept/old/texinfo/glibc-manual-0.02/library_19.html#SEC311>,
> which is from the GNU library documentation.
> <url:
> http://h30097.www3.hp.com/docs/base_doc/DOCUMENTATION/V50_HTML/ARH9NATE/DOCU_024.HTM>
> gives the same subtraction advice for DEC C, however without casting
> to double.
> <url: http://www.scit.wlv.ac.uk/~jphb/spos/notes/calls/time.html>,
> apparently a college course in Unix programming, gives the same advice
> for unspecified implementations.
> And so on (just search for "clock_t" to find more examples and no
> counter-examples).
It's just that I don't see any relationship between these
"recommendations" and the problem at hand. The recommendations have
nothing to do with the possibility of overflow in the subtraction.
> > The only thing I can remember seeing was an example of the typical
> > use of clock() -- you take the starting time, the ending time, and
> > the difference. These recommendations
> Aha!
> > have nothing to do with whether the clock_t has some defined
> > behavior on overflow.
> Why do you think they don't test for overflow?
Because there is no easy way of doing it, and because in practice, it is
pretty easy to avoid. If there is overflow, regardless of how it is
handled by the system, the results are wrong.
> > As long as the total program run is less than 20 or 30 minutes,
> > there should be no problem.
> Note that one not uncommon usage is to terminate an operation (e.g. an
> event loop) after a certain maximum time. That can happen at any time
> in the program's execution, e.g. an event loop might be invoked to
> display a notification after 2 or 3 hours of program operation...
> Also, this "guaranteed" limit asserted above, is that mentioned at all
> in the C standard or -- to be practical -- in some vendor's
> documentation?
But you don't use clock() for this. You use time(). (If you try to
measure 2 or 3 hours with clock() under Solaris, you'll never get
there. Because of overflow.)
> In short, I find that assertion very much less than convincing.
> Do you agree that _if_ clock() is invoked after the "guaranteed"
> period (which I suspect is not guaranteed anywhere) _then_ following
> the recommendations listed above is to rely on signed integer
> wraparound?
No. Because in the case of overflow, the results are wrong. Even if
signed integers wrap.
There is, as you correctly point out, no "guarantee" anywhere. As I
pointed out, clock_t can theoretically be a 16 bit signed short, with
CLOCKS_PER_SEC 32000 ; trying to measure anything above a second would
be futile. Most implementations try to provide something useful, taking
into account the intended use of clock() (or what they think the
intended use is or should be). The actual semantics do vary greatly,
and there is not really much portable you can do with the function.
(Under Solaris, clock() measures user time, e.g. the amount of time
actually spent executing my code in user state, and is good for about 35
minutes of user time. Under Windows, it measures (from what I've been
told) wall clock time, and is good for over 24 days. I've never
actually verified it on other systems; it's not a function I've ever
used in production code.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.fr
Date: Fri, 3 Sep 2004 17:27:31 GMT Raw View
sk@bez.spamu.z.pl (Sebastian Kaliszewski) wrote in message
news:<ch7h66$sjd$1@bozon2.softax.pl>...
> kanze@gabi-soft.fr wrote:
> > Is it really faster than checking whether y > INT_MAX - x before
> > hand
> This is of course worng (i.e. UB) for x < 0.
I know that the general condition is more complex. My intent was just
to identify the solution I was talking about.
> > (a solution which also works for multiplication and division).
> Same as above, valid only for x >= 0.
The conditions are actually slightly different. You can do the test on
absolut values, but you have to verify that the divisor isn't 0 in the
case of multiplication. (Of course, integral division can never
overflow.)
> > The pre-check obviously requires some verifications with regards to
> > the sign, but I'm not sure that they are expensive enough to
> > outweigh the difference.
> Jump instructions are expensive on todays hardware.
At least one jump instruction is necessary in any case. And with
correct branch prediction, the jump instructions shouldn't be that
expensive.
My only point was that until you've actually tried it and measured the
results, you don't know which is faster. The pre-checking is more
portable, and is the only technique I know that can ever be used for
multiplication. Which is faster is implementation dependent.
It's also what I used when I needed overflow checking. It was fast
enough, in my particular application, on the machine I was using at the
time.
Of course, the real shame is that the hardware almost always has a much
faster and better solution, that we cannot access in any way from C or
C++. (In the one case I needed it, I found that calling subroutines
written in assembler for each atomic operation was actually the fastest
solution. The hardware based solution was fast enough to outweigh the
cost of the subroutine call. But since the pre-checking solution was
fast enough, and we were considering supporting a different hardware
architecture, I stuck with it, rather than use my assembler routines.)
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Sat, 4 Sep 2004 22:56:05 GMT Raw View
* kanze@gabi-soft.fr:
> If there is overflow, regardless of how it is
> handled by the system, the results are wrong.
That is incorrect.
And I think that technical misunderstanding is the cornerstone
of your earlier postings in this sub-thread, so all of them are
now to be disregarded.
Consider clock_t = int for 16 bit two's complement,
first call of clock() giving 32760, and elapsed time in clock ticks
before second call of clock() as 200 ticks, say. If you do this
correctly, as per the recommendations cited earlier, you should obtain the
correct result of 200 ticks. For use of clock() on current machines &
implementations the only requirement is (as has now been stated how many
times?) that the elapsed tick count is is within the range of clock_t.
As long the tick count is representable an overflow can occur as much as it
wants, and it does occur.
But the overflow doesn't affect anything. The recommended way of using
clock() still produces the correct answer (and that's why it is the
recommended way). It does that by relying on signed integer wraparound.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: Mon, 6 Sep 2004 15:23:21 GMT Raw View
In article <41391287.72776296@news.individual.net>, Alf P. Steinbach
<alfps@start.no> writes
>But the overflow doesn't affect anything. The recommended way of using
>clock() still produces the correct answer (and that's why it is the
>recommended way). It does that by relying on signed integer wraparound.
And just in case anyone missed the point, it does so by relying on an
explicit behaviour in the context of undefined behaviour.
Now there are several ways of fixing this problem, one of which is to
apply more constraints to clock_t and time_t.
However that would be to miss the point which is that the original
standardisers of C actually did not think that signed integer overflow
would normally do anything bad (had they done so, the limitations
applied to various standard typedefs would have to have been written
differently).
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.fr
Date: Wed, 8 Sep 2004 15:06:29 GMT Raw View
alfps@start.no (Alf P. Steinbach) wrote in message
news:<41391287.72776296@news.individual.net>...
> * kanze@gabi-soft.fr:
> > If there is overflow, regardless of how it is handled by the system,
> > the results are wrong.
> That is incorrect.
No it isn't. You seem to be stubornly missing the point. The results
are well defined only in the absense of overflow. If overflow occurs,
they may be correct, some of the time, on some machines, but you have no
way of knowing when they are correct, and when they are not.
For all practical purposes, there is a limited interval of time in which
you can use clock(). There is also a limited interval of time in which
you can use time(), as well -- typically, the interval is a bit longer,
of course (although the standard doesn't require it). This is a very
basic result of using finite arithmetic. When you leave this interval,
your results may be incorrect. On the machine I usually work on (Sun
Sparc, Solaris), the interval for clock() is about 35 minutes, starting
at the beginning of the program, and the interval for time() is about 68
years, starting from Jan. 1, 1970. Neither of these limits are really
documented:-), but they are there. Neither really causes any problem
with the intended use of the functions, et least for now. (The limit on
time() will cause some serious problems in a little over 30 years from
now. I can't see the limit on clock() ever causing problems.)
> And I think that technical misunderstanding is the cornerstone of your
> earlier postings in this sub-thread, so all of them are now to be
> disregarded.
> Consider clock_t = int for 16 bit two's complement, first call of
> clock() giving 32760, and elapsed time in clock ticks before second
> call of clock() as 200 ticks, say.
You now have undefined behavior.
In practice, if the first call to clock() returns such a high value,
there is no point in continuing.
> If you do this correctly, as per the recommendations cited earlier,
> you should obtain the correct result of 200 ticks.
For this one particular example. Not necessarily in general.
In general, clock() is good for a certain period of time. Beyond that,
you can't use it. On my system, for example, if the program runs for
less than 35 minutes, I know that calculations based on the return value
of clock() are valid. If it runs for a day or two, I don't know.
> For use of clock() on current machines & implementations the only
> requirement is (as has now been stated how many times?) that the
> elapsed tick count is is within the range of clock_t.
And how do you know it is within the range of clock_t? You know it only
because the total values have never overflowed; because the total
runtime is small enough so that overflow cannot occur.
Do you know of any real programs which count on the difference between
two calls to clock() giving correct results, even though the program has
been running for hours? The *only* programs I know which use clock()
are benchmark harnesses, which call clock() very near the beginning of
the program, and which terminate before it has had the time to wrap.
I won't say that you cannot invent programs which do count on some
specific behavior in the case of overflow. But such programs don't
exist in real life -- in every real case of overflow I've seen, it has
been a program error, and it would have been better to abort the program
immediately.
> As long the tick count is representable an overflow can occur as much
> as it wants, and it does occur.
Except that if overflow can occur, you have to deal with the case that
the tick count might not be representable.
> But the overflow doesn't affect anything. The recommended way of
> using clock() still produces the correct answer (and that's why it is
> the recommended way).
The reason that it is the recommended way is because it is the only way
to obtain the correct answer, even without overflow. Overflow has
nothing to do with the motivation behind the recommendation.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Mon, 30 Aug 2004 20:10:55 GMT Raw View
* James Kanze:
>
> In practice, on all the implementations I know of, the clock_t value
> starts at 0. So any program which uses clock_t in the first couple of
> minutes doesn't rely on wrapping whatsoever. Just as obviously, any
> program which runs for hours and still expects to be able to use the
> results from clock() reliably is broken. But I don't know of any
> programs which do this -- as I said, the only use I've seen of clock()
> has been for quicky benchmarks.
AFAIK there is no guarantee that clock() starts at 0.
And there is no guarantee any measurement starts at process startup.
The recommendations cited earlier would be meaningless if such
guarantees existed, even just in practice; are you saying these
recommendations are meaningless?
> > So as of 2004 _all_ that code is formally incorrect.
>
> Code that uses clock() to measure execution times of hours is not only
> formally incorrect -- the results we be very wrong on many systems.
Well we're talking about measuring minutes, not hours, and the question is,
is code that uses the recommended wrapping subtraction technique broken?
Stated another way, does the C or C++ standard specify the result of
subtraction of clock_t values so that the recommendation (and code that
uses it) relies on this spec, or does it not, so that code that uses
the recommendation relies on knowledge of signed integer wrapping?
I don't have the C standard so I'm not asking a rhetorical question.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.fr
Date: Tue, 31 Aug 2004 21:20:43 GMT Raw View
alfps@start.no (Alf P. Steinbach) wrote in message
news:<41336bfc.167334843@news.individual.net>...
> * James Kanze:
> > In practice, on all the implementations I know of, the clock_t value
> > starts at 0. So any program which uses clock_t in the first couple
> > of minutes doesn't rely on wrapping whatsoever. Just as obviously,
> > any program which runs for hours and still expects to be able to use
> > the results from clock() reliably is broken. But I don't know of
> > any programs which do this -- as I said, the only use I've seen of
> > clock() has been for quicky benchmarks.
> AFAIK there is no guarantee that clock() starts at 0.
In general, there's no guarantee that an implementation will be usable.
Do you know of any implementations where the clock() doesn't start at 0?
(There could be, of course, but I've never seen them.)
> And there is no guarantee any measurement starts at process startup.
> The recommendations cited earlier would be meaningless if such
> guarantees existed, even just in practice; are you saying these
> recommendations are meaningless?
Which recommendations? The only thing I can remember seeing was an
example of the typical use of clock() -- you take the starting time, the
ending time, and the difference. These recommendations have nothing to
do with whether the clock_t has some defined behavior on overflow.
I use clock() in my benchmark code. I follow your example. There is
almost always some start-up code before the benchmark that I don't want
to measure, and I always measure at least two cases in the benchmark --
a first one with an empty function, and a second with a function with
the operation I want to test. The possibility of clock_t overflowing
has nothing to do with it: I know that the total execution time is
fairly short -- a couple of minutes at the most, and I count on clock_t
not overflowing.
But you're right. I should add the test. Because if clock_t does
overflow, the results are undefined.
> > > So as of 2004 _all_ that code is formally incorrect.
> > Code that uses clock() to measure execution times of hours is not
> > only formally incorrect -- the results we be very wrong on many
> > systems.
> Well we're talking about measuring minutes, not hours, and the
> question is, is code that uses the recommended wrapping subtraction
> technique broken?
No. Why should it be? As long as the total program run is less than 20
or 30 minutes, there should be no problem.
In practice, of course. In theory, an implementation could make clock_t
a 16 bit int, with 30000 CLOCKS_PER_SECOND, and always force to zero in
cases of overflow or whatever. Under such an implementation, clock()
would be for all practical purposes unusable, but the standard doesn't
mandate that an implementation be usable.
> Stated another way, does the C or C++ standard specify the result of
> subtraction of clock_t values so that the recommendation (and code
> that uses it) relies on this spec, or does it not, so that code that
> uses the recommendation relies on knowledge of signed integer
> wrapping?
I haven't seen any code yet that relies on signed integer wrapping. All
I've seen is code that relies on the fact that clock_t doesn't overflow
when used as intented. The Unix constraint that it only works for the
first 35 minutes of the program is rather draconian, I'll admit; Windows
is good for up to around 24 days (which is enough for any benchmark I'll
ever run).
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Wed, 1 Sep 2004 03:56:18 GMT Raw View
* James Kanze:
> * Alf P. Steinbach:
> > * James Kanze:
> > > In practice, on all the implementations I know of, the clock_t value
> > > starts at 0. So any program which uses clock_t in the first couple
> > > of minutes doesn't rely on wrapping whatsoever. Just as obviously,
> > > any program which runs for hours and still expects to be able to use
> > > the results from clock() reliably is broken. But I don't know of
> > > any programs which do this -- as I said, the only use I've seen of
> > > clock() has been for quicky benchmarks.
>
> > AFAIK there is no guarantee that clock() starts at 0.
>
> In general, there's no guarantee that an implementation will be usable.
> Do you know of any implementations where the clock() doesn't start at 0?
> (There could be, of course, but I've never seen them.)
I don't know of any implementation where it does start at 0.
> > And there is no guarantee any measurement starts at process startup.
>
> > The recommendations cited earlier would be meaningless if such
> > guarantees existed, even just in practice; are you saying these
> > recommendations are meaningless?
>
> Which recommendations?
As I wrote, "cited earlier".
Two steps up the thread I gave the <url:
http://www.cs.utah.edu/dept/old/texinfo/glibc-manual-0.02/library_19.html#SEC311>,
which is from the GNU library documentation.
<url:
http://h30097.www3.hp.com/docs/base_doc/DOCUMENTATION/V50_HTML/ARH9NATE/DOCU_024.HTM>
gives the same subtraction advice for DEC C, however without casting to
double.
<url: http://www.scit.wlv.ac.uk/~jphb/spos/notes/calls/time.html>,
apparently a college course in Unix programming, gives the same advice for
unspecified implementations.
And so on (just search for "clock_t" to find more examples and no
counter-examples).
> The only thing I can remember seeing was an
> example of the typical use of clock() -- you take the starting time, the
> ending time, and the difference. These recommendations
Aha!
> have nothing to
> do with whether the clock_t has some defined behavior on overflow.
Why do you think they don't test for overflow?
> As long as the total program run is less than 20
> or 30 minutes, there should be no problem.
Note that one not uncommon usage is to terminate an operation (e.g. an event
loop) after a certain maximum time. That can happen at any time in the
program's execution, e.g. an event loop might be invoked to display a
notification after 2 or 3 hours of program operation... Also, this
"guaranteed" limit asserted above, is that mentioned at all in the C
standard or -- to be practical -- in some vendor's documentation?
In short, I find that assertion very much less than convincing.
Do you agree that _if_ clock() is invoked after the "guaranteed" period
(which I suspect is not guaranteed anywhere) _then_ following the
recommendations listed above is to rely on signed integer wraparound?
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net (James Kuyper)
Date: Wed, 1 Sep 2004 16:32:32 GMT Raw View
kanze@gabi-soft.fr wrote in message news:<d6652001.0408310441.66f7d105@posting.google.com>
..
> Which recommendations? The only thing I can remember seeing was an
> example of the typical use of clock() -- you take the starting time, the
> ending time, and the difference. These recommendations have nothing to
> do with whether the clock_t has some defined behavior on overflow.
The difference can overflow. The recommended code produces the correct
result even if it does, as long as overflow wraps around, and as long
as clock() has wrapped around no more than once since the first call.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.fr
Date: Thu, 2 Sep 2004 15:45:05 GMT Raw View
kuyper@wizard.net (James Kuyper) wrote in message
news:<8b42afac.0409010444.23a87c64@posting.google.com>...
> kanze@gabi-soft.fr wrote in message
> news:<d6652001.0408310441.66f7d105@posting.google.com>
> ..
> > Which recommendations? The only thing I can remember seeing was an
> > example of the typical use of clock() -- you take the starting time,
> > the ending time, and the difference. These recommendations have
> > nothing to do with whether the clock_t has some defined behavior on
> > overflow.
> The difference can overflow. The recommended code produces the correct
> result even if it does, as long as overflow wraps around, and as long
> as clock() has wrapped around no more than once since the first call.
Does it? On my machine, if the difference overflows, the results are a
generally a negative number. That's not what I'd call a correct result.
If the actual difference is not representable in a clock_t, e.g. if it
is greater than about 35 minutes on my machine, then the example code
will not give the correct results. It cannot, regardless of what other
assumptions hold. In practice, this means that you can use clock()
reliably for about the first 35 minutes of program execution -- after
than, the results are meaningless.
Do you know of any reasonable applications of clock() where you would
want to use it beyond the first 35 minutes? The only ones I can think
of would also require my being able to successfully and correctly obtain
a difference of more than 35 minutes. And they don't work on my
machine, despite the fact that signed overflow wraps.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: sk@bez.spamu.z.pl (Sebastian Kaliszewski)
Date: Thu, 2 Sep 2004 16:58:43 GMT Raw View
kanze@gabi-soft.fr wrote:
> Is it really faster than checking whether y > INT_MAX - x before hand
This is of course worng (i.e. UB) for x < 0.
> (a
> solution which also works for multiplication and division).
Same as above, valid only for x >= 0.
> The
> pre-check obviously requires some verifications with regards to the
> sign, but I'm not sure that they are expensive enough to outweigh the
> difference.
Jump instructions are expensive on todays hardware.
rgds
Sebastian Kaliszewski
--
"Never underestimate the power of human stupidity" -- from Notebooks of LL
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: petebecker@acm.org (Pete Becker)
Date: Sun, 29 Aug 2004 22:25:50 GMT Raw View
"Alf P. Steinbach" wrote:
>
> * Anders J. Munch -> Francis Glassborow:
> >
> > Someone who wants implementations to help find overflow bugs might be
> > better served by pestering their compiler vendor for better
> > vendor-defined behaviour than proposing changes to C++ the language.
>
> AFAICS no-one here has a problem with overflow bugs, and no-one here
> has been pestering anybody. Especially not Francis. Shame on you.
>
This is the third time that the proponents of this idea have accused
people they disagree with of bad faith without responding to the
technical argument that was presented. That says a great deal about the
technical merits of their position.
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: andersjm@inbound.dk ("Anders J. Munch")
Date: Sun, 29 Aug 2004 23:08:51 GMT Raw View
"Alf P. Steinbach" <alfps@start.no> wrote:
> * Anders J. Munch -> Francis Glassborow:
> >
> > Someone who wants implementations to help find overflow bugs might be
> > better served by pestering their compiler vendor for better
> > vendor-defined behaviour than proposing changes to C++ the language.
>
> AFAICS no-one here has a problem with overflow bugs, and no-one here
> has been pestering anybody. Especially not Francis. Shame on you.
I am baffled at how you managed to read that into my words, but just
for the record, I certainly was not suggesting that Francis, nor
anyone else, was pestering anyone. If anything, we need _more_
submitting-of-feature-requests-to ("pestering") vendors on this issue.
> What we have as de-facto standard is silent wraparound; I think you'll
find
> it extremely difficult to change that, and arguing here won't help.
You're the one who's trying to change things.
> > It would be different if implementors saw
> > it as their job to implement undefined behaviour as the the deliberate
> > execution of random-generated code, but I'm not seeing that happen :)
>
> Is the argument in the last paragraph that this behavior doesn't need to
be
> officially defined because there's an effective de-facto standard?
The argument is that just because something is not specified by the
C++ standard, that is no reason to assume that implementations will do
something stupid.
- Anders
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.fr
Date: Mon, 30 Aug 2004 17:28:15 GMT Raw View
alfps@start.no (Alf P. Steinbach) wrote in message
news:<412fdcbd.451318421@news.individual.net>...
> * James Kanze:
> > * Alf P. Steinbach:
> > > James Kanze:
> > > > Programs with integer overflow are incorrect.
> > > Yes, that's what this discussion is about, that a large part of
> > > existing C++ programs are formally incorrect, while they could
> > > easily be formally correct if only the standard defined the
> > > behavior.
> > Are there? I've never seen a program, C or C++, which counted on
> > any specific behavior in the case of overflow. As far as I can
> > tell, it has been undefined behavior since the very first days of C;
> > the C standards committee actually innovated in defining it for
> > unsigned integral types.
> Hm. Never seen?
> I have given an example earlier, but that was just off-the-cuff. Here
> with some techno details. In
> <url:
> http://www.cs.utah.edu/dept/old/texinfo/glibc-manual-0.02/library_19.html#SEC311>
I don't see where anything there recommends counting on wrapping on
overflow.
> and in numerous other places, the recommended way to use the standard
> clock() function in C (and so with a few adjustments in C++) is given
> as, here quoting literally,
> #include <time.h>
> clock_t start, end;
> double elapsed;
>
> start = clock();
> ... /* Do the work. */
> end = clock();
> elapsed = ((double) (end - start)) / CLOCKS_PER_SEC;
> The return type of clock() is abstract but most often a 'long'
> (otherwise it's typically a 'double'); it must be signed because
> clock() is required to return -1 on error;
The C standard says that the error value is (clock_t)(-1). Presumably
in order to allow unsigned types to be used.
Not that it changes much with regards to your argument.
> and CLOCKS_PER_SEC is often a large number such as 1000000 -- e.g.,
> <url: http://www.hmug.org/man/3/clock.html> states that "Version 2 of
> the Single UNIX Specification (``SUSv2'') requires CLOCKS_PER_SEC to
> be defined as one million".
Interesting. I knew that some implementations use a ridiculously large
number, but I can remember when 60 most the most typical value.
Again, not that that changes anything.
> In <url: http://lists.boost.org/MailArchives/boost-users/msg00242.php>
> someone has calculated, presumably for 32-bit long, that this results
> in an overflow after 36 minutes of continous ticking (clock() doesn't
> need to tick continously since it measures process time, but it's in
> the ballpark).
Which means, of course, that using the clock function to measure times
beyond a couple of minutes, or after the program has been running for
more than a few minutes, isn't reliable.
I don't see any real problem here. I can't recall ever having seen the
function used for anything but benchmarks, in programs that don't run
hours on end.
> So, _all_ code that implements the recommended usage of clock() and
> uses a standard library where 'clock_t' is 'long' relies on signed int
> wrapping, and here I'm not referring only to the overflow in the
> clock() value itself but to the subtraction of the old value from the
> new value.
In practice, on all the implementations I know of, the clock_t value
starts at 0. So any program which uses clock_t in the first couple of
minutes doesn't rely on wrapping whatsoever. Just as obviously, any
program which runs for hours and still expects to be able to use the
results from clock() reliably is broken. But I don't know of any
programs which do this -- as I said, the only use I've seen of clock()
has been for quicky benchmarks.
> So as of 2004 _all_ that code is formally incorrect.
Code that uses clock() to measure execution times of hours is not only
formally incorrect -- the results we be very wrong on many systems.
But as I said, I've never seen code that uses clock() in a program that
runs over a couple of minutes -- ten minutes seems to be about the top.
> And let me ask: is it in your view, as it might seem from the
> statement at top above, and defense of that statement, also
> practically incorrect?
I'm not sure what you are asking is "practically incorrect". In
practice, trying to use clock() to measure execution times of over a
couple minutes will likely encounter wrong answers. And I've never seen
a program that tries to measure execution times after having run for
such a long time, alghough I suppose that some such exist somewhere.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.fr
Date: Mon, 30 Aug 2004 17:28:25 GMT Raw View
qrczak@knm.org.pl ("Marcin 'Qrczak' Kowalczyk") wrote in message
news:<87u0unejqx.fsf@qrnik.zagroda>...
> kanze@gabi-soft.fr writes:
> > Are there? I've never seen a program, C or C++, which counted on any
> > specific behavior in the case of overflow.
> I use it, relying on 2's complement arithmetic, to detect overflow of
> addition and subtraction:
> z = x + y;
> if ((~(x^y) & (z^x)) >= 0)
> // if x and y have different signs, or z and x have same signs
> return z;
> else
> redo the computation on bignums;
> This is the fastest semi-portable way I know.
Is it really faster than checking whether y > INT_MAX - x before hand (a
solution which also works for multiplication and division). The
pre-check obviously requires some verifications with regards to the
sign, but I'm not sure that they are expensive enough to outweigh the
difference.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Thu, 26 Aug 2004 06:28:08 GMT Raw View
* Ben Hutchings:
> Alf P. Steinbach wrote:
> > * John Potter:
> >> On Sat, 21 Aug 2004 17:02:33 GMT, alfps@start.no (Alf P. Steinbach)
> >> wrote:
> >>
> >> > * John Potter:
> >>
> >> > > Define the expected wrong answer
> >>
> >> > Although it follows from earlier: that question seems to be pure rhetoric.
> >>
> >> > An expected _correct_ answer for a*b might be defined as e.g. x such that
> >> > -(2^(n-1)) <= x <= 2^(n-1)-1 and x == a*b (mod 2^n) where n is the number
> >> > of bits in the representation.
> >>
> >> Let a = INT_MAX and b = 2. On my implementation the result is -2 but
> >> the modulo answer is 2*INT_MAX. They are not equal. Is my
> >> implementation broken with respect to your expectations?
> >
> >
> > Your understanding of what "mod m" means mathematically is incorrect.
> >
> > "(mod m)" is not an arithmetic operation that produces a value, like the %-
> > operator in C++ does.
> >
> > The expression 'x = y (mod m)' means exactly x = y + C*m for some integer C.
>
> Then your notation is incorrect, or at least unusual. You are using
> "=" to mean "is congruent to", which is normally denoted by three
> parallel horizontal lines rather than two.
You want me to post in some gobbledegook character set.
Sorry, my old & trusted Free Agent don't handle those.
And I think that's off-topic and anyway, my character set seems to be
perfectly acceptable to everybody else (yours is the first complaint).
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: pfefferd@hotmail.co.il.nospam ("Daniel Pfeffer")
Date: Thu, 26 Aug 2004 19:26:58 GMT Raw View
"Francis Glassborow" <francis@robinton.demon.co.uk> wrote in message
news:UzrqiFOv5GLBFwmr@robinton.demon.co.uk...
> In article <412b4536$0$234$edfadb0f@dread14.news.tele.dk>, Anders J.
> Munch <ajm@flonidan.dk> writes
> >"Alf P. Steinbach" <alfps@start.no> wrote in message
> >news:412504b0.14181406@news.individual.net...
[snip]
> >Defined behaviour is only preferable to undefined behaviour if it is
> >what the programmer intended. UB can be a good thing.
>
> Unlimited undefined behaviour (which is exactly what undefined behaviour
> is in C++) is so extreme that it should only be resorted to when there
> is not other reasonable solution. There is a great deal of difference
> between allowing a program to crash (which might have other undesirable
> consequences) or get a wrong answer (which better not happen if it is
> computing the duration of X-Ray treatment for a cancer patient) and
> literally washing ones hands of making any attempt to specify the
> behaviour of the program itself (which is the consequence of undefined
> behaviour).
>
> Even specifying that the consequence of integer overflow is the
> immediate termination of the program (were we to allow that as
> implementation defined behaviour) would, IMO, be better than what we
> currently have.
Given that integer arithmetic is typically implemented by a CPU instruction,
we have the following CPU behaviours at the minimum:
1. Perform the operation without any error indication. The arithmetically
exact result will be "wrapped around" in some manner to fit into the CPU
register.
2. Do not perform the operation and raise an overflow flag.
3. Perform the operation and raise an overflow flag. The result will be
"wrapped around" in some manner.
4. Do not perform the operation and throw a CPU exception.
5. Perform the operation and throw a CPU exception. The result will be
"wrapped around" in some manner.
The "reasonable" values for wrap around vary between the various CPU
architectures, and depend of wwhether trap representations, etc. exist. An
incomplete list would be:
1. Twos-complement arithmetic.
2. Ones-complement arithmetic.
3. Sign+magnitude arithmetic.
Each of these could have trap representation and no-trap representation
formats.
Reliable detection of overflow in many of the above architectures would
involve changes to compiler implementations as follows:
CPU case 1:
Either the operands must be checked before arithmetic is performed, or the
result must be checked in order to ensure that it "makes sense". The C++
runtime must either throw a C++ exception, or ensure that the result is
correct according to the C++ wrapping rules.
CPU case 2:
The overflow flag must be checked after every operation. As the operation
wasn't performed, the C++ runtime environment will have to decide on an
appropriate action, which IMHO should be to throw a C++ exception.
Alternatively, the C++ runtime could simulate the actions of the appropriate
wrapping rules, depending on the integer representation in the environment.
CPU case 3:
The overflow flag must be checked after every operation. There is no
guarantee that the CPU performs wrapping according to the C++ rules, so the
C++ runtime must either recreate the appropriate value or throw a C++
eception.
CPU case 4, 5:
A CPU exception handler must be set up by the C++ runtime in order to handle
integer overflow. If the operation is not performed, see case 2. If the
operation was performed, see case 3.
Conclusions:
1. A requirement for reliable detection of integer overflow imposes
unacceptable performance costs on simple calculations.
2. Given the fact that good programmers verify that operations will not
overflow, this requirement violates the "if a feature is not used, you don't
pay the cost" rule.
3. A class that performs integer arithmetic while checking for overflow,
division by zero etc. is fairly simple to write. It may be worth considering
if such a class should be added to the C++ Standard library.
HTH,
Daniel Pfeffer
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Thu, 26 Aug 2004 19:29:11 GMT Raw View
* kanze@gabi-soft.fr:
>
> Programs with integer overflow are incorrect.
Yes, that's what this discussion is about, that a large part of existing
C++ programs are formally incorrect, while they could easily be
formally correct if only the standard defined the behavior.
> The only acceptable
> defined behavior would be to require an implemetation defined signal to
> be raised.
Reasons?
(Note: (1) it's not expensive to detect overflow when the behavior is
defined as wrapping, so reasons should include why that is unacceptable; (2)
also, for client code it is cost-free relative to alternatives to detect
overflow if the behavior is defined la C# with explicit checked/unchecked
context, so reasons should include why that is unacceptable; (3) a
std::exception would make for portable code, so reasons should include why
that is unacceptable; not why those schemes might in your view be "not as
good" as implementation defined signal, but why they're unacceptably worse.)
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: ajm@flonidan.dk ("Anders J. Munch")
Date: Wed, 25 Aug 2004 04:26:59 GMT Raw View
"Alf P. Steinbach" <alfps@start.no> wrote in message
news:412504b0.14181406@news.individual.net...
>
> Also one must ask, what is the value of leaving signed overflow undefined,
> except the work in changing the standard?
It allows smart implementations to catch bugs.
As long as integer overflow is undefined behaviour, an implementation
is free to trap the overflow and send me an email that my application
has a bug. If integer overflow is defined, then, no matter what it is
defined to, the implementation has to accept the possibility that the
overflow was intentional and let it pass.
Defined behaviour is only preferable to undefined behaviour if it is
what the programmer intended. UB can be a good thing.
- Anders
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Wed, 25 Aug 2004 17:20:34 GMT Raw View
In article <412b4536$0$234$edfadb0f@dread14.news.tele.dk>, Anders J.
Munch <ajm@flonidan.dk> writes
>"Alf P. Steinbach" <alfps@start.no> wrote in message
>news:412504b0.14181406@news.individual.net...
>>
>> Also one must ask, what is the value of leaving signed overflow undefined,
>> except the work in changing the standard?
>
>It allows smart implementations to catch bugs.
>
So does making it implementation defined and providing 'throws an
exception' as one of the options.
>As long as integer overflow is undefined behaviour, an implementation
>is free to trap the overflow and send me an email that my application
>has a bug. If integer overflow is defined, then, no matter what it is
>defined to, the implementation has to accept the possibility that the
>overflow was intentional and let it pass.
Manifestly not the case unless we are going to rule that throwing a
documented exception is no allowed as implementation defined behaviour.
>
>Defined behaviour is only preferable to undefined behaviour if it is
>what the programmer intended. UB can be a good thing.
Unlimited undefined behaviour (which is exactly what undefined behaviour
is in C++) is so extreme that it should only be resorted to when there
is not other reasonable solution. There is a great deal of difference
between allowing a program to crash (which might have other undesirable
consequences) or get a wrong answer (which better not happen if it is
computing the duration of X-Ray treatment for a cancer patient) and
literally washing ones hands of making any attempt to specify the
behaviour of the program itself (which is the consequence of undefined
behaviour).
Even specifying that the consequence of integer overflow is the
immediate termination of the program (were we to allow that as
implementation defined behaviour) would, IMO, be better than what we
currently have.
Storing data at an entirely random address legitimately invokes
undefined behaviour as that is defined in the C++ Standard because we
really cannot limit the consequences in any way. Integer overflow cannot
conceivably be an equivalent problem, so why is it treated as if it is?
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: do-not-spam-benh@bwsint.com (Ben Hutchings)
Date: Wed, 25 Aug 2004 18:45:40 GMT Raw View
Alf P. Steinbach wrote:
> * John Potter:
>> On Sat, 21 Aug 2004 17:02:33 GMT, alfps@start.no (Alf P. Steinbach)
>> wrote:
>>
>> > * John Potter:
>>
>> > > Define the expected wrong answer
>>
>> > Although it follows from earlier: that question seems to be pure rhetoric.
>>
>> > An expected _correct_ answer for a*b might be defined as e.g. x such that
>> > -(2^(n-1)) <= x <= 2^(n-1)-1 and x == a*b (mod 2^n) where n is the number
>> > of bits in the representation.
>>
>> Let a = INT_MAX and b = 2. On my implementation the result is -2 but
>> the modulo answer is 2*INT_MAX. They are not equal. Is my
>> implementation broken with respect to your expectations?
>
>
> Your understanding of what "mod m" means mathematically is incorrect.
>
> "(mod m)" is not an arithmetic operation that produces a value, like the %-
> operator in C++ does.
>
> The expression 'x = y (mod m)' means exactly x = y + C*m for some integer C.
Then your notation is incorrect, or at least unusual. You are using
"=" to mean "is congruent to", which is normally denoted by three
parallel horizontal lines rather than two.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Thu, 26 Aug 2004 00:05:26 GMT Raw View
* "Anders J. Munch":
> "Alf P. Steinbach" <alfps@start.no> wrote in message
> news:412504b0.14181406@news.individual.net...
> >
> > Also one must ask, what is the value of leaving signed overflow undefined,
> > except the work in changing the standard?
>
> It allows smart implementations to catch bugs.
>
> As long as integer overflow is undefined behaviour, an implementation
> is free to trap the overflow and send me an email that my application
> has a bug. If integer overflow is defined, then, no matter what it is
> defined to, the implementation has to accept the possibility that the
> overflow was intentional and let it pass.
Concrete example of such C++ implementation, please.
> Defined behaviour is only preferable to undefined behaviour if it is
> what the programmer intended. UB can be a good thing.
What is the value of leaving signed overflow undefined, except the work in
changing the standard?
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.fr
Date: Thu, 26 Aug 2004 06:11:39 GMT Raw View
ajm@flonidan.dk ("Anders J. Munch") wrote in message
news:<412b4536$0$234$edfadb0f@dread14.news.tele.dk>...
> "Alf P. Steinbach" <alfps@start.no> wrote in message
> news:412504b0.14181406@news.individual.net...
> > Also one must ask, what is the value of leaving signed overflow
> > undefined, except the work in changing the standard?
> It allows smart implementations to catch bugs.
> As long as integer overflow is undefined behaviour, an implementation
> is free to trap the overflow and send me an email that my application
> has a bug. If integer overflow is defined, then, no matter what it is
> defined to, the implementation has to accept the possibility that the
> overflow was intentional and let it pass.
This is, of course, the real reason why the behavior is undefined.
Programs with integer overflow are incorrect. The only acceptable
defined behavior would be to require an implemetation defined signal to
be raised.
Implementing such defined behavior would be expensive on a lot of
machines. And correct programs don't have overflow. Good programmers
validate input before starting their calculations. So you're paying for
something you may not need. But if the hardware supports it without
extra cost, you certainly don't want to ban such an implementation.
Also, in some critical applications, you may want the checking despite
the cost. A compiler is currently free to implement it. If none do
today, it's probably because C++ isn't being used in critical
applications, or at least, it isn't used enough to create a market for a
special compiler.
> Defined behaviour is only preferable to undefined behaviour if it is
> what the programmer intended. UB can be a good thing.
In exceptional cases:-). But I agree, this is one.
On last point: one of the posters claimed that Java raises an
exception. This is not what it says in the Java specification; roughly,
Java requires 32 bit two's complement arithmetic, and you get what the
hardware gives you.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: ajm@flonidan.dk ("Anders J. Munch")
Date: Fri, 27 Aug 2004 19:19:34 GMT Raw View
"Francis Glassborow" <francis@robinton.demon.co.uk> wrote:
> In article <412b4536$0$234$edfadb0f@dread14.news.tele.dk>, Anders J.
> Munch <ajm@flonidan.dk> writes
>
> >As long as integer overflow is undefined behaviour, an implementation
> >is free to trap the overflow and send me an email that my application
> >has a bug. If integer overflow is defined, then, no matter what it is
> >defined to, the implementation has to accept the possibility that the
> >overflow was intentional and let it pass.
>
> Manifestly not the case unless we are going to rule that throwing a
> documented exception is no allowed as implementation defined behaviour.
If integer overflow has defined behaviour, then the implementation
must faithfully produce that behaviour. It is manifestly not at
liberty to start sending me email.
That's not saying an integer overflow exception wouldn't be helpful:
Down the line an integer overflow exception might escape main, which
luckily for us is UB, and hence the implementation might be able to
save a stack trace (or a partial one in case the exception was caught
and rethrown). With a little luck, the implementation might even have
skipped unwinding the potentially corrupted stack.
I certainly wouldn't mind an implementation that threw an exception on
integer overflow, even at the cost of slower integer math - it would
be an improvement over what we have now.
However an implementation that diagnoses most cases of integer
overflow in some implementation-specific way is much simpler to
implement and quite legit within the framework of current standard.
Someone who wants implementations to help find overflow bugs might be
better served by pestering their compiler vendor for better
vendor-defined behaviour than proposing changes to C++ the language.
> Storing data at an entirely random address legitimately invokes
> undefined behaviour as that is defined in the C++ Standard because we
> really cannot limit the consequences in any way. Integer overflow cannot
> conceivably be an equivalent problem, so why is it treated as if it is?
Because the only realistic alternative at the time C was standardised
would have been silent wraparound. Compared to that, even undefined
behaviour is better.
Keep in mind that I'm talking about standardisation rules, not
implementation strategies. It would be different if implementors saw
it as their job to implement undefined behaviour as the the deliberate
execution of random-generated code, but I'm not seeing that happen :)
- Anders
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.fr
Date: Sat, 28 Aug 2004 00:27:33 GMT Raw View
alfps@start.no (Alf P. Steinbach) wrote in message
news:<412e05b0.330729781@news.individual.net>...
> * kanze@gabi-soft.fr:
> > Programs with integer overflow are incorrect.
> Yes, that's what this discussion is about, that a large part of
> existing C++ programs are formally incorrect, while they could easily
> be formally correct if only the standard defined the behavior.
Are there? I've never seen a program, C or C++, which counted on any
specific behavior in the case of overflow. As far as I can tell, it has
been undefined behavior since the very first days of C; the C standards
committee actually innovated in defining it for unsigned integral types.
> > The only acceptable defined behavior would be to require an
> > implemetation defined signal to be raised.
> Reasons?
What other defined behavior is reasonable?
> (Note: (1) it's not expensive to detect overflow when the behavior is
> defined as wrapping, so reasons should include why that is
> unacceptable;
It's expensive on most machines, and not really that useful (since
correct programs don't have integer overflow, and most real programs are
correct in this regard), which is why the behavior should remain
undefined. When it doesn't cost, obviously, the ideal behavior should
be implemented. When it costs, we implement something else -- whatever
the machine gives you, in fact.
> (2) also, for client code it is cost-free relative to alternatives to
> detect overflow if the behavior is defined la C# with explicit
> checked/unchecked context, so reasons should include why that is
> unacceptable;
A checked/unchecked context could be considered. I don't find that it
fits in with the C++ philosophy too well, but the C++ philosophy isn't
something so well defined that we couldn't discuss the issue.
> (3) a std::exception would make for portable code, so reasons should
> include why that is unacceptable; not why those schemes might in your
> view be "not as good" as implementation defined signal, but why
> they're unacceptably worse.)
Turning overflow into an exception would make exception safe code
extremely difficult. In most cases, a program error doesn't merit an
exception, it merits an abort.
Calling a handler, which aborts by default, but which the user can
replace (perhaps with a function which throws) might be an option.
But realistically, it's not going to happen. The current situation is
more than acceptable, and it is certainly not worth the effort to try
and change it.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Sat, 28 Aug 2004 02:25:58 GMT Raw View
* James Kanze:
> * Alf P. Steinbach:
> > James Kanze:
>
> > > Programs with integer overflow are incorrect.
>
> > Yes, that's what this discussion is about, that a large part of
> > existing C++ programs are formally incorrect, while they could easily
> > be formally correct if only the standard defined the behavior.
>
> Are there? I've never seen a program, C or C++, which counted on any
> specific behavior in the case of overflow. As far as I can tell, it has
> been undefined behavior since the very first days of C; the C standards
> committee actually innovated in defining it for unsigned integral types.
Hm. Never seen?
I have given an example earlier, but that was just off-the-cuff. Here
with some techno details. In
<url:
http://www.cs.utah.edu/dept/old/texinfo/glibc-manual-0.02/library_19.html#SEC311>
and in numerous other places, the recommended way to use the standard
clock() function in C (and so with a few adjustments in C++) is given as,
here quoting literally,
#include <time.h>
clock_t start, end;
double elapsed;
start = clock();
... /* Do the work. */
end = clock();
elapsed = ((double) (end - start)) / CLOCKS_PER_SEC;
The return type of clock() is abstract but most often a 'long'
(otherwise it's typically a 'double'); it must be signed because clock() is
required to return -1 on error; and CLOCKS_PER_SEC is often a large number
such as 1000000 -- e.g., <url: http://www.hmug.org/man/3/clock.html>
states that "Version 2 of the Single UNIX Specification (``SUSv2'') requires
CLOCKS_PER_SEC to be defined as one million".
In <url: http://lists.boost.org/MailArchives/boost-users/msg00242.php>
someone has calculated, presumably for 32-bit long, that this results in an
overflow after 36 minutes of continous ticking (clock() doesn't need to
tick continously since it measures process time, but it's in the ballpark).
So, _all_ code that implements the recommended usage of clock() and uses a
standard library where 'clock_t' is 'long' relies on signed int wrapping,
and here I'm not referring only to the overflow in the clock() value itself
but to the subtraction of the old value from the new value.
So as of 2004 _all_ that code is formally incorrect.
And let me ask: is it in your view, as it might seem from the statement
at top above, and defense of that statement, also practically incorrect?
PS: It's late at night so I don't respond to the rest of your posting,
but perhaps later (I'll check it out tomorrow, I think).
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Sat, 28 Aug 2004 02:55:59 GMT Raw View
* Anders J. Munch -> Francis Glassborow:
>
> Someone who wants implementations to help find overflow bugs might be
> better served by pestering their compiler vendor for better
> vendor-defined behaviour than proposing changes to C++ the language.
AFAICS no-one here has a problem with overflow bugs, and no-one here
has been pestering anybody. Especially not Francis. Shame on you.
> the only realistic alternative at the time C was standardised
> would have been silent wraparound. Compared to that, even undefined
> behaviour is better.
What we have as de-facto standard is silent wraparound; I think you'll find
it extremely difficult to change that, and arguing here won't help.
> It would be different if implementors saw
> it as their job to implement undefined behaviour as the the deliberate
> execution of random-generated code, but I'm not seeing that happen :)
Is the argument in the last paragraph that this behavior doesn't need to be
officially defined because there's an effective de-facto standard?
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: qrczak@knm.org.pl ("Marcin 'Qrczak' Kowalczyk")
Date: Sat, 28 Aug 2004 16:10:09 GMT Raw View
kanze@gabi-soft.fr writes:
> Are there? I've never seen a program, C or C++, which counted on any
> specific behavior in the case of overflow.
I use it, relying on 2's complement arithmetic, to detect overflow of
addition and subtraction:
z = x + y;
if ((~(x^y) & (z^x)) >= 0)
// if x and y have different signs, or z and x have same signs
return z;
else
redo the computation on bignums;
This is the fastest semi-portable way I know.
--
__("< Marcin Kowalczyk
\__/ qrczak@knm.org.pl
^^ http://qrnik.knm.org.pl/~qrczak/
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Tue, 24 Aug 2004 02:55:12 GMT Raw View
* John Potter:
> On Sat, 21 Aug 2004 17:02:33 GMT, alfps@start.no (Alf P. Steinbach)
> wrote:
>
> > * John Potter:
>
> > > Define the expected wrong answer
>
> > Although it follows from earlier: that question seems to be pure rhetoric.
>
> > An expected _correct_ answer for a*b might be defined as e.g. x such that
> > -(2^(n-1)) <= x <= 2^(n-1)-1 and x == a*b (mod 2^n) where n is the number
> > of bits in the representation.
>
> Let a = INT_MAX and b = 2. On my implementation the result is -2 but
> the modulo answer is 2*INT_MAX. They are not equal. Is my
> implementation broken with respect to your expectations?
Your understanding of what "mod m" means mathematically is incorrect.
"(mod m)" is not an arithmetic operation that produces a value, like the %-
operator in C++ does.
The expression 'x = y (mod m)' means exactly x = y + C*m for some integer C.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Tue, 24 Aug 2004 20:07:43 GMT Raw View
* John Potter:
> On Sat, 21 Aug 2004 16:39:34 GMT, alfps@start.no (Alf P. Steinbach)
> wrote:
>
> > * John Potter:
>
> > > When is it important to get a wrong answer for signed?
>
> > Doing tax forms? <g>
>
> > Seriously I don't understand the question.
>
> Given two signed integers, when is it useful to execute a
> program on an implementation which can not hold the math world
> answer of the product of the two? There are computer trick
> reasons to want unsigned things to be well defined. Before
> asking for well definded signed things, give some reasons.
Still don't understand the question, but now I must give some reasons?
Well, to me it's meaningless to ask for importance of wrong answer.
> > > What is the value of defining signed overflow?
>
> > First and foremost (1) it means you can write portable code that relies
> > on this feature and have the backing of the standard.
>
> > Such code is very common but currently is invoking Undefined Behavior.
>
> Please give an example.
Perhaps the easiest:
int const start_time = ticks_now();
// Do something time-consuming, say, f().
int const end_time = ticks_now();
int const elapsed_time = end_time - start_time;
Here we know that start_time can conceivably be any value, including
INT_MAX. But we also know that f() won't take years to execute, so
we know that the final result won't exceed INT_MAX.
> > Also one must ask, what is the value of leaving signed overflow undefined,
> > except the work in changing the standard?
>
> If the program crashes, that is good enough.
Yes, any behavior less undefined than the current one is preferable.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Sun, 22 Aug 2004 19:25:28 GMT Raw View
In article <41266EC8.63D4FFCF@acm.org>, Pete Becker <petebecker@acm.org>
writes
>Francis Glassborow wrote:
>>
>> 3) My motive for wanting change is exactly that I want a guaranteed
>> opportunity to recover from cases of signed integer overflow. As of
>> today I have no such guarantee which effectively should prohibit the use
>> of these types in high integrity and safety critical systems.
>>
>
>Nothing in the discussion so far has shown that it is reasonable to
>expect such a guarantee. What do you think will give this guarantee, and
>why? No more handwaving -- give examples and analysis, so that readers
>of this thread can compare the complexity and effectiveness of your
>proposed solution to the complexity and effectiveness of other
>approaches.
As currently almost every use of arithmetic operators with at least one
operand of type signed int or signed long results in a program with
undefined behaviour I find it hard to imagine any proposal that would be
more complex. However, on 2s complement machines my proposal is simple,
the computation should be done exactly as if it were unsigned. That is
one of the great advantages of 2s complement, we do not need to
explicitly handle the sign-bit except when the value is being
interpreted (e.g. for comparisons, output etc.). 2s complement uses
unsigned arithmetic for the purposes of evaluation.
I have already stated that I do not know enough about the way 1s
complement and S&M architectures work to comment on the costs of
requiring signed integer arithmetic overflow be not undefined.
iff throwing is an allowed option for unspecified behaviour, then I
would be happy to have signed integer overflow have unspecified
behaviour. If that isn't the case then I think it should have
implementation defined behaviour with raising an exception being one of
the options.
2s complement machines whose integer types do not include trap values
need incur no cost for removing undefined behaviour for signed integer
overflow.
Those that include trap values would have to handle those. One option
for such handing is raising an exception.
I would be grateful for comments from anyone with expertise on the two
alternative architectures.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: nagle@animats.com (John Nagle)
Date: Fri, 20 Aug 2004 23:32:00 GMT Raw View
Francis Glassborow wrote:
> In article <4123ED67.E88DC90E@acm.org>, Pete Becker <petebecker@acm.org>
> writes
>
>> Francis Glassborow wrote:
>>
>>>
>>> OK, so why do we have such a vehement (from some people -- not here)
>>> defence of leaving overflow in signed arithmetic as undefined behaviour.
>>
>>
>> First and foremost, because nobody has yet suggested a reasonable way to
>> do anything else. As with all suggestions for language changes, "Hey,
>> this would be a good idea" isn't adequate. You have to fill in the
>> details, and so far details have been utterly lacking. Once again: what
>> do you think the standard should require on integer overflow?
Raising an arithmetic exception, as VAXen could do, is always a
possibility. That's what Java does. But nobody puts the hardware
support in current processors any more. It will be interesting to
see if integer overflow checking starts to return to CPU designs
as Java gains market share.
I long ago wrote a paper "Type Integer Considered Harmful", arguing
for portable integer semantics. There, I argued that the right answer
was that the compiler should size intermediate temporaries so that
overflow was impossible, unless it was inevitable in the final result,
in which case it should raise an exception.
So
short i,j,k,m;
i = j*k; // 16-bit multiply
i = (j*k)/m; // 32-bit multiply and divide
i = i+j; // 16-bit add
i = i+j+k; // 32-bit add (i+j can validly exceed 16 bits
// without the final result overflowing
If you want modular arithmetic, you write
const unsigned short MAX_UNSIGNED_SHORT 65535;
...
i = (i+1) % (MAX_UNSIGNED_SHORT+1);
// which the compiler recognizes as
// optimizable and computable in 16 bits.
If an intermediate had to exceed 64 bits, the compiler would be
free to reject the expression as uncompilable.
In a numerical sense, this is the "right" answer. You
get the same numerical result on all platforms. But since
we really don't care much about supporting the 36 bit DEC
and UNISYS ones-complement machines any more, there's not
much need for this. I wrote this before the 36 bit iron
had died off, and arithmetic inconsistency in C across
platforms was a real problem.
John Nagle
Animats
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Sat, 21 Aug 2004 16:39:34 GMT Raw View
* John Potter:
>
> When is it important to get a wrong answer for signed?
Doing tax forms? <g>
Seriously I don't understand the question.
An implementation that produces a wrong answer is non-conforming.
A better question is probably, when is it important to have the right answer
for a signed operation?
As I see it, always; but the current standard does not guarantee that.
> What is the value of defining signed overflow?
First and foremost (1) it means you can write portable code that relies
on this feature and have the backing of the standard.
Such code is very common but currently is invoking Undefined Behavior.
Also I think (2) it would simplify the standard itself, if done properly.
Also (3) it would simplify the teaching of C++.
Also one must ask, what is the value of leaving signed overflow undefined,
except the work in changing the standard?
No credible argument has been put forward for that, just arguments that
in an earlier time had some (marginal) merit.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Sat, 21 Aug 2004 17:01:00 GMT Raw View
In article <1nmVc.29600$nx2.715@newsread2.news.atl.earthlink.net>, John
Potter <jpotter@falcon.lhup.edu> writes
>The morning after pill for birth control? I guess it fits well with
>catching an exception for at ([]) only if it is specified to throw
>rather than produce a wrong answer. If you must test after every
>operation, you may as well test before.
>
>Define the expected wrong answer and consider:
>
>int mult(int a, int b){
> int c(a*b);
>// test code
> return c;
>}
>
>What code could be placed at the comment that would trap and throw if
>the result of a*b overflows?
if(c/a != b) throw(integer_overflow);
>
>How does it compare to the simple pretest supplied earlier?
Well I think that is somewhat simpler.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Sat, 21 Aug 2004 17:02:33 GMT Raw View
* John Potter:
> On Thu, 19 Aug 2004 18:39:32 GMT, francis@robinton.demon.co.uk (Francis
> Glassborow) wrote:
>
> > What is the value of defining signed overflow?
>
> > Because it guarantees me an opportunity to detect and handle the
> > erroneous answer after it has been obtained.
>
> The morning after pill for birth control? I guess it fits well with
> catching an exception for at ([]) only if it is specified to throw
> rather than produce a wrong answer. If you must test after every
> operation, you may as well test before.
>
> Define the expected wrong answer
Although it follows from earlier: that question seems to be pure rhetoric.
An expected _correct_ answer for a*b might be defined as e.g. x such that
-(2^(n-1)) <= x <= 2^(n-1)-1 and x == a*b (mod 2^n) where n is the number
of bits in the representation.
>and consider:
> int mult(int a, int b){
> int c(a*b);
> // test code
> return c;
> }
>
> What code could be placed at the comment that would trap and throw if
> the result of a*b overflows?
Sign check.
> How does it compare to the simple pretest supplied earlier?
First, it usually isn't necessary to throw when the operation is defined,
although of course that depends on the software's requirements.
That's a great saving: no check at all, and no costly exception! :-)
Second, if the software requirements are to produce an exception then the
check is a simple bit operation compared to division in the UB case.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: petebecker@acm.org (Pete Becker)
Date: Sat, 21 Aug 2004 17:03:02 GMT Raw View
Francis Glassborow wrote:
>
> 3) My motive for wanting change is exactly that I want a guaranteed
> opportunity to recover from cases of signed integer overflow. As of
> today I have no such guarantee which effectively should prohibit the use
> of these types in high integrity and safety critical systems.
>
Nothing in the discussion so far has shown that it is reasonable to
expect such a guarantee. What do you think will give this guarantee, and
why? No more handwaving -- give examples and analysis, so that readers
of this thread can compare the complexity and effectiveness of your
proposed solution to the complexity and effectiveness of other
approaches.
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: petebecker@acm.org (Pete Becker)
Date: Thu, 19 Aug 2004 19:34:27 GMT Raw View
Francis Glassborow wrote:
>
> In article <4123EE77.69F1781F@acm.org>, Pete Becker <petebecker@acm.org>
> writes
> >Yup, lots of possibilities, all vague handwaving so far. Which is why
> >the behavior is undefined.
>
> Actually I thought I had listed three alternatives:
>
> 1) wrapping
> 2) saturation
> 3) raise an exception.
>
> There are certainly applications in which the last would be a good
> choice (particularly given appropriate hardware)
>
The text that I replied to, which you snipped, actually said:
> In so far as trapping is concerned, having given more thought to it, I
> feel certain that programs on such machines would have to have some way
> to recover (else they would be unusable). Given that, overflow could be
> handled either by raising a C++ exception or by saturation or ...
Since this discussion seems to be more about evading technical
statements than making them I see no point in continuing.
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: radekg@b-runner.nospam.org (Radoslaw Grzanka)
Date: Thu, 19 Aug 2004 21:19:45 GMT Raw View
Dnia Thu, 19 Aug 2004 18:40:45 +0000, Pete Becker napisa=B3(a):
> James Kuyper wrote:
>>=20
>> petebecker@acm.org (Pete Becker) wrote in message news:<41213C72.C8A0F=
396@acm.org>...
>> ..
>> > Undefined behavior means that the program is not valid.
>>=20
>> Not quite; the standard quite rightly avoids saying that any code is n=
ot valid.
>> Code that depends upon an implementation-specific extension to C++ can=
have
>> behavior that is undefined by the standard. That code is perfectly val=
id, so long
>> as it's never intended to be ported anywhere where that extension is n=
ot
>> available.
>>=20
>=20
> That's a semantic quibble. If a program uses constructs whose behavior
> is undefined you cannot point to the standard to determine what its
> behavior should be. If you prefer "ill-formed" to "invalid", so be it.
Hmm, IMO the code is valid and defined for specific implementation and
machine. One could refer to the compiler specification to find out what
will happen.=20
It's UB in general but specific implementations must take
some approach to the situation and may document it. (Program may not be
portable between compiler realeases though)
In my opinion code is just not portable.
Cheers,
Radek.
--=20
"Oceniaj=B1 mnie, cho=E6 nic o mnie nie wiedz=B1. To dlatego jestem sam" =
- Shrek
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D
e-mail: sad[na]rpg[kropka]pl JID: radekg[na]chrome[kropka=
]pl
L:C++ E+++ T-- !R P+++ D G++ F:ADoM RL--- !RLA W:CP Q++ AI++ RN+ Hp- Re++=
S+
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: Fri, 20 Aug 2004 16:36:44 GMT Raw View
On Thu, 19 Aug 2004 18:39:32 GMT, francis@robinton.demon.co.uk (Francis
Glassborow) wrote:
> In article <F1VUc.2322$2L3.1097@newsread3.news.atl.earthlink.net>, John
> Potter <jpotter@falcon.lhup.edu> writes
> >It is still undefined on a 16 bit platform. 255*255 > 32767 is
> >overflow. It really is a user problem. What wrong answer would
> >you like? For unsigned, I know what I want and when it is
> >important to use it. When is it important to get a wrong answer
> >for signed? What is the value of defining signed overflow?
> Because it guarantees me an opportunity to detect and handle the
> erroneous answer after it has been obtained.
The morning after pill for birth control? I guess it fits well with
catching an exception for at ([]) only if it is specified to throw
rather than produce a wrong answer. If you must test after every
operation, you may as well test before.
Define the expected wrong answer and consider:
int mult(int a, int b){
int c(a*b);
// test code
return c;
}
What code could be placed at the comment that would trap and throw if
the result of a*b overflows?
How does it compare to the simple pretest supplied earlier?
BTW, should divide check also be defined?
John
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Fri, 20 Aug 2004 20:43:18 GMT Raw View
In article <4124F671.F1E67F92@acm.org>, Pete Becker <petebecker@acm.org>
writes
>> Actually I thought I had listed three alternatives:
>>
>> 1) wrapping
>> 2) saturation
>> 3) raise an exception.
>>
>> There are certainly applications in which the last would be a good
>> choice (particularly given appropriate hardware)
>>
>
>The text that I replied to, which you snipped, actually said:
>
>> In so far as trapping is concerned, having given more thought to it, I
>> feel certain that programs on such machines would have to have some way
>> to recover (else they would be unusable). Given that, overflow could be
>> handled either by raising a C++ exception or by saturation or ...
My apologies, similar but not identical threads and sub-threads are
currently running on two other newsgroups to which I contribute.
>
>Since this discussion seems to be more about evading technical
>statements than making them I see no point in continuing.
I think that is an unwarranted miss-characterisation.
However in summary:
1) The questions I raise are not about something that has worked fine
for 30 years, they concern issues that experts in the field of
high-integrity and safety critical programming have been raising
consistently throughout that time, usually getting a response that comes
down to 'that is your problem and not one a language specification can
solve'.
2) Many CPUs actually have a flag that allows them to identify the
occurrence of integer overflow, but neither C nor C++ provides any
mechanism by which a programmer can have access to that information.
There are other places where we deal with the possibility that a
specific feature may be missing for same hardware (e.g. whether or not
there is a system clock) but nonetheless provide for its use when it is
present. What is different about signed integer overflow apart from the
habits of a lifetime?
3) My motive for wanting change is exactly that I want a guaranteed
opportunity to recover from cases of signed integer overflow. As of
today I have no such guarantee which effectively should prohibit the use
of these types in high integrity and safety critical systems. Such
systems should never knowingly expose themselves to undefined behaviour.
4) Given a 2s complement signed integer representation it is easy to
specify the equivalent modular rules for overflow to those we use for
unsigned integer types and so your objection in your other recent post
is a pure debating trick (your skills are too well known for it to be
put down to ignorance).
5) The other possible representations of signed integers (1s complement
and sign and magnitude) are possibly less straightforward. I am not an
expert on such implementations because I have never had to use them.
However I do know (having used a system many years ago that had no
support for signed integer arithmetic) that it is not overwhelmingly
difficult to handle signed integer arithmetic using only unsigned
hardware support. I can not imagine that a system using 1s complement or
S&M has serious problems with handling overflow.
6) Having the Standard require something other than undefined behaviour
(I would prefer implementation defined and have already listed the three
main options) does not prohibit implementations from offering a
non-conforming optimisation for those for whom speed matters more than
risk. However I doubt that it would be necessary, certainly not on 2s
complement architectures.
7) Efforts to remove undefined behaviour from the C++ Standard are
always on topic. IOWs every place where the C++ Standard allows
undefined behaviour should be subject to periodic review. The time to do
such reviews is precisely when a new release is being worked on. The
argument that we have lived with it so far is not and never has been a
technical argument just a pragmatic one. Pragmatic solutions should
always be subject to review.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net (James Kuyper)
Date: Thu, 19 Aug 2004 04:58:42 GMT Raw View
petebecker@acm.org (Pete Becker) wrote in message news:<41213C72.C8A0F396@acm.org>...
..
> Undefined behavior means that the program is not valid.
Not quite; the standard quite rightly avoids saying that any code is not valid.
Code that depends upon an implementation-specific extension to C++ can have
behavior that is undefined by the standard. That code is perfectly valid, so long
as it's never intended to be ported anywhere where that extension is not
available.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: Thu, 19 Aug 2004 06:15:23 GMT Raw View
On Wed, 18 Aug 2004 17:16:09 GMT, francis@robinton.demon.co.uk (Francis
Glassborow) wrote:
> unsigned char a(255), b(255), c(255), d(0);
> d = a * b * c;
> has, if I understand the rules for standard conversions (prefer
> conversion to int over unsigned int) and when they should be applied,
> has undefined behaviour on a 16-bit int platform but fully defined and
> deterministic behaviour on a 32-bit platform.
Yes.
> Perhaps if DR 222 is resolved the way it is currently proposed, we
> should get in the habit of writing arithmetic expressions in forms such
> as:
> (((d=a) *= b) *= c);
> :-) Would it not be better to make such transformations implicit?
It is still undefined on a 16 bit platform. 255*255 > 32767 is
overflow. It really is a user problem. What wrong answer would
you like? For unsigned, I know what I want and when it is
important to use it. When is it important to get a wrong answer
for signed? What is the value of defining signed overflow?
John
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Thu, 19 Aug 2004 14:42:56 GMT Raw View
In article <4123ED67.E88DC90E@acm.org>, Pete Becker <petebecker@acm.org>
writes
>Francis Glassborow wrote:
>>
>> OK, so why do we have such a vehement (from some people -- not here)
>> defence of leaving overflow in signed arithmetic as undefined behaviour.
>
>First and foremost, because nobody has yet suggested a reasonable way to
>do anything else. As with all suggestions for language changes, "Hey,
>this would be a good idea" isn't adequate. You have to fill in the
>details, and so far details have been utterly lacking. Once again: what
>do you think the standard should require on integer overflow?
That it wraps with the same rules as those for unsigned integer types.
Which is de facto what happens on all common platforms with which I am
familiar (i.e. it standardises existing practice)
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Thu, 19 Aug 2004 15:49:49 GMT Raw View
* Pete Becker -> Francis Glassborow:
> >
> >
> > We do not have those problems for unsigned arithmetic, and that means
> > that specifying a modular style behaviour for overflow would work fine
> > for signed arithmetic as well.
>
> This assumes that the performance requirements for signed arithetic are
> the same as those for unsigned, and that the implementation complexity
> of a modular style behaviour is the same. Neither is self-evident.
Right.
It depends on the machine.
Mathematically it's exactly the same if one assumes modular arithmetic in a
range, and at the C++ level it's relatively easy to implement one in terms
of the other with marginal overhead.
So the questions are, (1) is there a computer in actual use or perhaps on
the drawing board that implements some extra delay for signed
two-complement's wrapping operations, for example like the delay Microsoft
has put in the volume control in Windows, _and_ (2) is it very important
that the standard supports maximal efficiency on this machine, if it exists?
I don't think either is self-evident.
> Yup, lots of possibilities, all vague handwaving so far. Which is why
> the behavior is undefined.
That is incorrect on the first count, and I believe also on the second.
There's nothing vague about how most (all?) C++ implementations actually
work.
There's nothing vague about how to make that required, defined behavior.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Thu, 19 Aug 2004 16:39:59 GMT Raw View
* Pete Becker:
> Francis Glassborow wrote:
> >
> > OK, so why do we have such a vehement (from some people -- not here)
> > defence of leaving overflow in signed arithmetic as undefined behaviour.
>
> First and foremost, because nobody has yet suggested a reasonable way to
> do anything else. As with all suggestions for language changes, "Hey,
> this would be a good idea" isn't adequate. You have to fill in the
> details, and so far details have been utterly lacking. Once again: what
> do you think the standard should require on integer overflow?
Don't know about Francis but I would like the standard to require wrapping
in two-complements form, as it already does for unsigned, and as most (all?)
actual C++ implementations already do.
If you want, the details are simply that any C++ operation 'a op b' should
produce the value congruent to a op b modulo 2^n in the range of the type,
where n is the number of bits in the representation.
Note that this is the same detailed specification as for unsigned, as
mentioned above.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Thu, 19 Aug 2004 18:39:32 GMT Raw View
In article <F1VUc.2322$2L3.1097@newsread3.news.atl.earthlink.net>, John
Potter <jpotter@falcon.lhup.edu> writes
>It is still undefined on a 16 bit platform. 255*255 > 32767 is
>overflow. It really is a user problem. What wrong answer would
>you like? For unsigned, I know what I want and when it is
>important to use it. When is it important to get a wrong answer
>for signed? What is the value of defining signed overflow?
Because it guarantees me an opportunity to detect and handle the
erroneous answer after it has been obtained.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Thu, 19 Aug 2004 18:39:40 GMT Raw View
In article <4123EE77.69F1781F@acm.org>, Pete Becker <petebecker@acm.org>
writes
>Yup, lots of possibilities, all vague handwaving so far. Which is why
>the behavior is undefined.
Actually I thought I had listed three alternatives:
1) wrapping
2) saturation
3) raise an exception.
There are certainly applications in which the last would be a good
choice (particularly given appropriate hardware)
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: petebecker@acm.org (Pete Becker)
Date: Thu, 19 Aug 2004 18:40:45 GMT Raw View
James Kuyper wrote:
>
> petebecker@acm.org (Pete Becker) wrote in message news:<41213C72.C8A0F396@acm.org>...
> ..
> > Undefined behavior means that the program is not valid.
>
> Not quite; the standard quite rightly avoids saying that any code is not valid.
> Code that depends upon an implementation-specific extension to C++ can have
> behavior that is undefined by the standard. That code is perfectly valid, so long
> as it's never intended to be ported anywhere where that extension is not
> available.
>
That's a semantic quibble. If a program uses constructs whose behavior
is undefined you cannot point to the standard to determine what its
behavior should be. If you prefer "ill-formed" to "invalid", so be it.
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: petebecker@acm.org (Pete Becker)
Date: Thu, 19 Aug 2004 18:41:20 GMT Raw View
Francis Glassborow wrote:
>
> In article <4123ED67.E88DC90E@acm.org>, Pete Becker <petebecker@acm.org>
> writes
> >Francis Glassborow wrote:
> >>
> >> OK, so why do we have such a vehement (from some people -- not here)
> >> defence of leaving overflow in signed arithmetic as undefined behaviour.
> >
> >First and foremost, because nobody has yet suggested a reasonable way to
> >do anything else. As with all suggestions for language changes, "Hey,
> >this would be a good idea" isn't adequate. You have to fill in the
> >details, and so far details have been utterly lacking. Once again: what
> >do you think the standard should require on integer overflow?
>
> That it wraps with the same rules as those for unsigned integer types.
> Which is de facto what happens on all common platforms with which I am
> familiar (i.e. it standardises existing practice)
>
The rule for unsigned types is that they obey the rules for arithmetic
modulo 2^n, where n is the number of bits in the value representation.
Signed values typically overflow at 2^(n-1), so there are a bunch of
overflowed values that wouldn't be covered by this rule. If by "the same
rules" you mean "by different but similar rules", then you need to say
more than what you've said so far. Note that requiring arithmetic modulo
2^(n-1) isn't what any processor currently does. Incrementing INT_MAX by
1 would produce 0 under this rule.
But let's back up: what problem are you trying to solve? That's the
primary consideration in evaluating tentative solutions. As Yogi Berra
said, "If you don't know where you are going, you will wind up someplace
else." So why should we change a rule that has worked well for thirty
years?
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Mon, 23 Aug 2004 00:50:41 GMT Raw View
* Francis Glassborow:
> on 2s complement machines my proposal is simple,
> the computation should be done exactly as if it were unsigned. That is
> one of the great advantages of 2s complement, we do not need to
> explicitly handle the sign-bit except when the value is being
> interpreted (e.g. for comparisons, output etc.). 2s complement uses
> unsigned arithmetic for the purposes of evaluation.
Just a little nit-picking, if I may... (heh ;-) ).
Consider the 8-bit pattern (direct binary or 2's complement)
10000000
As unsigned it equates to 128, and as signed it equates to -128.
Now we divide by 2.
For unsigned that's a so-called "logical" right-shift, resulting in
01000000
which equates to 64.
For signed it's a so-called "arithmetic" right-shift, where the most
significant bit is left as-is, resulting in
11000000
which equates to -64 (you can view it as 256 + -64 = 128+64).
Thus, operations for signed are not exactly as for unsigned. I'm not sure
whether that's what you meant by "except when the values are being
interpreted". But I suspect not.
However, operations can be _specified_ with the exact same words, as I've
shown earlier (one must simply refer to type's range in the abstract).
But even though I obviously disagree with you about this little detail,
and for that matter also on the details of how best to check for overflow,
and on the detail of accepting John Potter's terminology of "wrong" answer,
I think you're 100% _right_ in the overall judgement: there's much to gain
and apparently nothing to lose by requiring two's complement for signed,
thus making the actual behavior of C++ compilers defined and Standard.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: Mon, 23 Aug 2004 02:32:52 GMT Raw View
On Sat, 21 Aug 2004 17:01:00 GMT, francis@robinton.demon.co.uk (Francis
Glassborow) wrote:
> In article <1nmVc.29600$nx2.715@newsread2.news.atl.earthlink.net>, John
> Potter <jpotter@falcon.lhup.edu> writes
> >The morning after pill for birth control? I guess it fits well with
> >catching an exception for at ([]) only if it is specified to throw
> >rather than produce a wrong answer. If you must test after every
> >operation, you may as well test before.
> >Define the expected wrong answer and consider:
> >int mult(int a, int b){
> > int c(a*b);
> >// test code
> > return c;
> >}
> >What code could be placed at the comment that would trap and throw if
> >the result of a*b overflows?
> if(c/a != b) throw(integer_overflow);
Does this throw when a is zero?
> >How does it compare to the simple pretest supplied earlier?
Which was b != 0 && INT_MAX / abs(b) > abs(a).
> Well I think that is somewhat simpler.
If the division by zero check is added, it is a bit simpler.
If you define the result to be what S2C hardware seems to produce
and it is an S2C machine, this also covers the special case of
INT_MIN. That would make it much simpler.
The definition still has not been given in standard acceptable terms.
John
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Mon, 23 Aug 2004 05:04:08 GMT Raw View
* Alf P. Steinbach:
> * John Potter:
>
> > int mult(int a, int b){
> > int c(a*b);
> > // test code
> > return c;
> > }
> >
> > What code could be placed at the comment that would trap and throw if
> > the result of a*b overflows?
>
> Sign check.
It's now time to correct myself: the above is incorrect.
For example, (2^(n-2)+1) * 4 = 2^n + 4 = 4 (mod 2^n), which for n>3
gives the answer 4 not detectable as overflow by simple sign check.
Happily the standard need not prescribe how to do such checking, and
if an example is deemed appropriate, Francis' division works. ;-)
The C# language has an interesting construct: in a _checked
context_ overflow throws, while in an _unchecked context_ it wraps.
The programmer indicates the context via special keywords 'checked'
and 'unchecked'; see <url: http://tinyurl.com/69hbd>.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: Mon, 23 Aug 2004 15:49:41 GMT Raw View
On Sat, 21 Aug 2004 16:39:34 GMT, alfps@start.no (Alf P. Steinbach)
wrote:
> * John Potter:
> > When is it important to get a wrong answer for signed?
> Doing tax forms? <g>
> Seriously I don't understand the question.
Given two signed integers, when is it useful to execute a
program on an implementation which can not hold the math world
answer of the product of the two? There are computer trick
reasons to want unsigned things to be well defined. Before
asking for well definded signed things, give some reasons.
> > What is the value of defining signed overflow?
> First and foremost (1) it means you can write portable code that relies
> on this feature and have the backing of the standard.
> Such code is very common but currently is invoking Undefined Behavior.
Please give an example.
> Also one must ask, what is the value of leaving signed overflow undefined,
> except the work in changing the standard?
Without a use, there is no need to define it. If the program crashes,
that is good enough.
John
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: Mon, 23 Aug 2004 15:50:35 GMT Raw View
On Sat, 21 Aug 2004 17:02:33 GMT, alfps@start.no (Alf P. Steinbach)
wrote:
> * John Potter:
> > Define the expected wrong answer
> Although it follows from earlier: that question seems to be pure rhetoric.
> An expected _correct_ answer for a*b might be defined as e.g. x such that
> -(2^(n-1)) <= x <= 2^(n-1)-1 and x == a*b (mod 2^n) where n is the number
> of bits in the representation.
Let a = INT_MAX and b = 2. On my implementation the result is -2 but
the modulo answer is 2*INT_MAX. They are not equal. Is my
implementation broken with respect to your expectations?
Why would it be useful?
> >and consider:
> > int mult(int a, int b){
> > int c(a*b);
> > // test code
> > return c;
> > }
> > What code could be placed at the comment that would trap and throw if
> > the result of a*b overflows?
> Sign check.
On my implementation, INT_MAX * INT_MAX == 1. What do you mean by sign
check?
> First, it usually isn't necessary to throw when the operation is defined,
> although of course that depends on the software's requirements.
> That's a great saving: no check at all, and no costly exception! :-)
Do you mean that any garbage is acceptable?
> Second, if the software requirements are to produce an exception then the
> check is a simple bit operation compared to division in the UB case.
Obviously, you have not done any computations to aid in producing a
reasonable answer.
John
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: petebecker@acm.org (Pete Becker)
Date: Mon, 23 Aug 2004 15:52:51 GMT Raw View
Francis Glassborow wrote:
>
> In article <41266EC8.63D4FFCF@acm.org>, Pete Becker <petebecker@acm.org>
> writes
> >Francis Glassborow wrote:
> >>
> >> 3) My motive for wanting change is exactly that I want a guaranteed
> >> opportunity to recover from cases of signed integer overflow. As of
> >> today I have no such guarantee which effectively should prohibit the use
> >> of these types in high integrity and safety critical systems.
> >>
> >
> >Nothing in the discussion so far has shown that it is reasonable to
> >expect such a guarantee. What do you think will give this guarantee, and
> >why? No more handwaving -- give examples and analysis, so that readers
> >of this thread can compare the complexity and effectiveness of your
> >proposed solution to the complexity and effectiveness of other
> >approaches.
>
> As currently almost every use of arithmetic operators with at least one
> operand of type signed int or signed long results in a program with
> undefined behaviour
Nonsense. Most programmers write code that never overflows, in part
because they respect the ranges in which such operations are well
defined, knowingly or otherwise.
>I find it hard to imagine any proposal that would be
> more complex.
It's not a matter of what you can imagine, but of what you can
demonstrate. I'm getting tired of asking you to give examples and
analysis, but surely you know that that's what's needed. Without actual
code showing how to write pre-tests and your post-tests it's impossible
to compare their complexity. But your approach would have to offer an
extremely large reduction in complexity to offset the complexity
inherent in changing the language definition.
> However, on 2s complement machines my proposal is simple,
> the computation should be done exactly as if it were unsigned. That is
> one of the great advantages of 2s complement, we do not need to
> explicitly handle the sign-bit except when the value is being
> interpreted (e.g. for comparisons, output etc.). 2s complement uses
> unsigned arithmetic for the purposes of evaluation.
>
> I have already stated that I do not know enough about the way 1s
> complement and S&M architectures work to comment on the costs of
> requiring signed integer arithmetic overflow be not undefined.
Okay, so you're willing to tolerate different results on different
architectures, so long as they're well defined. Can you write your
post-tests without depending on architectural details? Examples and
analysis, please. (a futile request, I know, but I'll keep making it)
>
> iff throwing is an allowed option for unspecified behaviour, then I
> would be happy to have signed integer overflow have unspecified
> behaviour. If that isn't the case then I think it should have
> implementation defined behaviour with raising an exception being one of
> the options.
So, the requirement would be something like either give a wrapped result
or throw an exception? That's the worst of all worlds: you have to write
code to handle both possibilities. Just like operator new returning a
null pointer or throwing an exception.
>
> 2s complement machines whose integer types do not include trap values
> need incur no cost for removing undefined behaviour for signed integer
> overflow.
>
Well, maybe. But we don't make language changes just because they can be
made to appear easy. They must also offer a significant benefit. Again,
this means writing examples of your post-test code and comparing them to
the pre-test code that's valid under the present language rules. And not
just for multiplication; include addition and subtraction, and then do
some more complex examples. Start with a*x+b*y.
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: llewelly.at@xmission.dot.com (llewelly)
Date: Mon, 23 Aug 2004 15:54:31 GMT Raw View
alfps@start.no (Alf P. Steinbach) writes:
> * Francis Glassborow:
>> on 2s complement machines my proposal is simple,
>> the computation should be done exactly as if it were unsigned. That is
>> one of the great advantages of 2s complement, we do not need to
>> explicitly handle the sign-bit except when the value is being
>> interpreted (e.g. for comparisons, output etc.). 2s complement uses
>> unsigned arithmetic for the purposes of evaluation.
>
> Just a little nit-picking, if I may... (heh ;-) ).
>
> Consider the 8-bit pattern (direct binary or 2's complement)
>
> 10000000
>
> As unsigned it equates to 128, and as signed it equates to -128.
>
> Now we divide by 2.
>
> For unsigned that's a so-called "logical" right-shift, resulting in
>
> 01000000
>
> which equates to 64.
>
> For signed it's a so-called "arithmetic" right-shift, where the most
> significant bit is left as-is, resulting in
>
> 11000000
>
> which equates to -64 (you can view it as 256 + -64 = 128+64).
>
> Thus, operations for signed are not exactly as for unsigned. I'm not sure
> whether that's what you meant by "except when the values are being
> interpreted". But I suspect not.
huh? If I understand your example, if you interpret 10000000 as 128
unsigned, you do a logical right-shift, but if you interpret
10000000 as -128 signed, you do an arithmetic right-shift. This
seems to me exactly what Francis must have meant by 'interpreted'.
> However, operations can be _specified_ with the exact same words, as I've
> shown earlier (one must simply refer to type's range in the abstract).
>
> But even though I obviously disagree with you about this little detail,
> and for that matter also on the details of how best to check for overflow,
> and on the detail of accepting John Potter's terminology of "wrong" answer,
> I think you're 100% _right_ in the overall judgement: there's much to gain
> and apparently nothing to lose by requiring two's complement for signed,
> thus making the actual behavior of C++ compilers defined and Standard.
[snip]
Well it will cost someone time and energy to mmake a proposal which
is agreeable, and contains the necessary rigor and
completeless. I think this is clearly worth it, though.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Wed, 18 Aug 2004 05:33:06 GMT Raw View
In article <41213D8B.877DDC5E@acm.org>, Pete Becker <petebecker@acm.org>
writes
>Uwe Schnitker wrote:
>>
>> If it's "implementation defined behaviour", the implementation is required
>> to document the actually choosen behaviour. This allows the user to write
>> code that is working. even if it's not portable. It also allows library
>> writers to write portable abstractions for the platforms their libary
>> supports by using conditional compilation.
>>
>
>It makes a nightmare for implementors. Consider:
>
>int i = 2;
>int j = (INT_MAX * i) / INT_MAX;
>
>The numerator overflows, so the implementation would have to describe
>what happens in that case. But if the compiler does constant folding the
>two INT_MAX's cancel out and the result is well defined, so the
>implementation would have to document what happens in that case, as
>well. Now multiply that by all the possible optimizations, as well as
>any other compiler options that affect code generation. The resulting
>documentation would be incomprehensible.
We do not have those problems for unsigned arithmetic, and that means
that specifying a modular style behaviour for overflow would work fine
for signed arithmetic as well.
On a sign & value machine or a ones complement one I am not sure how the
hardware deals with overflow because I have never had to use one,
perhaps someone else would comment, However AIUI those machines have to
explicitly handles the sign bit.
In so far as trapping is concerned, having given more thought to it, I
feel certain that programs on such machines would have to have some way
to recover (else they would be unusable). Given that, overflow could be
handled either by raising a C++ exception or by saturation or ...
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Wed, 18 Aug 2004 17:16:09 GMT Raw View
In article <1467218.JmYAskXeuB@technoboredom.net>, Marco Manfredini
<nospam@phoyd.net> writes
>Francis Glassborow wrote:
>
>> In article <411fe38f.26591734@news.individual.net>, Alf P. Steinbach
>> <alfps@start.no> writes
>>>* Francis Glassborow:
>>>> Now I recently saw
>>>> this defended on the basis that some processors will trap on
>>>> overflow.
>>>
>>>In theory that can happen, but in theory so can unsigned overflow
>>>trap.
>>
>> Not for a conforming C++ implementation.
>
>I think he wanted to say, that a /processor/ can trap both unsigned and
>signed overflows. This renders the "UB because the processor can trap"
>argument useless - a conforming implementation would have to handle
>traps from unsigned overflows to emulate the defined behaviour anyway,
>so why couldn't this be done for signed overflows?
OK, so why do we have such a vehement (from some people -- not here)
defence of leaving overflow in signed arithmetic as undefined behaviour.
For example:
unsigned char a(255), b(255), c(255), d(0);
d = a * b * c;
has, if I understand the rules for standard conversions (prefer
conversion to int over unsigned int) and when they should be applied,
has undefined behaviour on a 16-bit int platform but fully defined and
deterministic behaviour on a 32-bit platform.
Perhaps if DR 222 is resolved the way it is currently proposed, we
should get in the habit of writing arithmetic expressions in forms such
as:
(((d=a) *= b) *= c);
:-) Would it not be better to make such transformations implicit?
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: petebecker@acm.org (Pete Becker)
Date: Thu, 19 Aug 2004 00:35:06 GMT Raw View
Francis Glassborow wrote:
>
> In article <41213D8B.877DDC5E@acm.org>, Pete Becker <petebecker@acm.org>
> writes
> >Uwe Schnitker wrote:
> >>
> >> If it's "implementation defined behaviour", the implementation is required
> >> to document the actually choosen behaviour. This allows the user to write
> >> code that is working. even if it's not portable. It also allows library
> >> writers to write portable abstractions for the platforms their libary
> >> supports by using conditional compilation.
> >>
> >
> >It makes a nightmare for implementors. Consider:
> >
> >int i = 2;
> >int j = (INT_MAX * i) / INT_MAX;
> >
> >The numerator overflows, so the implementation would have to describe
> >what happens in that case. But if the compiler does constant folding the
> >two INT_MAX's cancel out and the result is well defined, so the
> >implementation would have to document what happens in that case, as
> >well. Now multiply that by all the possible optimizations, as well as
> >any other compiler options that affect code generation. The resulting
> >documentation would be incomprehensible.
>
> We do not have those problems for unsigned arithmetic, and that means
> that specifying a modular style behaviour for overflow would work fine
> for signed arithmetic as well.
This assumes that the performance requirements for signed arithetic are
the same as those for unsigned, and that the implementation complexity
of a modular style behaviour is the same. Neither is self-evident.
>
> On a sign & value machine or a ones complement one I am not sure how the
> hardware deals with overflow because I have never had to use one,
> perhaps someone else would comment, However AIUI those machines have to
> explicitly handles the sign bit.
>
> In so far as trapping is concerned, having given more thought to it, I
> feel certain that programs on such machines would have to have some way
> to recover (else they would be unusable). Given that, overflow could be
> handled either by raising a C++ exception or by saturation or ...
>
Yup, lots of possibilities, all vague handwaving so far. Which is why
the behavior is undefined.
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: petebecker@acm.org (Pete Becker)
Date: Thu, 19 Aug 2004 01:51:35 GMT Raw View
Francis Glassborow wrote:
>
> OK, so why do we have such a vehement (from some people -- not here)
> defence of leaving overflow in signed arithmetic as undefined behaviour.
First and foremost, because nobody has yet suggested a reasonable way to
do anything else. As with all suggestions for language changes, "Hey,
this would be a good idea" isn't adequate. You have to fill in the
details, and so far details have been utterly lacking. Once again: what
do you think the standard should require on integer overflow?
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Sun, 15 Aug 2004 20:32:08 GMT Raw View
AFAICS int overflow results in undefined behaviour. Now I recently saw
this defended on the basis that some processors will trap on overflow.
It has always been my understanding that UB is reserved for cases where
either diagnosing a problem at compile time is impossible or requires
unreasonable computing resources _and_ that there is no way to restrict
the consequences to a well-defined list of possibilities.
The question that I have to ask is why a processor trap is considered
justification for UB. Should we not just allow that implementation
defined behaviour/unspecified behaviour can include trapping? In
practice few, if any, modern CPUs trap on integer overflow.
Consider:
int mult(int a, int b){
// test code
return a*b;
}
What code could be placed at the comment that would trap and throw if
the result of a*b overflows?
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Mon, 16 Aug 2004 06:41:53 GMT Raw View
* Francis Glassborow:
>
> AFAICS int overflow results in undefined behaviour.
Yes.
> Now I recently saw
> this defended on the basis that some processors will trap on overflow.
In theory that can happen, but in theory so can unsigned overflow trap.
> It has always been my understanding that UB is reserved for cases where
> either diagnosing a problem at compile time is impossible or requires
> unreasonable computing resources _and_ that there is no way to restrict
> the consequences to a well-defined list of possibilities.
For unsigned there is no problem in defining arithmetic results modulo
2^n (works for both direct binary and gray code), but for signed that would
limit the representation (currently the standard allows two-complement and
sign-bit, I'm not sure about the theoretical possibility of one's complement
or nega-binary, but I think the latter is ruled out by the C++ shift rules).
Personally I think it would be nice if the standard required two's
complement for signed ints.
Then all could be well-defined and very much simpler.
> The question that I have to ask is why a processor trap is considered
> justification for UB. Should we not just allow that implementation
> defined behaviour/unspecified behaviour can include trapping? In
> practice few, if any, modern CPUs trap on integer overflow.
Possibly that is not the issue.
> Consider:
>
> int mult(int a, int b){
>
> // test code
> return a*b;
> }
>
> What code could be placed at the comment that would trap and throw if
> the result of a*b overflows?
Perhaps the numerical computing people can give a much better answer.
But at the C++ level, I think the following would work.
If a > 0, b > 0, max > 0, then a*b > max iff a > max/b. For integers in
C++ the problem is a > floor(max/b) does not imply a > max/b but only
that a > max/b - c where 0 <= c < 1, i.e. that a*b > max - b*c, where
0 <= b*c = max%b < b. This suggests first checking whether (a-1)*b
is in the danger zone of overflowing: if it is, then a*b must overflow,
and if it isn't, perform the multiplication and check against max-b.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: petebecker@acm.org (Pete Becker)
Date: Mon, 16 Aug 2004 06:41:58 GMT Raw View
Francis Glassborow wrote:
>
> The question that I have to ask is why a processor trap is considered
> justification for UB.
It's not that it's a justification, it's that that's what happens. If we
want defined behavior then the standard has to define a "processor
trap."
> Should we not just allow that implementation
> defined behaviour/unspecified behaviour can include trapping?
Regardless of what it's called, code that produces integer overflow is
not portable. What is the benefit to language users of changing what
it's called?
> In
> practice few, if any, modern CPUs trap on integer overflow.
>
> Consider:
>
> int mult(int a, int b){
>
> // test code
> return a*b;
> }
>
> What code could be placed at the comment that would trap and throw if
> the result of a*b overflows?
>
Split each number into an upper half-word and a lower half-word: au, al,
bu, and bl. If au and bu are both non-zero the multiplication overflows.
Otherwise, if either of the cross-products au*bl and bu*al is too large
to fit in a half-word the multiplication overflows. Otherwise it's okay.
It's just multiplication of two-digit numbers, base sqrt(INT_MAX+1), by
hand. If you get a carry out of the second digit you've got an overflow.
But the real problem here is that that function is badly designed or
badly underspecified. It's far better to avoid overflows by knowing the
ranges of the values that your'e dealing with. For example, if you know
that a and b are in the range -32727..32767 (i.e. they're values that
can portably be stored in an int) then their product will fit in a long.
Or if a is in the range 0..10 and b is in the range
INT_MIN/10..INT_MAX/10 then the product will fit in an int.
Ultimately the issue is: What do you want to accomplish by fiddling with
the current rules?
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Mon, 16 Aug 2004 16:36:39 GMT Raw View
In article <411fe38f.26591734@news.individual.net>, Alf P. Steinbach
<alfps@start.no> writes
>If a > 0, b > 0, max > 0, then a*b > max iff a > max/b. For integers in
>C++ the problem is a > floor(max/b) does not imply a > max/b but only
>that a > max/b - c where 0 <= c < 1, i.e. that a*b > max - b*c, where
>0 <= b*c = max%b < b. This suggests first checking whether (a-1)*b
>is in the danger zone of overflowing: if it is, then a*b must overflow,
>and if it isn't, perform the multiplication and check against max-b.
That last clause blows it. We must not perform the multiplication before
we know it does not overflow. However if we know that (a-1)*b does not
overflow we can perform that then check if we have enough headroom to
add on one more b value.
However do you honestly propose that we should do this to avoid the
taint of UB in our code? I guess not, so is it not time to make it
defined (and platforms using sign&value or ones complement can be
allowed to produce wrong answers but not reformat my harddrive).
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: Mon, 16 Aug 2004 16:38:05 GMT Raw View
On Mon, 16 Aug 2004 06:41:53 GMT, alfps@start.no (Alf P. Steinbach)
wrote:
> * Francis Glassborow:
> > Consider:
> > int mult(int a, int b){
> > // test code
> > return a*b;
> > }
> > What code could be placed at the comment that would trap and throw if
> > the result of a*b overflows?
> But at the C++ level, I think the following would work.
> If a > 0, b > 0, max > 0, then a*b > max iff a > max/b. For integers in
> C++ the problem is a > floor(max/b) does not imply a > max/b but only
> that a > max/b - c where 0 <= c < 1, i.e. that a*b > max - b*c, where
> 0 <= b*c = max%b < b.
I think you forgot that a is an integer. If a > floor(max/b) then a >=
floor(max/b) + 1 and a*b >= b*floor(max/b) + b > max.
if (b != 0 && INT_MAX / abs(b) > abs(a))
throw "Overflow";
The special case of INT_MIN for S2C is left to the reader.
John
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Mon, 16 Aug 2004 16:41:44 GMT Raw View
In article <411fe38f.26591734@news.individual.net>, Alf P. Steinbach
<alfps@start.no> writes
>* Francis Glassborow:
>>
>> AFAICS int overflow results in undefined behaviour.
>
>Yes.
>
>
>> Now I recently saw
>> this defended on the basis that some processors will trap on overflow.
>
>In theory that can happen, but in theory so can unsigned overflow trap.
Not for a conforming C++ implementation.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Mon, 16 Aug 2004 16:41:55 GMT Raw View
In article <41201322.F8DBF50B@acm.org>, Pete Becker <petebecker@acm.org>
writes
>Francis Glassborow wrote:
>>
>> The question that I have to ask is why a processor trap is considered
>> justification for UB.
>
>It's not that it's a justification, it's that that's what happens. If we
>want defined behavior then the standard has to define a "processor
>trap."
And I think that would be better than, to my mind, the gratuitous use of
UB as a get out.
>
>> Should we not just allow that implementation
>> defined behaviour/unspecified behaviour can include trapping?
>
>Regardless of what it's called, code that produces integer overflow is
>not portable. What is the benefit to language users of changing what
>it's called?
Nor is unspecified or implementation defined behaviour. The gain is in
applying the appropriate level of semantic specification. Undefined
behaviour is or should be a serious issue. Using it in cases where it is
nearly inconceivable that it will ever happen trivialises it.
>
>> In
>> practice few, if any, modern CPUs trap on integer overflow.
>>
>> Consider:
>>
>> int mult(int a, int b){
>>
>> // test code
>> return a*b;
>> }
>>
>> What code could be placed at the comment that would trap and throw if
>> the result of a*b overflows?
>>
>
>Split each number into an upper half-word and a lower half-word: au, al,
>bu, and bl. If au and bu are both non-zero the multiplication overflows.
>Otherwise, if either of the cross-products au*bl and bu*al is too large
>to fit in a half-word the multiplication overflows. Otherwise it's okay.
>It's just multiplication of two-digit numbers, base sqrt(INT_MAX+1), by
>hand. If you get a carry out of the second digit you've got an overflow.
OK, so you have provided an algorithm that could be applied to any
hardware where actual overflow would be an immediate problem.
>
>But the real problem here is that that function is badly designed or
>badly underspecified. It's far better to avoid overflows by knowing the
>ranges of the values that your'e dealing with. For example, if you know
>that a and b are in the range -32727..32767 (i.e. they're values that
>can portably be stored in an int) then their product will fit in a long.
>Or if a is in the range 0..10 and b is in the range
>INT_MIN/10..INT_MAX/10 then the product will fit in an int.
This assumes that there will always be a larger integer type that can be
used for the intermediate computation.
>
>Ultimately the issue is: What do you want to accomplish by fiddling with
>the current rules?
Making the Standard actually concur with reality. Having the Standard
mark something as potentially UB when every programmer knows it won't
happen lowers the threshold of tolerance for UB. I suggest that this is
one of the very few possible changes to the Standard that would have
zero effect on real code and compilers whilst making better guarantees.
It really, IMO, should be no big deal to make the change unless someone
can demonstrate that it will break at least one compiler.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: schnitkerAffenschaukel@sigma-c.com (Uwe Schnitker)
Date: Mon, 16 Aug 2004 16:42:47 GMT Raw View
petebecker@acm.org (Pete Becker) wrote in message news:<41201322.F8DBF50B@acm.org>...
> Francis Glassborow wrote:
> >
> > The question that I have to ask is why a processor trap is considered
> > justification for UB.
>
> It's not that it's a justification, it's that that's what happens. If we
> want defined behavior then the standard has to define a "processor
> trap."
The next sentence shows that Francis doesn't want "defined behaviour".
>
> > Should we not just allow that implementation
> > defined behaviour/unspecified behaviour can include trapping?
>
> Regardless of what it's called, code that produces integer overflow is
> not portable. What is the benefit to language users of changing what
> it's called?
If it's "implementation defined behaviour", the implementation is required
to document the actually choosen behaviour. This allows the user to write
code that is working. even if it's not portable. It also allows library
writers to write portable abstractions for the platforms their libary
supports by using conditional compilation.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Mon, 16 Aug 2004 16:59:00 GMT Raw View
* Francis Glassborow:
> * Alf P. Steinbach:
> >If a > 0, b > 0, max > 0, then a*b > max iff a > max/b. For integers in
> >C++ the problem is a > floor(max/b) does not imply a > max/b but only
> >that a > max/b - c where 0 <= c < 1, i.e. that a*b > max - b*c, where
> >0 <= b*c = max%b < b. This suggests first checking whether (a-1)*b
> >is in the danger zone of overflowing: if it is, then a*b must overflow,
> >and if it isn't, perform the multiplication and check against max-b.
>
> That last clause blows it. We must not perform the multiplication before
> we know it does not overflow. However if we know that (a-1)*b does not
> overflow we can perform that then check if we have enough headroom to
> add on one more b value.
Yes, that's what I wrote? :-)
> However do you honestly propose that we should do this to avoid the
> taint of UB in our code? I guess not, so is it not time to make it
> defined (and platforms using sign&value or ones complement can be
> allowed to produce wrong answers but not reformat my harddrive).
Yes I agree: as I wrote, I think it's time to _require_ two's complement.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Mon, 16 Aug 2004 18:09:51 GMT Raw View
* Francis Glassborow:
> * Alf P. Steinbach
> >* Francis Glassborow:
> >>
> >> AFAICS int overflow results in undefined behaviour.
> >
> >Yes.
> >
> >> Now I recently saw
> >> this defended on the basis that some processors will trap on overflow.
> >
> >In theory that can happen, but in theory so can unsigned overflow trap.
>
> Not for a conforming C++ implementation.
It can.
What it cannot do is to affect the final result in the C++ code.
The argument rephrased: if it isn't a problem for unsigned (and presumably
it isn't), then it shouldn't be more of a problem for signed.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Mon, 16 Aug 2004 23:03:58 GMT Raw View
In article <4120e989.93657937@news.individual.net>, Alf P. Steinbach
<alfps@start.no> writes
>* Francis Glassborow:
>> * Alf P. Steinbach
>> >* Francis Glassborow:
>>> >
>>> > AFAICS int overflow results in undefined behaviour.
>> >
>> >Yes.
>> >
>>> > Now I recently saw
>>> > this defended on the basis that some processors will trap on overflow.
>> >
>> >In theory that can happen, but in theory so can unsigned overflow trap.
>>
>> Not for a conforming C++ implementation.
>
>It can.
Then we must have different meanings for 'trap'.
>
>What it cannot do is to affect the final result in the C++ code.
>
>The argument rephrased: if it isn't a problem for unsigned (and presumably
>it isn't), then it shouldn't be more of a problem for signed.
OK, I will go with that.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: petebecker@acm.org (Pete Becker)
Date: Mon, 16 Aug 2004 23:04:18 GMT Raw View
Francis Glassborow wrote:
>
> In article <41201322.F8DBF50B@acm.org>, Pete Becker <petebecker@acm.org>
> writes
> >Francis Glassborow wrote:
> >>
> >> The question that I have to ask is why a processor trap is considered
> >> justification for UB.
> >
> >It's not that it's a justification, it's that that's what happens. If we
> >want defined behavior then the standard has to define a "processor
> >trap."
>
> And I think that would be better than, to my mind, the gratuitous use of
> UB as a get out.
Well, if it were gratuitous I'd agree. But it's not.
>
> >
> >> Should we not just allow that implementation
> >> defined behaviour/unspecified behaviour can include trapping?
> >
> >Regardless of what it's called, code that produces integer overflow is
> >not portable. What is the benefit to language users of changing what
> >it's called?
>
> Nor is unspecified or implementation defined behaviour. The gain is in
> applying the appropriate level of semantic specification. Undefined
> behaviour is or should be a serious issue. Using it in cases where it is
> nearly inconceivable that it will ever happen trivialises it.
No. Calling it undefined behavior says that the langauge definition
imposes no requirements. Saying that it is unspecified imposes
requirements that have to be fleshed out. Saying that it is
implementation defined imposes unworkable requirements on implementors.
>
> >
> >> In
> >> practice few, if any, modern CPUs trap on integer overflow.
> >>
> >> Consider:
> >>
> >> int mult(int a, int b){
> >>
> >> // test code
> >> return a*b;
> >> }
> >>
> >> What code could be placed at the comment that would trap and throw if
> >> the result of a*b overflows?
> >>
> >
> >Split each number into an upper half-word and a lower half-word: au, al,
> >bu, and bl. If au and bu are both non-zero the multiplication overflows.
> >Otherwise, if either of the cross-products au*bl and bu*al is too large
> >to fit in a half-word the multiplication overflows. Otherwise it's okay.
> >It's just multiplication of two-digit numbers, base sqrt(INT_MAX+1), by
> >hand. If you get a carry out of the second digit you've got an overflow.
>
> OK, so you have provided an algorithm that could be applied to any
> hardware where actual overflow would be an immediate problem.
Actually, thre's a much simpler one, as has been pointed out in other
messages. I shouldn't have written that so late at night. <g>
>
> >
> >But the real problem here is that that function is badly designed or
> >badly underspecified. It's far better to avoid overflows by knowing the
> >ranges of the values that your'e dealing with. For example, if you know
> >that a and b are in the range -32727..32767 (i.e. they're values that
> >can portably be stored in an int) then their product will fit in a long.
> >Or if a is in the range 0..10 and b is in the range
> >INT_MIN/10..INT_MAX/10 then the product will fit in an int.
>
> This assumes that there will always be a larger integer type that can be
> used for the intermediate computation.
No, it assumes that int meets the requirements of C and C++.
>
> >
> >Ultimately the issue is: What do you want to accomplish by fiddling with
> >the current rules?
>
> Making the Standard actually concur with reality. Having the Standard
> mark something as potentially UB when every programmer knows it won't
> happen lowers the threshold of tolerance for UB.
I don't know what "lower the threshold of tolerance" means here.
Let's go back to basics. The language definition describes what happens
when a program uses expressions that the language definition says are
valid. Sometimes the standard writers decide that dictating exactly one
correct behavior is inappropriate. In that case we have three
alternatives: unspecified behavior, implementation-defined behavior, and
undefined behavor.
Unspecified behavior means that the program is valid (unless other parts
are invalid) and there is a [small] set of reasonable alternatives that
the implementation can arbitrarily choose from. One common example is
the expression f(g(),h()) -- the order of the calls to g and h is
unspecified.
Implementation defined behavior means that the program is valid (unless
other parts are invalid) and the implementor must document what the
implementation does. One common example is int a = 40000; Whether this
code is valid depends on the range of values that can be stored in an
int. That is documented by INT_MAX.
Undefined behavior means that the program is not valid.
Now, which of these is appropriate for integer overflow? Currently it's
undefined behavior. Making it implementation defined is a non-starter:
the result is far too dependent on compiler optimizations, and
documenting it would effectively prohibit many optimizations. So the
only other possibility is to make it unspecified. That doens't mean that
it's allowed to do something that has no specification; it means only
that the compiler can choose between various well-defined alternatives.
It does not mean that valid code is allowed to crash, which is the
effect (from a standards perspective) of a "processor trap".
> I suggest that this is
> one of the very few possible changes to the Standard that would have
> zero effect on real code and compilers whilst making better guarantees.
>
> It really, IMO, should be no big deal to make the change unless someone
> can demonstrate that it will break at least one compiler.
>
Whoa, there's a lot more needed to "make this change" than has been
discussed here. If a "processor trap" is to be allowed the standard must
specify its behavior. What, exactly, should the standard require to
happen on a "processor trap"?
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: petebecker@acm.org (Pete Becker)
Date: Mon, 16 Aug 2004 23:21:30 GMT Raw View
Uwe Schnitker wrote:
>
> If it's "implementation defined behaviour", the implementation is required
> to document the actually choosen behaviour. This allows the user to write
> code that is working. even if it's not portable. It also allows library
> writers to write portable abstractions for the platforms their libary
> supports by using conditional compilation.
>
It makes a nightmare for implementors. Consider:
int i = 2;
int j = (INT_MAX * i) / INT_MAX;
The numerator overflows, so the implementation would have to describe
what happens in that case. But if the compiler does constant folding the
two INT_MAX's cancel out and the result is well defined, so the
implementation would have to document what happens in that case, as
well. Now multiply that by all the possible optimizations, as well as
any other compiler options that affect code generation. The resulting
documentation would be incomprehensible.
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: pasa@lib.hu ("Balog Pal")
Date: Mon, 16 Aug 2004 23:21:52 GMT Raw View
"Francis Glassborow" <francis@robinton.demon.co.uk> wrote in message
news:a1NJDoDEszHBFw2Q@robinton.demon.co.uk...
> AFAICS int overflow results in undefined behaviour. Now I recently saw
> this defended on the basis that some processors will trap on overflow.
A better defend could say 'let's make it a QoI issue without tieing the
hands'. IMHO most platforms and comilers have a well defined behavior on
integer overflow. Okey, I can't support the 'most' part, but everything I
ever worked on, and that's a long list did the same thing as unsigned
overflow. And if those trapping platforms exist what is the problem with
writing down what will actually happen?
The pick one idea is interesting too, but it woud better fit in a major
reform, with stricter definitions on binary representation, bit count and
such.
However I'd be glad if the standard came with a sheet of generally undefined
and unspecified areas, and implemetations were required to fill that sheet
according to their behavior. Still leaving option to write 'anything can
happen', but I'd bet it would be a rare thing to see.
The real-life problem with UB is too many times the dox is sloppy enough
leaving us to build on heuristics.
Paul
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: Tue, 17 Aug 2004 22:59:19 GMT Raw View
On Mon, 16 Aug 2004 16:36:39 GMT, francis@robinton.demon.co.uk (Francis
Glassborow) wrote:
> However do you honestly propose that we should do this to avoid the
> taint of UB in our code? I guess not, so is it not time to make it
> defined (and platforms using sign&value or ones complement can be
> allowed to produce wrong answers but not reformat my harddrive).
Are platforms with trap values allowed to generate wrong values which
are trap values which crash your program? If not, why not? If so, how
can a crash be anything other than UB?
John
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: nospam@phoyd.net (Marco Manfredini)
Date: Wed, 18 Aug 2004 05:25:30 GMT Raw View
Francis Glassborow wrote:
> In article <411fe38f.26591734@news.individual.net>, Alf P. Steinbach
> <alfps@start.no> writes
>>* Francis Glassborow:
>>> Now I recently saw
>>> this defended on the basis that some processors will trap on
>>> overflow.
>>
>>In theory that can happen, but in theory so can unsigned overflow
>>trap.
>
> Not for a conforming C++ implementation.
I think he wanted to say, that a /processor/ can trap both unsigned and
signed overflows. This renders the "UB because the processor can trap"
argument useless - a conforming implementation would have to handle
traps from unsigned overflows to emulate the defined behaviour anyway,
so why couldn't this be done for signed overflows?
Marco
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]