Search code examples
c++cundefined-behaviorinteger-overflow

Is a safe accumulator really this complicated?


I'm trying to write an accumulator that is well behaved given unconstrained inputs. This seems to not be trivial and requires some pretty strict planning. Is it really this hard?

int naive_accumulator(unsigned int max,
                      unsigned int *accumulator,
                      unsigned int amount) {
    if(*accumulator + amount >= max) {
        return 1; // could overflow
    }

    *accumulator += max; // could overflow

    return 0;
}

int safe_accumulator(unsigned int max,
                     unsigned int *accumulator,
                     unsigned int amount) {
    // if amount >= max, then certainly *accumulator + amount >= max
    if(amount >= max) {
        return 1;
    }

    // based on the comparison above, max - amount is defined
    // but *accumulator + amount might not be
    if(*accumulator >= max - amount) {
        return 1;
    }

    // based on the comparison above, *accumulator + amount is defined
    // and *accumulator + amount < max
    *accumulator += amount;

    return 0;
}

EDIT: I have removed the style bias


Solution

  • Have you considered:

    if ( max - *accumulator < amount )
        return 1;
    
    *accumulator += amount;
    return 0;
    

    By changing the direction of your first comparison in the "naive" version you avoid overflows, i.e. see how much room is left (safe) and compare that against the amount to add (also safe).

    This version assumes that *accumulator never exceeds max already when the function is called; if you want to support that case then you'd have to add in an extra test.