Is there a better way to achieve this ?

F

Francis Moreau

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
 
M

Malcolm McLean

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;
}
 
A

Andrew Poelstra

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

CarlosB

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

CarlosB

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

Francis Moreau

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().
 
F

Francis Moreau

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

Tim Rentsch

Francis Moreau said:
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 */
 
A

Andrew Poelstra

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);
'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.
 
P

Peter Nilsson

There seem to be more criteria, e.g. a and b are non-negative.
    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;
}
 
M

Mark

Peter said:
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?
 
P

Peter Nilsson

Mark said:
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.
 
M

Mark

Peter said:
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?
 
T

Thad Smith

Francis said:
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.
 
F

Francis Moreau

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

Tim Rentsch

Peter Nilsson said:
There seem to be more criteria, e.g. a and b are non-negative.

Yes, and also another one...

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

Mark

Francis said:
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?
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top