Is there a better way to achieve this ?

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

  1. 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
    #1
    1. Advertising

  2. 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;
    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;
    }
     
    Malcolm McLean, Mar 2, 2010
    #2
    1. Advertising

  3. 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
    #3
  4. Francis Moreau

    CarlosB Guest

    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
    #4
  5. Francis Moreau

    CarlosB Guest

    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
  6. 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;
    >   int answer;
    >
    >   if(a >= 0 && b >= 0)
    >   {
    >     t = (unsigned) a + (unsigned) b;
    >     if(t > limit)
    >       answer = limit - b;
    >     else
    >       answer = 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().
     
    Francis Moreau, Mar 2, 2010
    #6
  7. 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
    #7
  8. Francis Moreau

    Tim Rentsch Guest

    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
    #8
  9. 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
    #9
  10. 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
    #10
  11. Francis Moreau

    Mark Guest

    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
    #11
  12. 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
    #12
  13. Francis Moreau

    Mark Guest

    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
    #13
  14. "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
    #14
  15. Francis Moreau

    Mark Guest

    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
    #15
  16. Francis Moreau

    Thad Smith Guest

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


    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
     
    Thad Smith, Mar 3, 2010
    #16
  17. 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
    #17
  18. Francis Moreau

    Tim Rentsch Guest

    "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
    #18
  19. Francis Moreau

    Tim Rentsch Guest

    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
    #19
  20. Francis Moreau

    Mark Guest

    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
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. E. Naubauer
    Replies:
    11
    Views:
    569
    Thomas Hawtin
    Jan 18, 2006
  2. Fendi Baba
    Replies:
    0
    Views:
    379
    Fendi Baba
    Oct 15, 2003
  3. Peter Bencsik
    Replies:
    2
    Views:
    878
  4. Replies:
    2
    Views:
    807
    Tris Orendorff
    May 16, 2007
  5. Paul Rubin
    Replies:
    5
    Views:
    440
    Hendrik van Rooyen
    Aug 6, 2009
Loading...

Share This Page