views:

777

answers:

7

What is the single most effective practice to prevent arithmetic overflow and underflow?

Some examples that come to mind are:

  • testing based on valid input ranges
  • validation using formal methods
  • use of invariants
  • detection at runtime using language features or libraries (this does not prevent it)
+3  A: 

One possibility is to use a language that has arbitrarily sized integers that never overflow / underflow.

Otherwise, if this is something you're really concerned about, and if your language allows it, write a wrapper class that acts like an integer, but checks every operation for overflow. You could even have it do the check on debug builds, and leave things optimized for release builds. In a language like C++, you could do this, and it would behave almost exactly like an integer for release builds, but for debug builds you'd get full run-time checking.

class CheckedInt
{
private: 
    int Value;

public:
    // Constructor
    CheckedInt(int src) : Value(src) {}

    // Conversions back to int
    operator int&() { return Value; }
    operator const int &() const { return Value; }

    // Operators
    CheckedInt operator+(CheckedInt rhs) const
    {
        if (rhs.Value < 0 && rhs.Value + Value > Value)
            throw OverflowException();
        if (rhs.Value > 0 && rhs.Value + Value < Value)
            throw OverflowException();
        return CheckedInt(rhs.Value + Value);
    }

    // Lots more operators...
};

Edit:

Turns out someone is doing this already for C++ - the current implementation is focused for Visual Studio, but it looks like they're getting support for gcc as well.

Eclipse
+1  A: 

I write a lot of test code to do range/validity checking on my code. This tends to catch most of these types of situations - and definitely helps me write more bulletproof code.

itsmatt
+1  A: 

Use high precision floating point numbers like a long double.

postfuturist
Floating point (with any precision) introduces an even harder class of issues, namely loss of precision. I.e. `(x+1.0)-x != 1`. Using `long double` merely reduces the frequency and the magnitude.
MSalters
+1  A: 

I think you are missing one very important option in your list: choose the right programming language for the job. There are many programming languages which do not have these problems, because they don't have fixed size integers.

Jörg W Mittag
A: 

There are more important considerations when choosing which language you use than the size of the integer. Simply check your input if you don't know if the value is in bounds, or use exception handling if the case is extremely rare.

pro3carp3
A: 

Was just testing something, good answer though

A: 

A wrapper that checks for inconsistencies will make sense in many cases. If an additive operation (ie, addition or multiplication) on two or more integers results in a smaller value than the operands then you know something went wrong. Every additive operation should be followed by,

if (sum < operand1 || sum < operand2)
    omg_error();

Likewise any operation that should logically result in a smaller value should be check to see if it was accidentally embiggin'd.