# Is there a better way to achieve this ?

Discussion in 'C Programming' started by Francis Moreau, Mar 2, 2010.

1. ### Francis MoreauGuest

Hello,

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

Francis Moreau, Mar 2, 2010

2. ### Malcolm McLeanGuest

On Mar 2, 4:42 pm, Francis Moreau <> wrote:
> Hello,
>
> 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;

if(a >= 0 && b >= 0)
{
t = (unsigned) a + (unsigned) b;
if(t > limit)
else
}
/* you haven't specified your other cases. What do we do if one or
both are negative?*/
}

Malcolm McLean, Mar 2, 2010

3. ### Andrew PoelstraGuest

On 2010-03-02, Francis Moreau <> wrote:
> Hello,
>
> 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

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

Andrew Poelstra, Mar 2, 2010
4. ### CarlosBGuest

On Mar 2, 11:42 am, Francis Moreau <> wrote:
> Hello,
>
> 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

a=(a+b > limit) ? limit-b ? a;

CarlosB, Mar 2, 2010
5. ### CarlosBGuest

On Mar 2, 11:42 am, Francis Moreau <> wrote:
> Hello,
>
> 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

a=(a+b > limit) ? limit-b : a;

CarlosB, Mar 2, 2010
6. ### Francis MoreauGuest

On Mar 2, 3:53 pm, Malcolm McLean <>
wrote:
> On Mar 2, 4:42 pm, Francis Moreau <> wrote:
>
>
>
>
>
> > Hello,

>
> > 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;
>
>   if(a >= 0 && b >= 0)
>   {
>     t = (unsigned) a + (unsigned) b;
>     if(t > limit)
>       answer = limit - b;
>     else
>   }

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

>   /* 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().

Francis Moreau, Mar 2, 2010
7. ### Francis MoreauGuest

On Mar 2, 3:54 pm, Andrew Poelstra <>
wrote:
> On 2010-03-02, Francis Moreau <> wrote:
>
>
>
>
>
> > Hello,

>
> > 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

>
> I think:
>
>   if(a > limit - b)
>     a = limit - b;
>

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.

Francis Moreau, Mar 2, 2010
8. ### Tim RentschGuest

Francis Moreau <> 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'.
>
> 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 */

Tim Rentsch, Mar 2, 2010
9. ### Andrew PoelstraGuest

On 2010-03-02, Francis Moreau <> wrote:
> On Mar 2, 3:54 pm, Andrew Poelstra <>
> wrote:
>>
>> I think:
>>
>>   if(a > limit - b)
>>     a = limit - b;
>>

>
> This doesn't trap overflow or negative values...
>

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.

--
Andrew Poelstra
http://www.wpsoftware.net/andrew

Andrew Poelstra, Mar 2, 2010
10. ### Peter NilssonGuest

Tim Rentsch <> wrote:
> Francis Moreau <> 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.

> > 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

Peter Nilsson, Mar 2, 2010
11. ### MarkGuest

Tim Rentsch wrote:
[snip]
>> Can anybody think to something more 'elegant' ?

>
> if( a<0 || b<0 || limit<b ) goto end;
> if( a > limit - b ) a = limit - b;

Why can't we make it as 'if (a+b > limit)' ?

> /* Here a >= 0, b >= 0, a+b <= limit */

--
Mark

Mark, Mar 3, 2010
12. ### Peter NilssonGuest

On Mar 3, 11:48 am, "Mark" <> wrote:
> Tim Rentsch wrote:
> >    if(  a<0 || b<0 || limit<b  )  goto end;
> >    if(  a > limit - b  )  a = limit - b;

>
> Why can't we make it as 'if (a+b > limit)' ?

Because a + b can overflow, whereas limit - b can't if
they're all non-negative.

--
Peter

Peter Nilsson, Mar 3, 2010
13. ### MarkGuest

Peter Nilsson wrote:
> On Mar 3, 11:48 am, "Mark" <> wrote:
>> Tim Rentsch wrote:
>>> if( a<0 || b<0 || limit<b ) goto end;
>>> if( a > limit - b ) a = limit - b;

>>
>> Why can't we make it as 'if (a+b > limit)' ?

>
> Because a + b can overflow, whereas limit - b can't if
> they're all non-negative.

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

Mark, Mar 3, 2010
14. ### Peter NilssonGuest

"Mark" <> wrote:
> Peter Nilsson wrote:
> > "Mark" <> wrote:
> > > Tim Rentsch wrote:
> > > > if( a<0 || b<0 || limit<b ) goto end;
> > > > if( a > limit - b ) a = limit - b;
> > >
> > > Why can't we make it as 'if (a+b > limit)' ?

> >
> > Because a + b can overflow, whereas limit - b can't if
> > they're all non-negative.

>
> 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?

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

Peter Nilsson, Mar 3, 2010
15. ### MarkGuest

Peter Nilsson wrote:
> 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.

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

Mark, Mar 3, 2010

Francis Moreau wrote:
> On Mar 2, 3:53 pm, Malcolm McLean <>
> wrote:
>> On Mar 2, 4:42 pm, Francis Moreau <> wrote:
>>> 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;
>>
>> if(a >= 0 && b >= 0)
>> {
>> t = (unsigned) a + (unsigned) b;
>> if(t > limit)
>> answer = limit - b;
>> else
>> }

>
> 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.

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.

--

17. ### Francis MoreauGuest

On Mar 3, 5:13 am, "Mark" <> wrote:
>
> PS. What is the idiom to check sum/subtraction for overflow?
>

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.

Francis Moreau, Mar 3, 2010
18. ### Tim RentschGuest

"Mark" <> writes:

> Tim Rentsch wrote:
> [snip]
>>> Can anybody think to something more 'elegant' ?

>>
>> if( a<0 || b<0 || limit<b ) goto end;
>> if( a > limit - b ) a = limit - b;

>
> Why can't we make it as 'if (a+b > limit)' ?
>
>> /* Here a >= 0, b >= 0, a+b <= limit */

For the reason that Peter Nilsson explained in his response.

Tim Rentsch, Mar 3, 2010
19. ### Tim RentschGuest

Peter Nilsson <> writes:

> Tim Rentsch <> wrote:
>> Francis Moreau <> 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 <> 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.

Tim Rentsch, Mar 3, 2010
20. ### MarkGuest

Francis Moreau wrote:
>> PS. What is the idiom to check sum/subtraction for 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?

> But when using signed type, I can't think of something portable
> anymore.

--
Mark

Mark, Mar 3, 2010