For rounding to the nearest integer, we're only interested in the remainder if it is larger than half of the numerator. In other words; we're only interested in the decimal part if it's greater or equal to 0.5. We don't even need to know the value of the decimal part. We only need to know if it is greater or equal to 0.5. The modulo operation is expensive, so an alternative would be to multiply the numerator by 2 before doing the integer division. Or to left-shift it by 1, which is quicker, but gcc does that substitution for you.
After this division, the least-significant bit will contain the remaining 0.5. All you need to do is to add that to the result after shifting it back.
Below a code example, to make it more visual:
unsigned int uintdiv1(unsigned int numerator, unsigned int denominator)
{
unsigned int div;
div = (numerator << 1) / denominator;
if (div & 1)
return (div >> 1) + 1;
return (div >> 1);
}
This version might be a bit quicker, and can be converted to a macro more easily:
unsigned int uintdiv2(unsigned int numerator, unsigned int denominator)
{
unsigned int div;
div = (numerator << 1) / denominator;
div += (div & 1) << 1;
return (div >> 1);
}
These examples work for unsigned integers, but you requested a solution for signed integers. That makes things a little more complicated, but not much.
If the result is negative, the default rounding already works in our favor. So we only need to test if the result is expected to be positive, and add the remaining 0.5 only if that's the case.
Again a code example, to make it more visual:
int intdiv1(int numerator, int denominator)
{
int div;
div = (numerator << 1) / denominator;
if (!((numerator < 0) ^ (denominator < 0)) && (div & 1))
return (div >> 1) + 1;
return (div >> 1);
}
The really brave among us, could write it like this, but I wouldn't recommend it, as it may produce unexpected result with non-gcc compilers:
int intdiv2(int numerator, int denominator)
{
int div;
div = (numerator << 1) / denominator;
div += (!((numerator < 0) ^ (denominator < 0)) && (div & 1)) << 1;
return (div >> 1);
}
This algorithm could be implemented in a macro, which is more versatile, because macros are handled by the preprocessor and are type agnostic.
#define INTDIV(n, d) (((((n) << 1) / (d)) + ((!(((n) < 0) ^ ((d) < 0)) && ((((n) << 1) / (d)) & 1)) ? (1 << 1) : 0)) >> 1)
What you really need to be aware of, is that the implementations above do not deal with overflow errors. If you plug in a very large number, and it is multiplied by 2, it may overflow, causing all kinds of havoc. This can be mitigated to some extend by using 64-bit arithmetic when using the macro:
#include <stdint.h>
int result = INTDIV((uint64_t)n, d);
And finally the proof that it works:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define INTDIV(n, d) (((((n) << 1) / (d)) + ((!(((n) < 0) ^ ((d) < 0)) && ((((n) << 1) / (d)) & 1)) ? (1 << 1) : 0)) >> 1)
static unsigned int uintdiv1(unsigned int numerator, unsigned int denominator)
{
unsigned int div;
div = (numerator << 1) / denominator;
if (div & 1)
return (div >> 1) + 1;
return (div >> 1);
}
static unsigned int uintdiv2(unsigned int numerator, unsigned int denominator)
{
unsigned int div;
div = (numerator << 1) / denominator;
div += (div & 1) << 1;
return (div >> 1);
}
static int intdiv1(int numerator, int denominator)
{
int div;
div = (numerator << 1) / denominator;
if (!((numerator < 0) ^ (denominator < 0)) && (div & 1))
return (div >> 1) + 1;
return (div >> 1);
}
static int intdiv2(int numerator, int denominator)
{
int div;
div = (numerator << 1) / denominator;
div += (!((numerator < 0) ^ (denominator < 0)) && (div & 1)) << 1;
return (div >> 1);
}
static void pruintdiv1(unsigned int numerator, unsigned int denominator)
{
unsigned int expected = roundf((float)numerator / denominator);
unsigned int result = uintdiv1(numerator, denominator);
printf("%u / %u = %u, uintdiv1(%u, %u) = %u%s\n", numerator, denominator, expected, numerator, denominator, result, (result != expected) ? " ERROR!" : "");
}
static void pruintdiv2(unsigned int numerator, unsigned int denominator)
{
unsigned int expected = roundf((float)numerator / denominator);
unsigned int result = uintdiv2(numerator, denominator);
printf("%u / %u = %u, uintdiv2(%u, %u) = %u%s\n", numerator, denominator, expected, numerator, denominator, result, (result != expected) ? " ERROR!" : "");
}
static void printdiv1(int numerator, int denominator)
{
int expected = roundf((float)numerator / denominator);
int result = intdiv1(numerator, denominator);
printf("%d / %d = %d, intdiv1(%d, %d) = %d%s\n", numerator, denominator, expected, numerator, denominator, result, (result != expected) ? " ERROR!" : "");
}
static void printdiv2(int numerator, int denominator)
{
int expected = roundf((float)numerator / denominator);
int result = intdiv2(numerator, denominator);
printf("%d / %d = %d, intdiv2(%d, %d) = %d%s\n", numerator, denominator, expected, numerator, denominator, result, (result != expected) ? " ERROR!" : "");
}
static void prINTDIV(int numerator, int denominator)
{
int expected = roundf((float)numerator / denominator);
int result = INTDIV(numerator, denominator);
printf("%d / %d = %d, INTDIV(%d, %d) = %d%s\n", numerator, denominator, expected, numerator, denominator, result, (result != expected) ? " ERROR!" : "");
}
int main(int argc, char* argv[])
{
pruintdiv1(57, 4);
pruintdiv1(58, 4);
pruintdiv1(59, 4);
pruintdiv1(60, 4);
pruintdiv1(61, 4);
pruintdiv1(62, 4);
printf("\n");
pruintdiv2(57, 4);
pruintdiv2(58, 4);
pruintdiv2(59, 4);
pruintdiv2(60, 4);
pruintdiv2(61, 4);
pruintdiv2(62, 4);
printf("\n");
printdiv1(57, 4);
printdiv1(58, 4);
printdiv1(59, 4);
printdiv1(60, 4);
printdiv1(61, 4);
printdiv1(62, 4);
printf("\n");
printdiv1(-57, 4);
printdiv1(-58, 4);
printdiv1(-59, 4);
printdiv1(-60, 4);
printdiv1(-61, 4);
printdiv1(-62, 4);
printf("\n");
printdiv1(57, -4);
printdiv1(58, -4);
printdiv1(59, -4);
printdiv1(60, -4);
printdiv1(61, -4);
printdiv1(62, -4);
printf("\n");
printdiv1(-57, -4);
printdiv1(-58, -4);
printdiv1(-59, -4);
printdiv1(-60, -4);
printdiv1(-61, -4);
printdiv1(-62, -4);
printf("\n");
printdiv2(57, 4);
printdiv2(58, 4);
printdiv2(59, 4);
printdiv2(60, 4);
printdiv2(61, 4);
printdiv2(62, 4);
printf("\n");
printdiv2(-57, 4);
printdiv2(-58, 4);
printdiv2(-59, 4);
printdiv2(-60, 4);
printdiv2(-61, 4);
printdiv2(-62, 4);
printf("\n");
printdiv2(57, -4);
printdiv2(58, -4);
printdiv2(59, -4);
printdiv2(60, -4);
printdiv2(61, -4);
printdiv2(62, -4);
printf("\n");
printdiv2(-57, -4);
printdiv2(-58, -4);
printdiv2(-59, -4);
printdiv2(-60, -4);
printdiv2(-61, -4);
printdiv2(-62, -4);
printf("\n");
prINTDIV(57, 4);
prINTDIV(58, 4);
prINTDIV(59, 4);
prINTDIV(60, 4);
prINTDIV(61, 4);
prINTDIV(62, 4);
printf("\n");
prINTDIV(-57, 4);
prINTDIV(-58, 4);
prINTDIV(-59, 4);
prINTDIV(-60, 4);
prINTDIV(-61, 4);
prINTDIV(-62, 4);
printf("\n");
prINTDIV(57, -4);
prINTDIV(58, -4);
prINTDIV(59, -4);
prINTDIV(60, -4);
prINTDIV(61, -4);
prINTDIV(62, -4);
printf("\n");
prINTDIV(-57, -4);
prINTDIV(-58, -4);
prINTDIV(-59, -4);
prINTDIV(-60, -4);
prINTDIV(-61, -4);
prINTDIV(-62, -4);
return EXIT_SUCCESS;
}
Build with:
$ gcc intdiv.c -Wall -pedantic -lm -o intdiv
And let her rip:
robert@prodesk:~/src/test/intdiv$ ./intdiv
57 / 4 = 14, uintdiv1(57, 4) = 14
58 / 4 = 15, uintdiv1(58, 4) = 15
59 / 4 = 15, uintdiv1(59, 4) = 15
60 / 4 = 15, uintdiv1(60, 4) = 15
61 / 4 = 15, uintdiv1(61, 4) = 15
62 / 4 = 16, uintdiv1(62, 4) = 16
57 / 4 = 14, uintdiv2(57, 4) = 14
58 / 4 = 15, uintdiv2(58, 4) = 15
59 / 4 = 15, uintdiv2(59, 4) = 15
60 / 4 = 15, uintdiv2(60, 4) = 15
61 / 4 = 15, uintdiv2(61, 4) = 15
62 / 4 = 16, uintdiv2(62, 4) = 16
57 / 4 = 14, intdiv1(57, 4) = 14
58 / 4 = 15, intdiv1(58, 4) = 15
59 / 4 = 15, intdiv1(59, 4) = 15
60 / 4 = 15, intdiv1(60, 4) = 15
61 / 4 = 15, intdiv1(61, 4) = 15
62 / 4 = 16, intdiv1(62, 4) = 16
-57 / 4 = -14, intdiv1(-57, 4) = -14
-58 / 4 = -15, intdiv1(-58, 4) = -15
-59 / 4 = -15, intdiv1(-59, 4) = -15
-60 / 4 = -15, intdiv1(-60, 4) = -15
-61 / 4 = -15, intdiv1(-61, 4) = -15
-62 / 4 = -16, intdiv1(-62, 4) = -16
57 / -4 = -14, intdiv1(57, -4) = -14
58 / -4 = -15, intdiv1(58, -4) = -15
59 / -4 = -15, intdiv1(59, -4) = -15
60 / -4 = -15, intdiv1(60, -4) = -15
61 / -4 = -15, intdiv1(61, -4) = -15
62 / -4 = -16, intdiv1(62, -4) = -16
-57 / -4 = 14, intdiv1(-57, -4) = 14
-58 / -4 = 15, intdiv1(-58, -4) = 15
-59 / -4 = 15, intdiv1(-59, -4) = 15
-60 / -4 = 15, intdiv1(-60, -4) = 15
-61 / -4 = 15, intdiv1(-61, -4) = 15
-62 / -4 = 16, intdiv1(-62, -4) = 16
57 / 4 = 14, intdiv2(57, 4) = 14
58 / 4 = 15, intdiv2(58, 4) = 15
59 / 4 = 15, intdiv2(59, 4) = 15
60 / 4 = 15, intdiv2(60, 4) = 15
61 / 4 = 15, intdiv2(61, 4) = 15
62 / 4 = 16, intdiv2(62, 4) = 16
-57 / 4 = -14, intdiv2(-57, 4) = -14
-58 / 4 = -15, intdiv2(-58, 4) = -15
-59 / 4 = -15, intdiv2(-59, 4) = -15
-60 / 4 = -15, intdiv2(-60, 4) = -15
-61 / 4 = -15, intdiv2(-61, 4) = -15
-62 / 4 = -16, intdiv2(-62, 4) = -16
57 / -4 = -14, intdiv2(57, -4) = -14
58 / -4 = -15, intdiv2(58, -4) = -15
59 / -4 = -15, intdiv2(59, -4) = -15
60 / -4 = -15, intdiv2(60, -4) = -15
61 / -4 = -15, intdiv2(61, -4) = -15
62 / -4 = -16, intdiv2(62, -4) = -16
-57 / -4 = 14, intdiv2(-57, -4) = 14
-58 / -4 = 15, intdiv2(-58, -4) = 15
-59 / -4 = 15, intdiv2(-59, -4) = 15
-60 / -4 = 15, intdiv2(-60, -4) = 15
-61 / -4 = 15, intdiv2(-61, -4) = 15
-62 / -4 = 16, intdiv2(-62, -4) = 16
57 / 4 = 14, INTDIV(57, 4) = 14
58 / 4 = 15, INTDIV(58, 4) = 15
59 / 4 = 15, INTDIV(59, 4) = 15
60 / 4 = 15, INTDIV(60, 4) = 15
61 / 4 = 15, INTDIV(61, 4) = 15
62 / 4 = 16, INTDIV(62, 4) = 16
-57 / 4 = -14, INTDIV(-57, 4) = -14
-58 / 4 = -15, INTDIV(-58, 4) = -15
-59 / 4 = -15, INTDIV(-59, 4) = -15
-60 / 4 = -15, INTDIV(-60, 4) = -15
-61 / 4 = -15, INTDIV(-61, 4) = -15
-62 / 4 = -16, INTDIV(-62, 4) = -16
57 / -4 = -14, INTDIV(57, -4) = -14
58 / -4 = -15, INTDIV(58, -4) = -15
59 / -4 = -15, INTDIV(59, -4) = -15
60 / -4 = -15, INTDIV(60, -4) = -15
61 / -4 = -15, INTDIV(61, -4) = -15
62 / -4 = -16, INTDIV(62, -4) = -16
-57 / -4 = 14, INTDIV(-57, -4) = 14
-58 / -4 = 15, INTDIV(-58, -4) = 15
-59 / -4 = 15, INTDIV(-59, -4) = 15
-60 / -4 = 15, INTDIV(-60, -4) = 15
-61 / -4 = 15, INTDIV(-61, -4) = 15
-62 / -4 = 16, INTDIV(-62, -4) = 16