I have the following requierement: 3 ints (a, b, limit). The sum of
'a' and 'b' shouldn't be bigger than limit otherwise 'a' should be
adjusted so that the sum of 'a' and 'b' is equal to 'limit'.
Basically this can be written in C like this:
int a, b, limit;
/* some code that setup the 3 variables */
if (a < 0 || b < 0)
goto end;
if (a + b > b) /* test for overflow (correct with GCC but not
portable) */
goto end;
if (a + b > limit)
a -= a + b - limit;
if (a < 0)
goto end;
/* ... */
So this should work (ok this uses an undefined behaviour but this code
is only intended to be compiled by GCC) but it looks quite
complicated.
Can anybody think to something more 'elegant' ?
Thanks
int geta(a, b, limit)
{
unsigned int t;
int answer;
if(a >= 0 && b >= 0)
{
t = (unsigned) a + (unsigned) b;
if(t > limit)
answer = limit - b;
else
answer = a;
}
/* you haven't specified your other cases. What do we do if one or
both are negative?*/
return answer;
}
I think:
if(a > limit - b)
a = limit - b;
The rest of your code does things you didn't specify, and
it's not clear where 'end' goes to, so I can't tell how to
clean up the rest.
--
Andrew Poelstra
http://www.wpsoftware.net/andrew
a=(a+b > limit) ? limit-b : a;
This doesn't seem right: for example if a=5 b=600 limit=500
In your case answer is equal to -100, which shouldn't happen since
answer must be >= 0.
> /* you haven't specified your other cases. What do we do if one or
> both are negative?*/
It should terminate (goto end; statement) for example by calling
exit().
This doesn't trap overflow or negative values...
> The rest of your code does things you didn't specify, and
> it's not clear where 'end' goes to, so I can't tell how to
> clean up the rest.
'end' goes to "exit(1);" for example. Otherwise 'a' is used to compute
new values.
> I have the following requierement: 3 ints (a, b, limit). The sum of
> 'a' and 'b' shouldn't be bigger than limit otherwise 'a' should be
> adjusted so that the sum of 'a' and 'b' is equal to 'limit'.
>
> Basically this can be written in C like this:
>
> int a, b, limit;
>
> /* some code that setup the 3 variables */
>
> if (a < 0 || b < 0)
> goto end;
> if (a + b > b) /* test for overflow (correct with GCC but not
> portable) */
Presumably you meant a + b < b in this test (still bad because
it relies on GCC overflow behavior, but this test is the one
I think you meant).
> goto end;
> if (a + b > limit)
> a -= a + b - limit;
> if (a < 0)
> goto end;
>
> /* ... */
>
> So this should work (ok this uses an undefined behaviour but this code
> is only intended to be compiled by GCC) but it looks quite
> complicated.
>
> Can anybody think to something more 'elegant' ?
if( a<0 || b<0 || limit<b ) goto end;
if( a > limit - b ) a = limit - b;
/* Here a >= 0, b >= 0, a+b <= limit */
Where is there overflow to be trapped?
For negative values, use:
if(a > limit - b)
a = limit - b;
if(a < 0 || b < 0 || limit < 0)
exit(1);
>> The rest of your code does things you didn't specify, and
>> it's not clear where 'end' goes to, so I can't tell how to
>> clean up the rest.
>
> 'end' goes to "exit(1);" for example. Otherwise 'a' is used to compute
> new values.
Given these specifications, the above two conditionals should
be sufficient.
There seem to be more criteria, e.g. a and b are non-negative.
> > Basically this can be written in C like this:
<snip>
> > Can anybody think to something more 'elegant' ?
>
> if( a<0 || b<0 || limit<b ) goto end;
> if( a > limit - b ) a = limit - b;
> /* Here a >= 0, b >= 0, a+b <= limit */
The purely general case is...
if (b < 0)
{
if (limit <= INT_MAX + b)
if (limit - b < a)
a = limit - b;
else
{
if (limit < INT_MIN + b)
goto end; /* a needs to be < INT_MIN : ERROR! */
if (limit - b < a)
a = limit - b;
}
--
Peter
Why can't we make it as 'if (a+b > limit)' ?
> /* Here a >= 0, b >= 0, a+b <= limit */
--
Mark
Because a + b can overflow, whereas limit - b can't if
they're all non-negative.
--
Peter
But you implicitly check 'b' for being negative:
if (b < 0)
{
if (limit <= INT_MAX + b)
if (limit - b < a)
.. then here 'b' is already negative?
--
Mark
Tim's code checked that a, b, and limit were non-negative.
My code allows a, b, and limit to have any int range value,
although it flags the case where the new value for a would
be outside the range of int.
--
Peter
Hm.. I still can't get it right. Below why there is no check for 'a' being
negative or non-negative?
> The purely general case is...
>
> if (b < 0)
> {
> if (limit <= INT_MAX + b)
Here you check 'limit' and make sure it doesn't overflow? But it doesn't
guarantee limit is non-negative. So 'limi-t-b < a' can be as well overflow..
> if (limit - b < a)
> a = limit - b;
> else
> {
> if (limit < INT_MIN + b)
> goto end; /* a needs to be < INT_MIN : ERROR! */
> if (limit - b < a)
> a = limit - b;
> }
PS. What is the idiom to check sum/subtraction for overflow?
--
Mark
Check the specification above. The only adjustment allowed is to a, and there
was no prohibition against negative numbers. If you want something different,
fix the specification.
--
Thad
Well when using unsigned type, the following code should work and
should be portable:
unsigned a, b;
if (a + b < b)
goto overflow;
But when using signed type, I can't think of something portable
anymore.
For the reason that Peter Nilsson explained in his response.
> Tim Rentsch <t...@x-alumni2.alumni.caltech.edu> wrote:
>> Francis Moreau <francis.m...@gmail.com> writes:
>> > I have the following requierement: 3 ints (a, b, limit).
>> > The sum of 'a' and 'b' shouldn't be bigger than limit
>> > otherwise 'a' should be adjusted so that the sum of 'a'
>> > and 'b' is equal to 'limit'.
>
> There seem to be more criteria, e.g. a and b are non-negative.
Yes, and also another one...
>> > Basically this can be written in C like this:
> <snip>
This '<snip>' unfortunately removed some relevant context.
>> > Can anybody think to something more 'elegant' ?
>>
>> if( a<0 || b<0 || limit<b ) goto end;
>> if( a > limit - b ) a = limit - b;
>> /* Here a >= 0, b >= 0, a+b <= limit */
>
> The purely general case is...
>
> if (b < 0)
> {
> if (limit <= INT_MAX + b)
> if (limit - b < a)
> a = limit - b;
> else
> {
> if (limit < INT_MIN + b)
> goto end; /* a needs to be < INT_MIN : ERROR! */
> if (limit - b < a)
> a = limit - b;
> }
I believe this code misses a case given implicitly in the earlier
example code.
Here is that context again, with one interspersed line highlight:
>restored> Francis Moreau <franci...@gmail.com> writes:
>restored>
>restored> > I have the following requierement: 3 ints (a, b, limit). The sum of
>restored> > 'a' and 'b' shouldn't be bigger than limit otherwise 'a' should be
>restored> > adjusted so that the sum of 'a' and 'b' is equal to 'limit'.
>restored> >
>restored> > Basically this can be written in C like this:
>restored> >
>restored> > int a, b, limit;
>restored> >
>restored> > /* some code that setup the 3 variables */
>restored> >
>restored> > if (a < 0 || b < 0)
>restored> > goto end;
>restored> > if (a + b > b) /* test for overflow (correct with GCC but not
>restored> > portable) */
>restored>
>restored> Presumably you meant a + b < b in this test (still bad because
>restored> it relies on GCC overflow behavior, but this test is the one
>restored> I think you meant).
>restored>
>restored> > goto end;
>restored> > if (a + b > limit)
>restored> > a -= a + b - limit;
>restored> > if (a < 0)
>restored> > goto end;
********** ^^^^^^^^^^^^^ NOTE THESE LAST TWO LINES.
>restored> >
>restored> > /* ... */
>restored> >
>restored> > So this should work (ok this uses an undefined behaviour but this code
>restored> > is only intended to be compiled by GCC) but it looks quite
>restored> > complicated.
>restored> >
>restored> > Can anybody think to something more 'elegant' ?
>restored>
>restored> if( a<0 || b<0 || limit<b ) goto end;
>restored> if( a > limit - b ) a = limit - b;
>restored> /* Here a >= 0, b >= 0, a+b <= limit */
The highlighted lines show some sort of expectation that OP
wants to adjust 'a' only if it's possible to preserve the
condtion a >= 0. Since that's what OP was looking for, that's
what I did in my response example -- the same adjustments, the
same conditions of 'goto end' as the original (the 'limit<b'
in my code corresponds to the 'a < 0' case in the original).
The "purely general" case you suggest may be "better" functionality
but I think it doesn't correspond to the example code given with the
original question.
So it is guaranteed by the C standard that in case of overfllow the result
of sum will be less then either operand?
> But when using signed type, I can't think of something portable
> anymore.
--
Mark
> So it is guaranteed by the C standard that in case of overfllow the result
> of sum will be less then either operand?
Addition of unsigned numbers is well-defined by the C Standard for any
input values; if the mathematical sum of a and b is greater than
UINT_MAX then the result is the mathematical sum (a + b - (UINT_MAX +
1)), which can easily be shown to be less than b in all cases (and
also less than a).
It isn't called "overflow" because the addition will produce the
result as it is defined - the "+" operator for unsigned integers isn't
defined to calculate the sum, but the sum modulo (UINT_MAX + 1) and
that result can always be produced. The "+" operator for signed
integers is defined to produce the mathematical sum. But sometimes it
is impossible to produce that result, and that is called "overflow".
When an overflow happens, nothing is guaranteed. It is undefined
behaviour; anything can happen.
There's no idiom since people don't do it that often.
But observe the maths...
INT_MIN <= a + b <= INT_MAX
<=> INT_MIN - b <= a <= INT_MAX - b
So, for signed integers...
/* summation overflow */
if (b < 0) { if (a < INT_MIN - b) overflow(); }
else { if (INT_MAX - b < a) overflow(); }
/* subraction overflow */
if (b < 0) { if (INT_MAX + b < a) overflow(); }
else { if (a < INT_MIN + b) overflow(); }
> > Well when using unsigned type, the following code should
> > work and should be portable:
> >
> > unsigned a, b;
> >
> > if (a + b < b)
> > goto overflow;
>
> So it is guaranteed by the C standard that in case of
> overfllow the result of sum will be less then either
> operand?
There is no overflow of unsigned types with a rank of int
or above. [Lower ranks may promote to int in which case
overflow is possible.] But the quoted range check works by
virtue of modulo arithmetic necessary for unsigned int.
It's really quite simple to see. Consider a + b mod 2^n.
Now what non-negative number b would you need to add to a
to make the result larger than a (modulo 2^n)?
--
Peter
I've not worked on a one's-complement machine since before there
was a C language, but I wonder how they work here. Perhaps
UINT_MAX on such a machine is *two* less than a power-of-two,
rather than *one* less, which would impact the cute number-of-bits
extractor discussed here a year ago. :-(
> It isn't called "overflow" because ...
Yes. But it's certainly understandable why *some* might *call*
it overflow. Kudos to Christian who explained this,
rather than just snapping at a "non-compliant usage"
and leaving new c.l.c'ers confused. :-)
<just another useless factoid>
The IBM 370/145 did unsigned arithmetic ("logical arithmetic")
*much* faster than it did signed arithmetic! The data results
are *identical* and both operations set the condition code,
but the condition-code spec for the signed arithmetic
required a microcode detour that took longer than the addition
itself!
Since often one doesn't care about condition code, use of
the logical ops could have sped up some code. No idea if
any programmers were masochisto-perfectionistic enough to
worry about this....
</just another useless factoid>
James Dow Allen
> On Mar 4, 8:01 am, "christian.bau" <christian....@cbau.wanadoo.co.uk>
> wrote:
>> Addition of unsigned numbers is well-defined by the C Standard for any
>> input values; if the mathematical sum of a and b is greater than
>> UINT_MAX then the result is the mathematical sum (a + b - (UINT_MAX +
>> 1)), which can easily be shown to be less than b in all cases (and
>> also less than a).
>
> I've not worked on a one's-complement machine since before there
> was a C language, but I wonder how they work here. Perhaps
> UINT_MAX on such a machine is *two* less than a power-of-two,
> rather than *one* less, which would impact the cute number-of-bits
> extractor discussed here a year ago. :-(
I don't see the issue. All machines that run standard C must use the
same pure binary representation for unsigned ints. The different
signed reps. have no obvious connection to the problem. Is there a
hardware issue you know of to do with implementing full-width pure
binary unsigned ints on a 1's complement system?
Also, unsigned into must be able to hold all the positive values of
signed ints so, if there is an issue, the two-bits shorter solution
is not available.
<snip>
--
Ben.
No.
(UINT_MAX + 1 == 0) is true
regardless of how negative integers are represented.
--
pete
Yes, I see the smiley, but I'm not sure how much of the
paragraph it applies to. Just in case: *unsigned* integers
do not use two's complement, or ones' complement, or signed
magnitude, all of which are schemes for encoding negative
values. Since unsigned integers cannot have negative values,
the question of how to represent them never arises.
An unsigned integer is represented by some number of value
bits and some number of padding bits (often none at all). The
maximum value is encoded by setting all the value bits to one,
hence that value is necessarily one less than a power of two.
It cannot be two less than a power of two, not never.
We return you now to the usual jesting and hijinks.
--
Eric Sosman
eso...@ieee-dot-org.invalid
I see three responses implying I'm nuts. I wonder if they're
from three people who've never worked with 1's-complement
machines.
Just to be clear, on the one and only one's-complement
machine I've used, there was no special opcode(s) for
*unsigned* integers. And, (pretending for simplicity
that that machine had 16-bit ints) when you added 0xFFFE
to 0x0001 the result was 0x0000. (If you added 0xffff
and 0x0001 the result was 0x0001.) AFAIK there would only
be two conceivable ways to implement a C compiler
on that machine: EITHER make UINT_MAX == 0xfffe OR
every unsigned arithmetic op would require a special
sequence involving tests and multiple machine ops.
I'm guessing the former, but that this got overlooked
in the subthread from a year ago: "Is {U,}{INT,LONG}_MAX
always 1 less than a power-of-two?"
Too bad Dik is no longer with us. Obviously he knew
this stuff like an eagle knows how to fly.
Am I wrong? Is there such a thing as 1's-complement
where 0xffff is *not* "negative zero"?
Note that, if my guess is correct, Pete's response
> No.
> (UINT_MAX + 1 == 0) is true
> regardless of how negative integers are represented.
becomes correct if we simply replace "No." with "Yes."
James Dow Allen
ISO/IEC 9899:1999 (E)
6.2.5 Types
9
A computation involving unsigned operands can never overflow,
because a result that cannot be represented by the resulting
unsigned integer type is reduced modulo the number that is
one greater than the largest value
that can be represented by the resulting type.
--
pete
The machine I speak of is the CDC-6{4,5,6}00 with 60-bit
words. Actually, there was another set of opcodes
called "Double Precision Floating Point" opcodes, but which
could also be used for, effectively, unsigned arithmetic.
I *think* only 48-bit results (plus a carry bit) could be
developed. Could C for that machine possibly have had
60-bit signed longs and 48-bit unsigned ints?
Ben and Eric are each correct well over 99% of the time,
so I'm probably going to end up embarrassed by my
outburst. :-(
I'll blame it all on creeping senility: Obviously I wasn't
that stupid 1 year ago, or I would have brought this up
in the "MAX always one less than power-of-two" thread. :-)
James
Yes. Everything you've written is compatible with BOTH
possibilities I've raised except for the single word "No"
in your first response which becomes "Yes" in the peculiar
variation I've outlined. (Note that the "modulo"
you mention would then be *1 less than a power-of-two*!)
If my perspective is still unclear, know this: I'm far
more interested in the behaviour of the C compiler on a
Real Machine with 1's-complement arithmetic than
I am in the specific diction of an ISO document.
As I imply in my recent post, I'm starting to guess the
CDC 6{4,5,6}00 used 48-bit unsigned ints that behaved
as normal 2's-complement integers behave, and special
coding for unsigned longs, if any, of some larger size.
James
> On Mar 4, 8:19 pm, pete <pfil...@mindspring.com> wrote:
>> James Dow Allen wrote:
>> > I've not worked on a one's-complement machine since before there
>> > was a C language, but I wonder how they work here. Perhaps
>> > UINT_MAX on such a machine is *two* less than a power-of-two,
>> > rather than *one* less, which would impact the cute number-of-bits
>> > extractor discussed here a year ago. :-(
>>
>> No.
>> (UINT_MAX + 1 == 0) is true
>> regardless of how negative integers are represented.
>
> I see three responses implying I'm nuts. I wonder if they're
> from three people who've never worked with 1's-complement
> machines.
>
> Just to be clear, on the one and only one's-complement
> machine I've used, there was no special opcode(s) for
> *unsigned* integers. And, (pretending for simplicity
> that that machine had 16-bit ints) when you added 0xFFFE
> to 0x0001 the result was 0x0000. (If you added 0xffff
> and 0x0001 the result was 0x0001.) AFAIK there would only
> be two conceivable ways to implement a C compiler
> on that machine: EITHER make UINT_MAX == 0xfffe OR
> every unsigned arithmetic op would require a special
> sequence involving tests and multiple machine ops.
That doesn't matter, because the Standard requires
unsigned types with N value bits to represent all
values between 0 and 2**N - 1.
> I'm guessing the former, but that this got overlooked
> in the subthread from a year ago: "Is {U,}{INT,LONG}_MAX
> always 1 less than a power-of-two?"
Yes.
(Honesty in advertsing: some people have argued that
the signed maximums INT_MAX or LONG_MAX don't have to
be one less than a power of two. I disagree. However,
about the unsigned types the Standard is quite clear,
and as far as I know there is no disagreement there.)
(1) Not "nuts," just "mistaken." (2) I've worked with a
ones' complement machine, although only briefly and not in C.
> Just to be clear, on the one and only one's-complement
> machine I've used, there was no special opcode(s) for
> *unsigned* integers. And, (pretending for simplicity
> that that machine had 16-bit ints) when you added 0xFFFE
> to 0x0001 the result was 0x0000. (If you added 0xffff
> and 0x0001 the result was 0x0001.) AFAIK there would only
> be two conceivable ways to implement a C compiler
> on that machine: EITHER make UINT_MAX == 0xfffe OR
> every unsigned arithmetic op would require a special
> sequence involving tests and multiple machine ops.
6.2.6.2p1: "For unsigned integer types [...] objects of
that type shall be capable of representing values from 0 to
2^N - 1 using a pure binary representation [...]"
An implementation might need to jump through hoops to
make this happen on unfriendly hardware, just as implementations
on word-addressed machines must jump through hoops to use
pointers to smaller-than-word types. That's the implementation's
problem, and the implementation's duty.
> I'm guessing the former, but that this got overlooked
> in the subthread from a year ago: "Is {U,}{INT,LONG}_MAX
> always 1 less than a power-of-two?"
>
> Too bad Dik is no longer with us. Obviously he knew
> this stuff like an eagle knows how to fly.
>
> Am I wrong? Is there such a thing as 1's-complement
> where 0xffff is *not* "negative zero"?
There could be a machine for which that bit pattern would
be a trap representation (for a signed integer), with no value
at all. If it's not a trap, though, it's negative zero on a
ones' complement machine.
... which makes no nevermind for *unsigned* types, which
do not encode a sign at all, not with any of the schemes that
are used for signed integers, nor with any other scheme.
--
Eric Sosman
eso...@ieee-dot-org.invalid
> On Mar 4, 9:37 pm, James Dow Allen <jdallen2...@yahoo.com> wrote:
>> Just to be clear, on the one and only one's-complement
>> machine I've used, there was no special opcode(s) for
>> *unsigned* integers. And, (pretending for simplicity
>> that that machine had 16-bit ints) when you added 0xFFFE
>> to 0x0001 the result was 0x0000....
These machines had very limited integer arithmetic on 60-bit fixed
point numbers. There was (if I am not mistaken) no multiply or divide
for example.
C on a CDC would have other problems. All the ones I know of have 6
bit characters and at least 8 are required for C. There is no byte
addressing so the compiler would have to emulate (a) wider characters,
(b) unsigned arithmetic, (c) integer multiply, divide and remainder
(if it opted to use the 60-bit number format) as well as (d) void *
and char *.
(a) and (d) can be solved by the very clumsy expedient of having
60-bit characters but, given the storage limits these machines had, no
one would do that.
> The machine I speak of is the CDC-6{4,5,6}00 with 60-bit
> words. Actually, there was another set of opcodes
> called "Double Precision Floating Point" opcodes, but which
> could also be used for, effectively, unsigned arithmetic.
> I *think* only 48-bit results (plus a carry bit) could be
> developed. Could C for that machine possibly have had
> 60-bit signed longs and 48-bit unsigned ints?
You'd still have a problem with unsigned long. For every signed type
there must be an unsigned type with at least as many value bits.
<snip>
--
Ben.
Thanks, Peter and Christian. Indeed it's simple. Sometimes the most obvious
solution is on a surface, but one would look it up beneath the surface :)
--
Mark
>No idea if
>any programmers were masochisto-perfectionistic enough to
>worry about this....
></just another useless factoid>
for me all that it is sloppy
who write C or C++ programs, he/she write for definition sloppy programs
programs that can not be 100% correct on every input they could have.
For example the replace() functions of some thread above is 99% of the times
[all the times that i see them] are sloppy for index overflow,
and for stack overflow, i not want to speak for called
library routines too (that someone suggest not use).
Yes i not have 100% the evidence that these function are sloppy
peraps it is wrong to think in that way so "perfectionistic"
and the error is in my mind that see all
these impossible overflow: possible.