Rounding Modes For Integer Division

This is a super quick blog post on how to get different rounding modes with integer division: floor to get an integer smaller than or equal to the real value, round to get the integer that closest to the real value, and ceiling to get an integer greater than or equal to the real value.

These operations are useful when you need to align memory allocations, calculate dispatch sizes for compute shaders, work with objects on a grid, and many other things.

Unsigned Integers

  • Floor: A / B
  • Round: (A+B/2) / B
  • Ceiling: (A+B-1) / B alternately: (A-1) / B+1 (thanks @clift_m!)
void RoundTest(unsigned int a, unsigned int b)
{
	printf("%i / %i = %0.2f\n", a, b, float(a) / float(b));
	printf("floor = %i\n", a / b);
	printf("round = %i\n", (a + b / 2) / b);
	printf("ceiling = %i\n\n", (a - 1) / b + 1);
}

Running the above with a couple different values:

Signed Integers

Here are routines that handle signed integers, and a testing program for them, courtesy of @insouris.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define N 30

static int div_floor(int a, int b) { return (a ^ b) < 0 && a ? (1 - abs(a)) / abs(b) - 1 : a / b; }
static int div_round(int a, int b) { return (a ^ b) < 0 ? (a - b / 2) / b : (a + b / 2) / b; }
static int div_ceil(int a, int b) { return (a ^ b) < 0 || !a ? a / b : (abs(a) - 1) / abs(b) + 1; }

int main()
{
    for (int a = -N; a <= N; a++) {
        for (int b = -N; b <= N; b++) {
            if (!b)
                continue;

            const float f = a / (float)b;

            const int ef = (int)floorf(f);
            const int er = (int)roundf(f); // X.5 to X+1, or -X.5 to -X
            const int ec = (int)ceilf(f);

            const int of = div_floor(a, b);
            const int orn = div_round(a, b);
            const int oc = div_ceil(a, b);

            const int df = ef != of;
            const int dr = er != orn;
            const int dc = ec != oc;

            if (df || dr || dc)
                fprintf(stderr, "%d/%d=%g%s\n", a, b, f, (a ^ b) < 0 ? " (diff sign)" : "");

            if (df) fprintf(stderr, "floor: %d != %d\n", of, ef);
            if (dr) fprintf(stderr, "round: %d != %d\n", orn, er);
            if (dc) fprintf(stderr, "ceil: %d != %d\n", oc, ec);
        }
    }
    return 0;
}


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s