Saturating arithmetic issues with warnings

user1697083

I have to create two functions that add together unsigned/signed numbers. However, the compiler is giving me the following warnings, and the implementations don't seem to work correctly (as it stalls). I believe there might be an error in logic here, not something else that is semantic which is throwing me off. I am new to this and would appreciate any insight.

Warnings:

  • comparison is always false due to limited range of data type; // this is in the first function, comparison lines
  • large integer implicitly truncated to unsigned type; // again, first function, comparison lines
  • overflow in implicit constant conversion; // if statements in bottom function

Both functions take parameters a and b. Here is the unsigned one:

    unsigntype result = a + b;
    if (result < INT_MIN) result = INT_MIN;
    if (result > INT_MAX) result = INT_MAX;
    return result;

And the signed one:

    signtype result = a + b;
    signtype check = result;
    signtype position = 0;

    while (check >>= 0)
            position++; // get sig fig

    if ((1 << (position + 1)) && result != 0) {
            if ((a > 0 && b > 0)) return INT_MAX;
            return result;
    }

    if ((a < 0 && b < 0) && result > 0) return INT_MIN;
    return result;

EDIT: The typedefs you see here are placeholders that can be filled by any integer family type defined by a header file that is included.

ANOTHER EDIT: This controls which type should be used. Both functions have to be completely portable - can use bitwise operations.

#ifndef SAT_TYPE
#define SAT_TYPE 1
#endif

#if SAT_TYPE == 1
typedef signed char signtype;
typedef unsigned char unsigntype;
#define FMT "hh"
#elif SAT_TYPE == 2
typedef signed short signtype;
typedef unsigned short unsigntype;
#define FMT "h"
#elif SAT_TYPE == 3
typedef signed int signtype;
typedef unsigned int unsigntype;
#define FMT ""
Useless

In the unsigned case:

unsigntype result = a + b;
if (result < INT_MIN) result = INT_MIN;

INT_MIN is negative but an unsigned type can never be less than zero, so this test is indeed always false. In the next line

if (result > INT_MAX) result = INT_MAX;

you still haven't said what unsigntype is, but if it can't hold a value bigger than INT_MAX (for example, if it's an unsigned short or unsigned char) then this will also be always false. Ideally you should be using the correct max and min for your actual type, eg.

unsigned short add_ushort(unsigned short a, unsigned short b) {
  if (a > USHRT_MAX - b) return USHRT_MAX;
  return a+b;
}

Note that I'm ignoring the negative check, because that's impossible here (you didn't say what type a and b are, so I can't tell if they might be negative in your case), and I wrote an overflow check that actually works.


As for the signed case, I'm not even certain what you're trying to achieve. You have an infinite loop here:

while (check != 0)
        position++; // doesn't change check, so never exits

and the rest looks .. puzzling. Perhaps you could show the expected results for some inputs?


Now you've described the setup, I'd suggest defining the type-specific max/min values in your existing pre-processor code:

#if SAT_TYPE == 1
typedef signed char signtype;
typedef unsigned char unsigntype;
#define SIGN_MAX CHAR_MAX
#define SIGN_MIN CHAR_MIN
#define UNSIGN_MAX UCHAR_MAX
#define FMT "hh"
#else
/* ... */
#endif

unsigntype add_unsigned(unsigntype a, unsigntype b) {
  // NB. you need to check for overflow before adding:
  // after the sum has overflowed, it's too late
  if (a > UNSIGN_MAX - b) return UNSIGN_MAX;
  return a+b;
}

signtype add_signed(signtype a, signtype b) {
  if (b < 0 && a < SIGN_MIN - b) return SIGN_MIN;
  if (b > 0 && a > SIGN_MAX - b) return SIGN_MAX;
  return a+b;
}

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related