Rounding integer division (instead of truncating)
Asked Answered
Z

27

110

I was curious to know how I can round a number to the nearest whole number. For instance, if I had:

int a = 59 / 4;

which would be 14.75 if calculated in floating point; how can I store the result as 15 in "a"?

Zettazeugma answered 11/3, 2010 at 5:20 Comment(0)
L
60
int a = 59.0f / 4.0f + 0.5f;

This only works when assigning to an int as it discards anything after the '.'

Edit: This solution will only work in the simplest of cases. A more robust solution would be:

unsigned int round_closest(unsigned int dividend, unsigned int divisor)
{
    return (dividend + (divisor / 2)) / divisor;
}
Larghetto answered 11/3, 2010 at 5:23 Comment(17)
Note that this is FLOATING pointer solution. I recommend that you use integer operation for many reasons.Izzo
What problems? I've used this before and have never encountered a problem.Larghetto
Because on systems without a FPU, this makes really, really, bad code.Physiognomy
That makes perfect sense, however should this even compile for a target that cant support floating point?Larghetto
that's the problem. the OP's question is solvable without using any floating point at all, and so will not be dependent on FPU support being present or being good. also, faster (in the event that lots of these need to be calculated) on most architectures, including those with otherwise fantastic FPU support. also note that your solution could be problematic for larger numbers where floats cannot accurately represent the integer values given.Robbins
-1, this gives the wrong answer for many values when sizeof(int) >= sizeof(float). For example, a 32-bit float uses some bits to represent the exponent, and thus it cannot exactly represent every 32-bit int. So 12584491 / 3 = 4194830.333..., which should round down to 4194830, but, on my machine which cannot represent 12584491 exactly in a float, the above formula rounds up to 4194831, which is wrong. Using double is safer.Frustule
This doesn't make sense. Your float solution is rounding the number to its nearest integer, while the second one is returning the ceiling.Procurance
Ah Sorry. I adjusted the implementation to also round rather than ceilLarghetto
this doesn't work at all for negative numbers, try std::cout << "exact: " << (-8.0f / 2.0f) << std::endl; and std::cout << "rounded: " << (int) (-8.0f / 2.0f + 0.5f) << std::endl;. first -4 and rounded is -3. for negative you should -0.5 instead of 0.5Brindabrindell
@javapowered, yes. That's why the function only operates on unsigned ints.Larghetto
see @PauliusZ's answer for Linux's DIV_ROUND_CLOSEST macro, which uses GNU C typeof() to be safe with inputs like i++, and will work right for negative numbers when used with signed operands.Beachhead
Really the question is why you want to represent values like this as an integer type. double holds perfect integers up to 2^53 and allows you to easily specify how errors will be rounded.Photomontage
It should be noted that this is a rearrangement of some mathematics which intends to add 0.5 to the numerator. This has the effect of forcing any number that has a decimal part of 0.5 or greater, to instead have an integer part made 1 greater than it previously was. Adding denominator/2 to the numerator, results in 0.5 being added to the calculated number. This works also, for negative numbers as the denominators negative sign is cancelled upon division by itself.Otoole
@MalcolmMcLean I cannot speak to all cases, but there are environments which do now permit floating point operations. It is entirely impossible when programming in UEFI and difficult (to potentially unrecommended) in the Linux KernelIrmgard
Your edit nails it! However, I prefer the macro or gcc statement expression type-free form of integer division with rounding, so I wrote it up and described it in detail here: stackoverflow.com/questions/2422712/…Nelrsa
dividend + (divisor / 2) risks overflow, which is well defined for unsinged math, but we get the wrong answer.Overdye
int a = some_float_A / some_float_B + 0.5f; can fail when quotient + 0.5 is inexact. Try nextafterf(0.5f,0) / 1.0f + 0.5f.Overdye
S
179

The standard idiom for integer rounding up is:

int a = (59 + (4 - 1)) / 4;

You add the divisor minus one to the dividend.

Squama answered 11/3, 2010 at 5:23 Comment(12)
What if you want to perform a mathematical round (14.75 to 15, 14.25 to 14)?Kimkimball
Ugh...then you have to think...add (n - 1) / 2, more or less. For n == 4, you want x % n ∈ { 0, 1 } to round down, and x % n ∈ { 2, 3 } to round up. So, you need to add 2, which is n / 2. For n == 5, you want x % n ∈ { 0, 1, 2 } to round down, and x % n ∈ { 3, 4 } to round up, so you need to add 2 again...hence: int i = (x + (n / 2)) / n;?Squama
What about negative x and/or n?Jacobsen
@caf: work it out for yourself. Hint: int abs(int n); (from Standard C) and int signum(int n) { return (n < 0) ? -1 : (n > 0) ? +1 : 0; } might come in handy.Squama
@JonathanLeffler: Right, but it's starting to get surprisingly non-trivial - more so again if you also want to handle the case where x + n / 2 overflows...Jacobsen
This method works for positive int. But if the divisor or dividend is negative it produces an incorrect answer. The hint to @Jacobsen does not work either.Overdye
The (original) title and the question asked for two different things. The title said rounding up (which is what you've answered), but the body says round to nearest (which is what the accepted answer attempts).Frustule
Just beware that c = (INT_MAX + (4 - 1)) / 4; gives c = -536870911 due to integer overflow...Luciferase
For anyone looking to handle both positive and negative numbers, in either the numerator or denominator or both, and to round up (away from zero), down (towards zero) or to nearest, I just added all of this to my answer here.Nelrsa
This rounds UP. This rounds UP. This rounds UP. This rounds UP. This rounds UP. (Sorry for repeating this, but since the question's title has been changed after the answer was posted, this needs to be stated clearly.) THIS ROUNDS UP!Onshore
And the first line of the answer clearly states 'rounding up', @bers.Squama
@JonathanLeffler you are absolutely right. In my comment, I should not have said "clearly" but "visibly". Two letters are easily overlooked if the top-voted answer answers a question different from the actual question (again, not your fault).Onshore
S
72

A code that works for any sign in dividend and divisor:

int divRoundClosest(const int n, const int d)
{
  return ((n < 0) == (d < 0)) ? ((n + d/2)/d) : ((n - d/2)/d);
}

In response to a comment "Why is this actually working?", we can break this apart. First, observe that n/d would be the quotient, but it is truncated towards zero, not rounded. You get a rounded result if you add half of the denominator to the numerator before dividing, but only if numerator and denominator have the same sign. If the signs differ, you must subtract half of the denominator before dividing. Putting all that together:

  1. (n < 0) is false (0) if n is non-negative
  2. (d < 0) is false (0) if d is non-negative
  3. ((n < 0) == (d < 0)) is true if n and d have the same sign
  4. (n + d/2)/d is the rounded quotient when n and d have the same sign
  5. (n - d/2)/d is the rounded quotient when n and d have opposite signs

If you prefer a macro:

#define DIV_ROUND_CLOSEST(n, d) ((((n) < 0) == ((d) < 0)) ? (((n) + (d)/2)/(d)) : (((n) - (d)/2)/(d)))

The linux kernel DIV_ROUND_CLOSEST macro doesn't work for negative divisors!

Statis answered 5/8, 2013 at 20:38 Comment(12)
Aside from int values near min/max int, this is the best solution so far.Overdye
Why is this actually working? What´s the mathematical concept behind this?Prentiss
@TobiasMarschall This is equivalent to floor(n / d + 0.5), where n and d are floats.Karelian
The code in the edit doesn't work. divRoundClosest(1, 5) is equal to 1.Kalidasa
Hi @Michael. Maybe you should move the EDIT you added here to a separate answer, so comments regarding that specific code can be discussed separately.Statis
That's typically the kind of function that begs for constexpr-ness. And that would remove the need for a macro version.Eyeleteer
I've rolled back @Micheal's answer because it doesn't work. For that version, divRoundClosest(1, 5) results in 1, as mentioned above, and even divRoundClosest(0, 5) results in 1!Huckaby
Please use != for logical exclusive-OR. ^ is meant for bitwise only. This would make your code more readable. ((n < 0) != (d < 0))Roomette
n + d/2 risks overflow.Overdye
@Roomette Using == is even easier to read: (n < 0) == (d < 0) and then reverse the later operations.Overdye
@Roomette and chux, thanks for the suggestions. Code updated.Statis
For anyone needing it, I added macros, statement expressions, and templates for rounding up (away from zero), down (towards zero) or to nearest to my answer here. It handles both positive and negative numerators and denominators (or both negative at the same time) as well, like this answer.Nelrsa
L
60
int a = 59.0f / 4.0f + 0.5f;

This only works when assigning to an int as it discards anything after the '.'

Edit: This solution will only work in the simplest of cases. A more robust solution would be:

unsigned int round_closest(unsigned int dividend, unsigned int divisor)
{
    return (dividend + (divisor / 2)) / divisor;
}
Larghetto answered 11/3, 2010 at 5:23 Comment(17)
Note that this is FLOATING pointer solution. I recommend that you use integer operation for many reasons.Izzo
What problems? I've used this before and have never encountered a problem.Larghetto
Because on systems without a FPU, this makes really, really, bad code.Physiognomy
That makes perfect sense, however should this even compile for a target that cant support floating point?Larghetto
that's the problem. the OP's question is solvable without using any floating point at all, and so will not be dependent on FPU support being present or being good. also, faster (in the event that lots of these need to be calculated) on most architectures, including those with otherwise fantastic FPU support. also note that your solution could be problematic for larger numbers where floats cannot accurately represent the integer values given.Robbins
-1, this gives the wrong answer for many values when sizeof(int) >= sizeof(float). For example, a 32-bit float uses some bits to represent the exponent, and thus it cannot exactly represent every 32-bit int. So 12584491 / 3 = 4194830.333..., which should round down to 4194830, but, on my machine which cannot represent 12584491 exactly in a float, the above formula rounds up to 4194831, which is wrong. Using double is safer.Frustule
This doesn't make sense. Your float solution is rounding the number to its nearest integer, while the second one is returning the ceiling.Procurance
Ah Sorry. I adjusted the implementation to also round rather than ceilLarghetto
this doesn't work at all for negative numbers, try std::cout << "exact: " << (-8.0f / 2.0f) << std::endl; and std::cout << "rounded: " << (int) (-8.0f / 2.0f + 0.5f) << std::endl;. first -4 and rounded is -3. for negative you should -0.5 instead of 0.5Brindabrindell
@javapowered, yes. That's why the function only operates on unsigned ints.Larghetto
see @PauliusZ's answer for Linux's DIV_ROUND_CLOSEST macro, which uses GNU C typeof() to be safe with inputs like i++, and will work right for negative numbers when used with signed operands.Beachhead
Really the question is why you want to represent values like this as an integer type. double holds perfect integers up to 2^53 and allows you to easily specify how errors will be rounded.Photomontage
It should be noted that this is a rearrangement of some mathematics which intends to add 0.5 to the numerator. This has the effect of forcing any number that has a decimal part of 0.5 or greater, to instead have an integer part made 1 greater than it previously was. Adding denominator/2 to the numerator, results in 0.5 being added to the calculated number. This works also, for negative numbers as the denominators negative sign is cancelled upon division by itself.Otoole
@MalcolmMcLean I cannot speak to all cases, but there are environments which do now permit floating point operations. It is entirely impossible when programming in UEFI and difficult (to potentially unrecommended) in the Linux KernelIrmgard
Your edit nails it! However, I prefer the macro or gcc statement expression type-free form of integer division with rounding, so I wrote it up and described it in detail here: stackoverflow.com/questions/2422712/…Nelrsa
dividend + (divisor / 2) risks overflow, which is well defined for unsinged math, but we get the wrong answer.Overdye
int a = some_float_A / some_float_B + 0.5f; can fail when quotient + 0.5 is inexact. Try nextafterf(0.5f,0) / 1.0f + 0.5f.Overdye
C
21

You should instead use something like this:

int a = (59 - 1)/ 4 + 1;

I assume that you are really trying to do something more general:

int divide(x, y)
{
   int a = (x -1)/y +1;

   return a;
}

x + (y-1) has the potential to overflow giving the incorrect result; whereas, x - 1 will only underflow if x = min_int...

Chaussure answered 11/2, 2011 at 16:33 Comment(6)
61.0 / 30.0 = 2.03333(3). So round up should be 2, but (61-1)/30+1=3Robinet
@Robinet why would 2.0333.. rounded up be 2?Penetrating
This does not work if x = 0. The intended result of x/y rounding up if x = 0 is 0. Yet this solution yields a result of 1. The other solution comes up with the correct answer.Fitzsimmons
Actually, this answer is not correct at all. It works for a few numbers but fails on quite a few. See my better (I hope) answer later on in the thread.Chaussure
If this answer is qrong why wouldn't you just delete it?Kep
@WayneJ, your function produces the smallest maximum integer for positive numbers, yet the question seeks the nearest integer; I assume that rounds-up to tie-break. In addition, it fails for negative numbers; for example, divide (-10, 2) gives -4.Birck
C
16

(Edited) Rounding integers with floating point is the easiest solution to this problem; however, depending on the problem set is may be possible. For example, in embedded systems the floating point solution may be too costly.

Doing this using integer math turns out to be kind of hard and a little unintuitive. The first posted solution worked okay for the the problem I had used it for but after characterizing the results over the range of integers it turned out to be very bad in general. Looking through several books on bit twiddling and embedded math return few results. A couple of notes. First, I only tested for positive integers, my work does not involve negative numerators or denominators. Second, and exhaustive test of 32 bit integers is computational prohibitive so I started with 8 bit integers and then mades sure that I got similar results with 16 bit integers.

I started with the 2 solutions that I had previously proposed:

#define DIVIDE_WITH_ROUND(N, D) (((N) == 0) ? 0:(((N * 10)/D) + 5)/10)

#define DIVIDE_WITH_ROUND(N, D) (N == 0) ? 0:(N - D/2)/D + 1;

My thought was that the first version would overflow with big numbers and the second underflow with small numbers. I did not take 2 things into consideration. 1.) the 2nd problem is actually recursive since to get the correct answer you have to properly round D/2. 2.) In the first case you often overflow and then underflow, the two canceling each other out. Here is an error plot of the two (incorrect) algorithms:Divide with Round1 8 bit x=numerator y=denominator

This plot shows that the first algorithm is only incorrect for small denominators (0 < d < 10). Unexpectedly it actually handles large numerators better than the 2nd version.

Here is a plot of the 2nd algorithm: 8 bit signed numbers 2nd algorithm.

As expected it fails for small numerators but also fails for more large numerators than the 1st version.

Clearly this is the better starting point for a correct version:

#define DIVIDE_WITH_ROUND(N, D) (((N) == 0) ? 0:(((N * 10)/D) + 5)/10)

If your denominators is > 10 then this will work correctly.

A special case is needed for D == 1, simply return N. A special case is needed for D== 2, = N/2 + (N & 1) // Round up if odd.

D >= 3 also has problems once N gets big enough. It turns out that larger denominators only have problems with larger numerators. For 8 bit signed number the problem points are

if (D == 3) && (N > 75))
else if ((D == 4) && (N > 100))
else if ((D == 5) && (N > 125))
else if ((D == 6) && (N > 150))
else if ((D == 7) && (N > 175))
else if ((D == 8) && (N > 200))
else if ((D == 9) && (N > 225))
else if ((D == 10) && (N > 250))

(return D/N for these)

So in general the the pointe where a particular numerator gets bad is somewhere around
N > (MAX_INT - 5) * D/10

This is not exact but close. When working with 16 bit or bigger numbers the error < 1% if you just do a C divide (truncation) for these cases.

For 16 bit signed numbers the tests would be

if ((D == 3) && (N >= 9829))
else if ((D == 4) && (N >= 13106))
else if ((D == 5) && (N >= 16382))
else if ((D == 6) && (N >= 19658))
else if ((D == 7) && (N >= 22935))
else if ((D == 8) && (N >= 26211))
else if ((D == 9) && (N >= 29487))
else if ((D == 10) && (N >= 32763))

Of course for unsigned integers MAX_INT would be replaced with MAX_UINT. I am sure there is an exact formula for determining the largest N that will work for a particular D and number of bits but I don't have any more time to work on this problem...

(I seem to be missing this graph at the moment, I will edit and add later.) This is a graph of the 8 bit version with the special cases noted above:![8 bit signed with special cases for 0 < N <= 10 3

Note that for 8 bit the error is 10% or less for all errors in the graph, 16 bit is < 0.1%.

Chaussure answered 11/10, 2013 at 20:48 Comment(1)
You are correct. The first macro was incorrect (I found this out the hard way.) This turned out to be harder that I expected. I updated the post acknowledging the incorrectness and include some further discussion.Chaussure
K
9

As written, you're performing integer arithmetic, which automatically just truncates any decimal results. To perform floating point arithmetic, either change the constants to be floating point values:

int a = round(59.0 / 4);

Or cast them to a float or other floating point type:

int a = round((float)59 / 4);

Either way, you need to do the final rounding with the round() function in the math.h header, so be sure to #include <math.h> and use a C99 compatible compiler.

Kimkimball answered 11/3, 2010 at 5:24 Comment(2)
A typical float (IEEE) limits the useful range of this solution to abs(a/b) < 16,777,216.Overdye
Or maybe lround.Pitman
V
7

From Linux kernel (GPLv2):

/*
 * Divide positive or negative dividend by positive divisor and round
 * to closest integer. Result is undefined for negative divisors and
 * for negative dividends if the divisor variable type is unsigned.
 */
#define DIV_ROUND_CLOSEST(x, divisor)(          \
{                           \
    typeof(x) __x = x;              \
    typeof(divisor) __d = divisor;          \
    (((typeof(x))-1) > 0 ||             \
     ((typeof(divisor))-1) > 0 || (__x) > 0) ?  \
        (((__x) + ((__d) / 2)) / (__d)) :   \
        (((__x) - ((__d) / 2)) / (__d));    \
}                           \
)
Verjuice answered 19/7, 2013 at 10:3 Comment(3)
Is typeof() part of C or a compiler specific extension?Overdye
@chux: It's a GCC extension. It's not a part of standard C.Amoeba
neat way to check for signed vs. unsigned args in a macro, so unsigned args can leave out the branch and extra instructions entirely.Beachhead
C
5
#define CEIL(a, b) (((a) / (b)) + (((a) % (b)) > 0 ? 1 : 0))

Another useful MACROS (MUST HAVE):

#define MIN(a, b)  (((a) < (b)) ? (a) : (b))
#define MAX(a, b)  (((a) > (b)) ? (a) : (b))
#define ABS(a)     (((a) < 0) ? -(a) : (a))
Comportment answered 18/11, 2011 at 23:47 Comment(3)
Your parentheses are making me dizzy.Ruling
Sure, it looks like a bad case of LISP, but omitting the parentheses around each argument and then evaluating ABS(4 & -1) is worse.Householder
He want's ROUND, not CEILToomin
N
5

This answer completely rewritten since the downvote in Oct. 2023.

The most-popular answer shows the correct principle, but only for rounding up, not down nor to nearest, and only for positive numbers.

Those are some big limitations, so I'll add a more complete answer here to round up (away from zero), down (towards zero), or to the nearest, and it will handle both positive and negative numbers (in either the numerator, denominator, or both). It also works in both C and C++, and I'll add a template version in C++, for completeness.

Rounding integer division (up/away from zero, down/towards zero, or to the nearest) for both positive and negative numbers

For my complete code, see the c/rounding_integer_division folder in my eRCaGuy_hello_world repo. See especially the rounding_integer_division.cpp file. Run the unit tests with ./run_tests.sh.

1. The code only

// -----------------------------------------------------------------------------
// 1. Macros
// -----------------------------------------------------------------------------

#define DIVIDE_ROUND_AWAY_FROM_ZERO(numer, denom) DIVIDE_ROUNDUP((numer), (denom))
#define DIVIDE_ROUNDUP(numer, denom) (                                                  \
    ((numer) < 0) != ((denom) < 0) ?                                                    \
    (numer) / (denom) :                                                                 \
    ((numer) + ((denom) < 0 ? (denom) + 1 : (denom) - 1)) / (denom)                     \
)

#define DIVIDE_ROUND_TOWARDS_ZERO(numer, denom) DIVIDE_ROUNDDOWN((numer), (denom))
#define DIVIDE_ROUNDDOWN(numer, denom) (                                                \
    ((numer) < 0) != ((denom) < 0) ?                                                    \
    ((numer) - ((denom) < 0 ? (denom) + 1 : (denom) - 1)) / (denom) :                   \
    (numer) / (denom)

#define DIVIDE_ROUNDNEAREST(numer, denom) (                                             \
    ((numer) < 0) != ((denom) < 0) ?                                                    \
    ((numer) - ((denom)/2)) / (denom) :                                                 \
    ((numer) + ((denom)/2)) / (denom)                                                   \
)

// -----------------------------------------------------------------------------
// 2. Statement Expressions (safer than macros)
// -----------------------------------------------------------------------------

#define DIVIDE_ROUND_AWAY_FROM_ZERO2(numer, denom) DIVIDE_ROUNDUP2((numer), (denom))
#define DIVIDE_ROUNDUP2(numer, denom)                                           \
    ({                                                                          \
        __typeof__(numer) numer_ = (numer);                                     \
        __typeof__(denom) denom_ = (denom);                                     \
        ((numer_) < 0) != ((denom_) < 0) ?                                      \
            (numer_) / (denom_) :                                               \
            ((numer_) + ((denom_) < 0 ? (denom_) + 1 : (denom_)-1)) / (denom_); \
    })

#define DIVIDE_ROUND_TOWARDS_ZERO2(numer, denom) DIVIDE_ROUNDDOWN2((numer), (denom))
#define DIVIDE_ROUNDDOWN2(numer, denom)                                          \
    ({                                                                           \
        __typeof__(numer) numer_ = (numer);                                      \
        __typeof__(denom) denom_ = (denom);                                      \
        ((numer_) < 0) != ((denom_) < 0) ?                                       \
            ((numer_) - ((denom_) < 0 ? (denom_) + 1 : (denom_)-1)) / (denom_) : \
            (numer_) / (denom_);                                                 \
    })

#define DIVIDE_ROUNDNEAREST2(numer, denom)                                              \
({                                                                                      \
    __typeof__ (numer) numer_ = (numer);                                                \
    __typeof__ (denom) denom_ = (denom);                                                \
    ((numer_) < 0) != ((denom_) < 0) ?                                                  \
    ((numer_) - ((denom_)/2)) / (denom_) :                                              \
    ((numer_) + ((denom_)/2)) / (denom_);                                               \
})

// -----------------------------------------------------------------------------
// 3. C++ Templated Functions (AKA: Function Templates)
// -----------------------------------------------------------------------------

#ifdef __cplusplus
#include <limits>

template <typename T>
T divide_roundup(T numer, T denom)
{
    static_assert(std::numeric_limits<T>::is_integer, "Only integer types are allowed");

    T result = ((numer) < 0) != ((denom) < 0) ?
        (numer) / (denom) :
        ((numer) + ((denom) < 0 ? (denom) + 1 : (denom) - 1)) / (denom);
    return result;
}

template <typename T>
inline T divide_round_away_from_zero(T numer, T denom)
{
    return divide_roundup(numer, denom);
}

template <typename T>
T divide_rounddown(T numer, T denom)
{
    static_assert(std::numeric_limits<T>::is_integer, "Only integer types are allowed");

    T result = ((numer) < 0) != ((denom) < 0) ?
        ((numer) - ((denom) < 0 ? (denom) + 1 : (denom) - 1)) / (denom) :
        (numer) / (denom);
    return result;
}

template <typename T>
inline T divide_round_towards_zero(T numer, T denom)
{
    return divide_rounddown(numer, denom);
}

template <typename T>
T divide_roundnearest(T numer, T denom)
{
    static_assert(std::numeric_limits<T>::is_integer, "Only integer types are allowed");

    T result = ((numer) < 0) != ((denom) < 0) ?
        ((numer) - ((denom)/2)) / (denom) :
        ((numer) + ((denom)/2)) / (denom);
    return result;
}

#endif

2. The code with extensive explanatory comments

// -----------------------------------------------------------------------------
// 1. Macros
// -----------------------------------------------------------------------------
// Great for C or C++, but some C++ developers hate them since they may have the multiple evaluation
// problem where you pass in an expression as an input parameter and it gets evaluated multiple
// times.

/// @brief      A function-like macro to perform integer division of numer/denom, rounding the
///             result UP (AWAY FROM ZERO) to the next whole integer.
/// @note       This works on *integers only* since it assumes integer truncation will take place
///             automatically during the division! It will NOT work properly on floating point
///             types! Valid types are int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t,
///             int64_t, uint64_t, etc.
/// @details    The concept is this:
///             (1) when the division result will be positive, *add*
///             (abs(denom) - 1) to the numerator *prior to* the division, as this is the
///             equivalent of adding a *tiny bit less than 1* to the result, which will always
///             result in a rounding up once integer truncation takes place. Examples:
///             1/4 = 0.25, but we add (abs(denom) - 1) to the numerator --> (1 + (4 - 1))/4 =
///             (1 + 3)/4 = 4/4 = 1.
///             (2) when the division result will be negative, simply truncating the result by
///             performing division as normal results in a rounding-up effect.
/// @param[in]  numer   The numerator in the division: any positive or negative integer
/// @param[in]  denom   The denominator in the division: any positive or negative integer
/// @return     The result of the (numer/denom) division rounded UP to the next *whole integer*!
#define DIVIDE_ROUND_AWAY_FROM_ZERO(numer, denom) DIVIDE_ROUNDUP((numer), (denom))
#define DIVIDE_ROUNDUP(numer, denom) (                                                  \
    /* NB: `!=` acts as a logical XOR operator */                                       \
    /* See: https://mcmap.net/q/15741/-logical-xor-operator-in-c */                              \
    ((numer) < 0) != ((denom) < 0) ?                                                    \
    /* numer OR denom, but NOT both, is negative, so do this: */                        \
    (numer) / (denom) :                                                                 \
    /* numer AND denom are either *both positive* OR *both negative*, so do this, */    \
    /* acting slightly differently if denom is negative: */                             \
    ((numer) + ((denom) < 0 ? (denom) + 1 : (denom) - 1)) / (denom)                     \
)

/// @brief      A function-like macro to perform integer division of numer/denom, rounding the
///             result DOWN (TOWARDS ZERO) to the next whole integer.
/// @note       This works on *integers only* since it assumes integer truncation will take place
///             automatically during the division! It will NOT work properly on floating point
///             types! Valid types are int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t,
///             int64_t, uint64_t, etc.
/// @details    The concept is this:
///             (1) when the division result will be positive, simply truncating the result by
///             performing division as normal results in a rounding-down effect.
///             (2) When the division result will be negative, *subtract*
///             (abs(denom) - 1) from the numerator *prior to* the division, as this is the
///             equivalent of subtracting a *tiny bit less than 1* from the result, which will
///             always result in a rounding down once integer truncation takes place. Examples:
///             -1/4 = -0.25, but we subtract (abs(denom) - 1) from the numerator -->
///             (-1 - (4 - 1))/4 = (-1 - 3)/4 = -4/4 = -1.
/// @param[in]  numer   The numerator in the division: any positive or negative integer
/// @param[in]  denom   The denominator in the division: any positive or negative integer
/// @return     The result of the (numer/denom) division rounded DOWN to the next *whole integer*!
#define DIVIDE_ROUND_TOWARDS_ZERO(numer, denom) DIVIDE_ROUNDDOWN((numer), (denom))
#define DIVIDE_ROUNDDOWN(numer, denom) (                                                \
    /* NB: `!=` acts as a logical XOR operator */                                       \
    /* See: https://mcmap.net/q/15741/-logical-xor-operator-in-c */                              \
    ((numer) < 0) != ((denom) < 0) ?                                                    \
    /* numer OR denom, but NOT both, is negative, so do this, */                        \
    /* acting slightly differently if denom is negative: */                             \
    ((numer) - ((denom) < 0 ? (denom) + 1 : (denom) - 1)) / (denom) :                   \
    /* numer AND denom are either *both positive* OR *both negative*, so do this: */    \
    (numer) / (denom)

/// @brief      A function-like macro to perform integer division of numer/denom, rounding the
///             result TO THE NEAREST whole integer.
/// @note       This works on *integers only* since it assumes integer truncation will take place
///             automatically during the division! It will NOT work properly on floating point
///             types! Valid types are int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t,
///             int64_t, uint64_t, etc.
/// @details    The concept is this:
///             (1) when the division result will be positive, *add* (denom/2) to
///             the numerator *prior to* the division, as this is the equivalent of adding
///             0.5 to the result, which will always result in rounding to the nearest whole
///             integer once integer truncation takes place. Examples:
///             3/4 = 0.75, but we add (denom/2) to the numerator --> (3 + 4/2)/4 =
///             (3 + 2)/4 = 5/4 = 1.25, which truncates to 1.
///             (2) when the division result will be negative, *subtract* (denom/2) from
///             the numerator *prior to* the division, as this is required to grow it by 0.5
///             in the direction *away from zero* (more negative in this case), which is required
///             for rounding to the nearest whole integer. The same principle as in the positive
///             case applies. Example: -3/4 = -0.75, but we subtract (denom/2) from the numerator
///             --> (-3 - 4/2)/4 = (-3 - 2)/4 = -5/4 = -1.25, which truncates to -1.
/// @param[in]  numer   The numerator in the division: any positive or negative integer
/// @param[in]  denom   The denominator in the division: any positive or negative integer
/// @return     The result of the (numer/denom) division rounded TO THE NEAREST *whole integer*!
#define DIVIDE_ROUNDNEAREST(numer, denom) (                                             \
    /* NB: `!=` acts as a logical XOR operator */                                       \
    /* See: https://mcmap.net/q/15741/-logical-xor-operator-in-c */                              \
    ((numer) < 0) != ((denom) < 0) ?                                                    \
    /* numer OR denom, but NOT both, is negative, so do this: */                        \
    ((numer) - ((denom)/2)) / (denom) :                                                 \
    /* numer AND denom are either *both positive* OR *both negative*, so do this: */    \
    ((numer) + ((denom)/2)) / (denom)                                                   \
)


// -----------------------------------------------------------------------------
// 2. Statement Expressions
// -----------------------------------------------------------------------------
// These solve the multiple evaluation problem of macros perfectly, but are not part of the C or
// C++ standard. Instead, they are gcc and clang compiler extensions to C and C++. These are safer
// to use than macros, but can still have a name pollution risk because variables created inside
// statement expressions are not in their own scope--rather, they are part of the outer scope.
// Nevertheless, prefer them to macros.

/// @brief  *gcc statement expression* form of the above equivalent macro
#define DIVIDE_ROUND_AWAY_FROM_ZERO2(numer, denom) DIVIDE_ROUNDUP2((numer), (denom))
#define DIVIDE_ROUNDUP2(numer, denom)                                           \
    ({                                                                          \
        __typeof__(numer) numer_ = (numer);                                     \
        __typeof__(denom) denom_ = (denom);                                     \
        ((numer_) < 0) != ((denom_) < 0) ?                                      \
            (numer_) / (denom_) :                                               \
            ((numer_) + ((denom_) < 0 ? (denom_) + 1 : (denom_)-1)) / (denom_); \
    })

/// @brief  *gcc statement expression* form of the above equivalent macro
#define DIVIDE_ROUND_TOWARDS_ZERO2(numer, denom) DIVIDE_ROUNDDOWN2((numer), (denom))
#define DIVIDE_ROUNDDOWN2(numer, denom)                                          \
    ({                                                                           \
        __typeof__(numer) numer_ = (numer);                                      \
        __typeof__(denom) denom_ = (denom);                                      \
        ((numer_) < 0) != ((denom_) < 0) ?                                       \
            ((numer_) - ((denom_) < 0 ? (denom_) + 1 : (denom_)-1)) / (denom_) : \
            (numer_) / (denom_);                                                 \
    })

/// @brief  *gcc statement expression* form of the above equivalent macro
#define DIVIDE_ROUNDNEAREST2(numer, denom)                                              \
({                                                                                      \
    __typeof__ (numer) numer_ = (numer);                                                \
    __typeof__ (denom) denom_ = (denom);                                                \
    ((numer_) < 0) != ((denom_) < 0) ?                                                  \
    ((numer_) - ((denom_)/2)) / (denom_) :                                              \
    ((numer_) + ((denom_)/2)) / (denom_);                                               \
})


// -----------------------------------------------------------------------------
// 3. C++ Templated Functions (AKA: Function Templates)
// -----------------------------------------------------------------------------
// Templates work in C++ only. They solve both problems above, and suffer neither from the multiple
// evaluation problem of macros, nor from the name pollution/variable scope problem of statement
// expressions. Since they work only in C++, I'm going to add type checking here too with a
// `static_assert()` using `std::numeric_limits`, but this feature could be *easily* added to both
// macros and statement expressions as well so long as you're using C++. Some C++ developers feel so
// strongly against macros (and are probably not aware of statement expressions) that they won't let
// you merge the above macro versions into their codebase. If this is the case, use templates.

#ifdef __cplusplus
#include <limits>

/// @brief  C++ function template form of the above equivalent macro
template <typename T>
T divide_roundup(T numer, T denom)
{
    // Ensure only integer types are passed in, as this round division technique does NOT work on
    // floating point types since it assumes integer truncation will take place automatically
    // during the division!
    // - The following static assert allows all integer types, including their various `const`,
    //   `volatile`, and `const volatile` variations, but prohibits any floating point type
    //   such as `float`, `double`, and `long double`.
    // - Reference page: https://en.cppreference.com/w/cpp/types/numeric_limits/is_integer
    static_assert(std::numeric_limits<T>::is_integer, "Only integer types are allowed");

    T result = ((numer) < 0) != ((denom) < 0) ?
        (numer) / (denom) :
        ((numer) + ((denom) < 0 ? (denom) + 1 : (denom) - 1)) / (denom);
    return result;
}

template <typename T>
inline T divide_round_away_from_zero(T numer, T denom)
{
    return divide_roundup(numer, denom);
}

/// @brief  C++ function template form of the above equivalent macro
template <typename T>
T divide_rounddown(T numer, T denom)
{
    // Ensure only integer types are passed in, as this round division technique does NOT work on
    // floating point types since it assumes integer truncation will take place automatically
    // during the division!
    // - The following static assert allows all integer types, including their various `const`,
    //   `volatile`, and `const volatile` variations, but prohibits any floating point type
    //   such as `float`, `double`, and `long double`.
    // - Reference page: https://en.cppreference.com/w/cpp/types/numeric_limits/is_integer
    static_assert(std::numeric_limits<T>::is_integer, "Only integer types are allowed");

    T result = ((numer) < 0) != ((denom) < 0) ?
        ((numer) - ((denom) < 0 ? (denom) + 1 : (denom) - 1)) / (denom) :
        (numer) / (denom);
    return result;
}

template <typename T>
inline T divide_round_towards_zero(T numer, T denom)
{
    return divide_rounddown(numer, denom);
}

/// @brief  C++ function template form of the above equivalent macro
template <typename T>
T divide_roundnearest(T numer, T denom)
{
    // Ensure only integer types are passed in, as this round division technique does NOT work on
    // floating point types since it assumes integer truncation will take place automatically
    // during the division!
    // - The following static assert allows all integer types, including their various `const`,
    //   `volatile`, and `const volatile` variations, but prohibits any floating point type
    //   such as `float`, `double`, and `long double`.
    // - Reference page: https://en.cppreference.com/w/cpp/types/numeric_limits/is_integer
    static_assert(std::numeric_limits<T>::is_integer, "Only integer types are allowed");

    T result = ((numer) < 0) != ((denom) < 0) ?
        ((numer) - ((denom)/2)) / (denom) :
        ((numer) + ((denom)/2)) / (denom);
    return result;
}

#endif

Unit tests

To prove that the above code is tested and works, here are some of my unit tests. Again, you can run them yourself. See the links at the top of this answer. This is not all of my unit tests. I could only paste some of them to keep this answer below the limit of 30k chars.

int main()
{
    printf("Testing Rounding Integer Division\n\n");


    printf("1. Macro Tests\n\n");

    printf("DIVIDE_ROUNDUP():\n");
    TEST_EQ(DIVIDE_ROUNDUP(5, 5), 1);   // 5/5   = 1.00 --> 1
    TEST_EQ(DIVIDE_ROUNDUP(5, 4), 2);   // 5/4   = 1.25 --> 2
    TEST_EQ(DIVIDE_ROUNDUP(6, 4), 2);   // 6/4   = 1.50 --> 2
    TEST_EQ(DIVIDE_ROUNDUP(7, 4), 2);   // 7/4   = 1.75 --> 2
    TEST_EQ(DIVIDE_ROUNDUP(9, 10), 1);  // 9/10  = 0.90 --> 1
    TEST_EQ(DIVIDE_ROUNDUP(3, 4), 1);   // 3/4   = 0.75 --> 1
    TEST_EQ(DIVIDE_ROUNDUP(-3, 4), 0);  // -3/4  = -0.75 --> 0
    TEST_EQ(DIVIDE_ROUNDUP(3, -4), 0);  // 3/-4  = -0.75 --> 0
    TEST_EQ(DIVIDE_ROUNDUP(-3, -4), 1); // -3/-4 = 0.75 --> 1
    TEST_EQ(DIVIDE_ROUNDUP(999, 1000), 1);   // 999/1000    = 0.999 --> 1
    TEST_EQ(DIVIDE_ROUNDUP(-999, 1000), 0);  // -999/1000   = -0.999 --> 0
    TEST_EQ(DIVIDE_ROUNDUP(999, -1000), 0);  // 999/-1000   = -0.999 --> 0
    TEST_EQ(DIVIDE_ROUNDUP(-999, -1000), 1); // -999/-1000  = 0.999 --> 1

    printf("\nDIVIDE_ROUND_AWAY_FROM_ZERO():\n");
    TEST_EQ(DIVIDE_ROUND_AWAY_FROM_ZERO(5, 5), 1);         // 5/5   = 1.00 --> 1
    TEST_EQ(DIVIDE_ROUND_AWAY_FROM_ZERO(5, 4), 2);         // 5/4   = 1.25 --> 2
    TEST_EQ(DIVIDE_ROUND_AWAY_FROM_ZERO(6, 4), 2);         // 6/4   = 1.50 --> 2
    TEST_EQ(DIVIDE_ROUND_AWAY_FROM_ZERO(7, 4), 2);         // 7/4   = 1.75 --> 2
    TEST_EQ(DIVIDE_ROUND_AWAY_FROM_ZERO(9, 10), 1);        // 9/10  = 0.90 --> 1
    TEST_EQ(DIVIDE_ROUND_AWAY_FROM_ZERO(3, 4), 1);         // 3/4   = 0.75 --> 1
    TEST_EQ(DIVIDE_ROUND_AWAY_FROM_ZERO(-3, 4), 0);        // -3/4  = -0.75 --> 0
    TEST_EQ(DIVIDE_ROUND_AWAY_FROM_ZERO(3, -4), 0);        // 3/-4  = -0.75 --> 0
    TEST_EQ(DIVIDE_ROUND_AWAY_FROM_ZERO(-3, -4), 1);       // -3/-4 = 0.75 --> 1
    TEST_EQ(DIVIDE_ROUND_AWAY_FROM_ZERO(999, 1000), 1);    // 999/1000    = 0.999 --> 1
    TEST_EQ(DIVIDE_ROUND_AWAY_FROM_ZERO(-999, 1000), 0);   // -999/1000   = -0.999 --> 0
    TEST_EQ(DIVIDE_ROUND_AWAY_FROM_ZERO(999, -1000), 0);   // 999/-1000   = -0.999 --> 0
    TEST_EQ(DIVIDE_ROUND_AWAY_FROM_ZERO(-999, -1000), 1);  // -999/-1000  = 0.999 --> 1

    printf("\nDIVIDE_ROUNDDOWN():\n");
    TEST_EQ(DIVIDE_ROUNDDOWN(5, 5), 1);   // 5/5   = 1.00 --> 1
    TEST_EQ(DIVIDE_ROUNDDOWN(5, 4), 1);   // 5/4   = 1.25 --> 1
    TEST_EQ(DIVIDE_ROUNDDOWN(6, 4), 1);   // 6/4   = 1.50 --> 1
    TEST_EQ(DIVIDE_ROUNDDOWN(7, 4), 1);   // 7/4   = 1.75 --> 1
    TEST_EQ(DIVIDE_ROUNDDOWN(9, 10), 0);  // 9/10  = 0.90 --> 0
    TEST_EQ(DIVIDE_ROUNDDOWN(3, 4), 0);   // 3/4   = 0.75 --> 0
    TEST_EQ(DIVIDE_ROUNDDOWN(-3, 4), -1); // -3/4  = -0.75 --> -1
    TEST_EQ(DIVIDE_ROUNDDOWN(3, -4), -1); // 3/-4  = -0.75 --> -1
    TEST_EQ(DIVIDE_ROUNDDOWN(-3, -4), 0); // -3/-4 = 0.75 --> 0
    TEST_EQ(DIVIDE_ROUNDDOWN(999, 1000), 0);   // 999/1000    = 0.999 --> 0
    TEST_EQ(DIVIDE_ROUNDDOWN(-999, 1000), -1);  // -999/1000   = -0.999 --> -1
    TEST_EQ(DIVIDE_ROUNDDOWN(999, -1000), -1);  // 999/-1000   = -0.999 --> -1
    TEST_EQ(DIVIDE_ROUNDDOWN(-999, -1000), 0); // -999/-1000  = 0.999 --> 0

    printf("\nDIVIDE_ROUND_TOWARDS_ZERO():\n");
    TEST_EQ(DIVIDE_ROUND_TOWARDS_ZERO(5, 5), 1);         // 5/5   = 1.00 --> 1
    TEST_EQ(DIVIDE_ROUND_TOWARDS_ZERO(5, 4), 1);         // 5/4   = 1.25 --> 1
    TEST_EQ(DIVIDE_ROUND_TOWARDS_ZERO(6, 4), 1);         // 6/4   = 1.50 --> 1
    TEST_EQ(DIVIDE_ROUND_TOWARDS_ZERO(7, 4), 1);         // 7/4   = 1.75 --> 1
    TEST_EQ(DIVIDE_ROUND_TOWARDS_ZERO(9, 10), 0);        // 9/10  = 0.90 --> 0
    TEST_EQ(DIVIDE_ROUND_TOWARDS_ZERO(3, 4), 0);         // 3/4   = 0.75 --> 0
    TEST_EQ(DIVIDE_ROUND_TOWARDS_ZERO(-3, 4), -1);       // -3/4  = -0.75 --> -1
    TEST_EQ(DIVIDE_ROUND_TOWARDS_ZERO(3, -4), -1);       // 3/-4  = -0.75 --> -1
    TEST_EQ(DIVIDE_ROUND_TOWARDS_ZERO(-3, -4), 0);       // -3/-4 = 0.75 --> 0
    TEST_EQ(DIVIDE_ROUND_TOWARDS_ZERO(999, 1000), 0);    // 999/1000    = 0.999 --> 0
    TEST_EQ(DIVIDE_ROUND_TOWARDS_ZERO(-999, 1000), -1);  // -999/1000   = -0.999 --> -1
    TEST_EQ(DIVIDE_ROUND_TOWARDS_ZERO(999, -1000), -1);  // 999/-1000   = -0.999 --> -1
    TEST_EQ(DIVIDE_ROUND_TOWARDS_ZERO(-999, -1000), 0);  // -999/-1000  = 0.999 --> 0

    printf("\nDIVIDE_ROUNDNEAREST():\n");
    TEST_EQ(DIVIDE_ROUNDNEAREST(5, 5), 1);   // 5/5   = 1.00 --> 1
    TEST_EQ(DIVIDE_ROUNDNEAREST(5, 4), 1);   // 5/4   = 1.25 --> 1
    TEST_EQ(DIVIDE_ROUNDNEAREST(6, 4), 2);   // 6/4   = 1.50 --> 2
    TEST_EQ(DIVIDE_ROUNDNEAREST(7, 4), 2);   // 7/4   = 1.75 --> 2
    TEST_EQ(DIVIDE_ROUNDNEAREST(9, 10), 1);  // 9/10  = 0.90 --> 1
    TEST_EQ(DIVIDE_ROUNDNEAREST(3, 4), 1);   // 3/4   = 0.75 --> 1
    TEST_EQ(DIVIDE_ROUNDNEAREST(-3, 4), -1);  // -3/4  = -0.75 --> -1
    TEST_EQ(DIVIDE_ROUNDNEAREST(3, -4), -1);  // 3/-4  = -0.75 --> -1
    TEST_EQ(DIVIDE_ROUNDNEAREST(-3, -4), 1); // -3/-4 = 0.75 --> 1
    TEST_EQ(DIVIDE_ROUNDNEAREST(999, 1000), 1);   // 999/1000    = 0.999 --> 1
    TEST_EQ(DIVIDE_ROUNDNEAREST(-999, 1000), -1);  // -999/1000   = -0.999 --> -1
    TEST_EQ(DIVIDE_ROUNDNEAREST(999, -1000), -1);  // 999/-1000   = -0.999 --> -1
    TEST_EQ(DIVIDE_ROUNDNEAREST(-999, -1000), 1); // -999/-1000  = 0.999 --> 1

    // Add a few extras with some unsigned types
    TEST_EQ(DIVIDE_ROUNDNEAREST((uint8_t)5, 5), 1);   // 5/5   = 1.00 --> 1
    TEST_EQ(DIVIDE_ROUNDNEAREST(5, (uint64_t)4), 1);   // 5/4   = 1.25 --> 1


    printf("\n\n2. Statement Expression Tests\n\n");

    // ...


#ifdef __cplusplus
    printf("\n\n3. Function Template Tests\n\n");

    // ...

    // Check the static assert to ensure only integer types are allowed,
    // including with const or volatile specifiers

    // Float test:
    // HITS STATIC ASSERT! GOOD!
    //      error: static assertion failed: Only integer types are allowed
    //              static_assert(std::numeric_limits<T>::is_integer, "Only integer types are allowed");
    //              ^~~~~~~~~~~~~
    // TEST_EQ(divide_roundnearest(7.0, 4.0), 2); // 7/4 = 1.75

    // ...

    // Try a few as uint8_t for kicks:
    TEST_EQ(divide_roundnearest((uint8_t)5, (uint8_t)4), 1);   // 5/4   = 1.25 --> 1
    TEST_EQ(divide_roundnearest((uint8_t)6, (uint8_t)4), 2);   // 6/4   = 1.50 --> 2
    TEST_EQ(divide_roundnearest((uint8_t)7, (uint8_t)4), 2);   // 7/4   = 1.75 --> 2

    // Try some explicit template types using the <> operator:
    /////////////// TODO
    // TEST_EQ(divide_roundnearest<7>(5, 4), 1);   // 5/4   = 1.25 --> 1

#endif

    printf("\nTest failure count = %u\n\n", test_fail_cnt);
    assert(test_fail_cnt == 0);

    return 0;
} // main

All tests pass in both C and C++, with the template form only being run in C++ of course.

References

  1. The c/rounding_integer_division folder in my eRCaGuy_hello_world repo.
  2. https://www.tutorialspoint.com/cplusplus/cpp_templates.htm

Related

  1. Fixed Point Arithmetic in C Programming - in this answer I go over how to do integer rounding to the nearest whole integer, then tenth place (1 decimal digit to the right of the decimal), hundredth place (2 dec digits), thousandth place (3 dec digits), etc. Search the answer for the section in my code comments called BASE 2 CONCEPT: for more details!

  2. A related answer of mine on gcc's statement expressions: MIN and MAX in C

  3. Rounding integer division (instead of truncating):

    1. The function form of this with fixed types
    2. For rounding up instead of to nearest integer, follow this similar pattern by @Jonathan Leffler
  4. What is the behavior of integer division?

TODO

  1. [ ] hard wrap all code to 80 columns so it will fit on Stack Overflow without scrolling left and right.
Nelrsa answered 26/10, 2019 at 7:0 Comment(11)
Definitely TLDRPlayful
Copy the code chunks. Delete all the comments. Each of the 3 approaches is like 1 to 4 lines. The details of what's really happening and how it works merit the verbose explanations as a teaching platform, however.Nelrsa
This answer's short. You wanna see a long one? stackoverflow.com/questions/44034633/…Nelrsa
The short answer is flawed: ROUND_DIVIDE(-3 , 4) evaluates to 0, which is not the nearest whole integer. The lengthy explanations do not address this problem at all. (int)round(-3.0 / 4.0) would evaluate to -1.Playful
I'll fix it when I get the chance (within the next 48 hrs or so). I've been using these for years but just on positive numbers. It just requires switching the addition to subtraction if either the numerator or denominator, but not both, is negative.Nelrsa
And if I stated that wrong I'll figure it out when I go to fix it. It's super late. I'll add negative numbers to my test cases too.Nelrsa
I haven't forgotten about this. My hunch was correct about swapping addition for subtraction under certain cases, requiring a logical XOR based on the negativity of each input. I'm in the process of rewriting this answer completely on my local computer first, fixing it to handle negative numbers, & also adding macros to round down and round up. When done, I'll have something like DIVIDE_ROUNDUP(), DIVIDE_ROUNDDOWN(), and DIVIDE_ROUNDNEAREST(), all of which will handle both positive and negative integer inputs. Hopefully then I'll win your upvote. I certainly will be using these myself.Nelrsa
Ok I've got all the code and unit tests done and it works perfectly! I've done all 3 functions I mention in the previous comment using macros, gcc/clang statement expresions, and C++ function templates, and it all works. I've run dozens of tests with both positive and negative inputs. Run it for yourself here: github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/tree/…. See the .cpp file. Run the .sh file to see the test output, or just look at the .txt file which contains sample output from when I ran it. Next I just need to update my answer here.Nelrsa
@chqrlie, answer updated to handle negative numerators and denominators.Nelrsa
I'm afraid your macros have undefined behavior for large absolute values because of signed arithmetic overflow. The same problem is present in the C++ templates for signed types. eg: DIVIDE_ROUNDUP(INT_MAX, INT_MAX), DIVIDE_ROUNDUP(INT_MIN, INT_MIN), DIVIDE_ROUNDDOWN(INT_MAX, -INT_MAX) and DIVIDE_ROUNDDOWN(-INT_MAX, INT_MAX), DIVIDE_ROUNDNEAREST(INT_MAX, INT_MAX)...Playful
@chqrlie, agreed. I don't think it makes sense to address that in a macro. I'm pretty sure every implementation in every answer here has that limitation, no? I mean, we could always add checks by making this a function not a macro, and return errors if it happens, but the assumption so far is that people are not using values near the extreme limits of their integer type.Nelrsa
E
4
int a, b;
int c = a / b;
if(a % b) { c++; }

Checking if there is a remainder allows you to manually roundup the quotient of integer division.

Encumbrancer answered 3/9, 2014 at 23:53 Comment(2)
Doesn't this round up too often when the divisor is anything other than 2?Salk
this is always rounding up like ceil function, not a proper roundingToomin
A
4

Here's my solution. I like it because I find it more readable and because it has no branching (neither ifs nor ternaries).

int32_t divide(int32_t a, int32_t b) {
  int32_t resultIsNegative = ((a ^ b) & 0x80000000) >> 31;
  int32_t sign = resultIsNegative*-2+1;
  return (a + (b / 2 * sign)) / b;
}

Full test program that illustrates intended behaviour:

#include <stdint.h>
#include <assert.h>

int32_t divide(int32_t a, int32_t b) {
  int32_t resultIsNegative = ((a ^ b) & 0x80000000) >> 31;
  int32_t sign = resultIsNegative*-2+1;
  return (a + (b / 2 * sign)) / b;
}

int main() {
  assert(divide(0, 3) == 0);

  assert(divide(1, 3) == 0);
  assert(divide(5, 3) == 2);

  assert(divide(-1, 3) == 0);
  assert(divide(-5, 3) == -2);

  assert(divide(1, -3) == 0);
  assert(divide(5, -3) == -2);

  assert(divide(-1, -3) == 0);
  assert(divide(-5, -3) == 2);
}
Amplify answered 9/4, 2015 at 8:27 Comment(1)
the & in ((a ^ b) & 0x80000000) >> 31; is redundant, since the low bits will be thrown away after the shift anywayToomin
U
3

Borrowing from @ericbn I prefere defines like

#define DIV_ROUND_INT(n,d) ((((n) < 0) ^ ((d) < 0)) ? (((n) - (d)/2)/(d)) : (((n) + (d)/2)/(d)))
or if you work only with unsigned ints
#define DIV_ROUND_UINT(n,d) ((((n) + (d)/2)/(d)))
Upstream answered 5/1, 2015 at 0:45 Comment(0)
C
2

For unsigned integer types and positive divider use:

template<typename T> T urounddiv(T n, T d) {
    return (n / d) + ((n % d) > (d / 2)); 
}

Step by step

59 / 4 + ((59 % 4) > (4 / 2))
14 + (3 > 2)
14 + true
14 + 1
15

General case

These C++ function templates work for any integral type T without overflowing, for any positive divider, and without using floating point.
Integer division in C truncates towards zero and so does rounddiv, rounddiv(3, 2) == 1 and rounddiv(-3, 2) == -1. The rounddiv_away function template rounds the half point away from zero, rounddiv_away(3, 2) == 2 and rounddiv_away(-3, 2) == -2. The results are different only when d is even.

// Round to zero division, no overflow
template<typename T> T rounddiv(T n, T d) {
    T r = n / d;
    T m = n % d;
    T h = d / 2;
    return r + (!(n < 0) & (m > h)) - ((n < 0) & ((m + h) < 0));
}
// Round away from zero division, no overflow
template<typename T> T rounddiv_away(T n, T d) {
    T r = n / d;
    T m = n % d;
    T h = (d / 2) + (d & 1);
    return r + (!(n < 0) & (m >= h)) - ((n < 0) & ((m + h) <= 0));
}

How it works

Start with positive integers. Instead of adding half of the divider to the original number, which is subject to range overflow, compare the remainder of the division (the result of the modulo operation) with half of the divider. If the reminder is larger than half of the divider, round up the result by incrementing it. The reminder value is available as a byproduct of the integer division in most cases, it is not an extra operation.

// Round to zero division of unsigned types, no overflow
template<typename T>
static T rounddiv(T x, T d) {
    static_assert(std::is_unsigned<T>(), "Unsigned integer types only");
    T r = x / d;
    T m = x % d;
    T h = d / 2;
    if (m > h)
        r = r + 1;
    return r;
}

For signed types, if x is positive the same formula applies. But when x is negative, both r and m will be negative, with r being truncated towards zero. This means that the result needs to be decremented when the absolute value of the reminder (-m) is larger than half of the quanta.

// Round to zero division, no overflow
template<typename T>
static T rounddiv(T x, T d) {
    static_assert(std::is_integral<T>(), "Integer types only");
    T r = x / d
    T m = x % d;
    T h = d / 2;
    if ((x >= 0) && (m > h))
        r = r + 1;
    else if ((x < 0) && (-m > h))
        r = r - 1
    return r;
}

The rest is just an optimized form to help the compiler generate better code. It is avoiding conditional execution by taking advantage of the fact that the result of a condition is a boolean which becomes 0 (false) or 1 (true) when converted to an integral type. The (m + h) < 0 is an alternate form of -m > h, which some compilers don't like when T is an unsigned type. For unsigned types most of the conditions are constant and will be optimized away.
The rounddiv_away function works similarly, with the conditions adjusted to include the exact middle value.
If the divider d is negative, use: -rounddiv(n, -d) (overflows only when d is minimum possible value for type). Round up (to plus infinity) or round down (to minus infinity) is also possible by combining parts of the two templates above.

Alternate solution

template<typename T>
T math_rounddiv(T n, T d) {
    return n / d + (n % d) / (d / 2 + 1);
}

template<typename T>
T math_rounddiv_away(T n, T d) {
    return n / d + (n % d) / (d / 2 + d % 2);
}

These functions have exactly the same behavior as the ones above, producing the correct result for all signed and unsigned values of n and strictly positive values of d for any integer types including 64bits. They are based on the algorithm described above and directly take care of the possible negative sign of n. While simpler, this version is slower than the initial one because it introduces a second mandatory integer division, except when the divider value is known at compile time.

Capriole answered 27/3, 2022 at 7:40 Comment(2)
I think it's possible for m + h to overflow (undefined behavior for signed) if e.g. d is close to the maximum for that integer type, and n is less than d but close the maximum integer. In that case m = n, so we have m + h = n + d/2, which is of course the same potential overflow from others' solutions that we were trying to avoidBiogenesis
Look at the larger component, ((n < 0) & ((m + h) < 0)). When n >=0 the result is always 0, regardless of the m+h result. When n < 0, m is also negative or zero, while h is positive or zero. (m + h) is a subtraction which can't overflow. It could also be written separately for signed types, in which case the (-m > h) can be used directly instead of (m+h) > 0.Capriole
L
1
int divide(x,y){
 int quotient = x/y;
 int remainder = x%y;
 if(remainder==0)
  return quotient;
 int tempY = divide(y,2);
 if(remainder>=tempY)
  quotient++;
 return quotient;
}

eg 59/4 Quotient = 14, tempY = 2, remainder = 3, remainder >= tempY hence quotient = 15;

Ludicrous answered 6/8, 2011 at 15:11 Comment(1)
This does not work correctly for negative numbers - consider divide(-59, 4).Jacobsen
F
1

The following correctly rounds the quotient to the nearest integer for both positive and negative operands WITHOUT floating point or conditional branches (see assembly output below). Assumes N-bit 2's complement integers.

#define ASR(x) ((x) < 0 ? -1 : 0)  // Compiles into a (N-1)-bit arithmetic shift right
#define ROUNDING(x,y) ( (y)/2 - (ASR((x)^(y)) & (y)))

int RoundedQuotient(int x, int y)
   {
   return (x + ROUNDING(x,y)) / y ;
   }

The value of ROUNDING will have the same sign as the dividend (x) and half the magnitude of the divisor (y). Adding ROUNDING to the dividend thus increases its magnitude before the integer division truncates the resulting quotient. Here's the output of the gcc compiler with -O3 optimization for a 32-bit ARM Cortex-M4 processor:

RoundedQuotient:                // Input parameters: r0 = x, r1 = y
    eor     r2, r1, r0          // r2 = x^y
    and     r2, r1, r2, asr #31 // r2 = ASR(x^y) & y
    add     r3, r1, r1, lsr #31 // r3 = (y < 0) ? y + 1 : y
    rsb     r3, r2, r3, asr #1  // r3 = y/2 - (ASR(x^y) & y)
    add     r0, r0, r3          // r0 = x + (y/2 - (ASR(x^y) & y)
    sdiv    r0, r0, r1          // r0 = (x + ROUNDING(x,y)) / y
    bx      lr                  // Returns r0 = rounded quotient
Fadil answered 21/12, 2018 at 22:37 Comment(1)
Seems to fail when x > 0 and y < 0: RoundedQuotient(10, -3) = -4Capriole
H
1

If I haven't missed something the answer of cipilo is the only solution which works for all parameter, even close to INT_MAX. It avoids the possible overflow errors of other solutions. I can't comment or up-vote due to lacking reputation.

His implementation handles only positive divisors. My solution considers those overflows as well and handles also negative divisors.

C (as asked):

unsigned round_div_halfawayu(unsigned n, unsigned d)
{
    return n / d + (n % d > (d - 1) / 2);
}

int round_div_halfaway(int n, int d)
{
    if (d == INT_MIN)
    {
        if (n <= d / 2)
            return 1;
        else if (-n <= d / 2)
            return -1;
        else
            return 0;
    }

    if ((n < 0) == (d < 0))
        return n / d + (abs(n % d) > (abs(d) - 1) / 2);
    else
        return n / d - (abs(n % d) > (abs(d) - 1) / 2);
}

C++ (I'm using):

template <typename T, std::enable_if_t<std::is_integral<T>::value, bool> = true>
T round_div_halfaway(T n, T d)
{
    if constexpr (std::is_unsigned<T>::value)
        return n / d + (n % d > (d - 1) / 2);
    else if constexpr (std::is_signed<T>::value)
    {
        if (d == std::numeric_limits<T>::min())
        {
            if (n <= d / 2)
                return 1;
            else if (-n <= d / 2)
                return -1;
            else
                return 0;
        }

        if ((n < 0) == (d < 0))
            return n / d + (std::abs(n % d) > (std::abs(d) - 1) / 2);
        else
            return n / d - (std::abs(n % d) > (std::abs(d) - 1) / 2);
    }
}

It is basically calculating the truncated result and increases the absolute if neccessary. The assertion checks for the overflow behavior of abs(INT_MIN), which is undefined by the standard.

The function implements the common commercial rounding (half away from zero).

Hipparch answered 7/6, 2022 at 16:5 Comment(4)
@chux thanks, you're right. One may not assert on UB. So I've updated the code to handle the case explicitly and leave the rest to the optimizer.Hipparch
Better. round_div_halfaway(INT_MAX, INT_MIN) now returns 0. Would not -1 make more sense?Overdye
@chux. Thanks for pointing this out. Now I took the time and tried to write all relevant test cases.Hipparch
Of course d==0 and round_div_halfaway(INT_MIN, -1) remain a problem - we can leave them alone. Yet instead of if (d == std::numeric_limits<T>::min()), std::abs()` calls, would not code flow better with if (n < 0) { if (d < 0) ... else ...} else { if d < 0) ... else ...}?Overdye
O
1

If you use floating point you will round to the nearest even number if two integers are equally close. For example round(5./2.) = 2, while the integer methods provided above gives 5/2 = 3. The round-to-nearest-or-even method is useful for minimizing accumulating rounding errors. See https://en.wikipedia.org/wiki/Rounding#Rounding_half_to_even

To do this without using floating point, you have to round away from zero if the remainder is equal to half the divisor and the division result is odd.

This code should work for positive integers:

unsigned int rounded_division(unsigned int n, unsigned int d) {
    unsigned int q = n / d;  // quotient
    unsigned int r = n % d;  // remainder
    if (r > d>>1  // fraction > 0.5
    || (r == d>>1 && (q&1) && !(d&1))) { // fraction == 0.5 and odd
        q++;
    }
    return q;
}
Overshoe answered 30/11, 2022 at 8:43 Comment(2)
This is the best answer. The rounding mode you learnt in school is not the best one. In school you learnt ROUND_HALF_UP. Where 7.5and 8.5 is always rounded up to 8 and 9. But this has statistical problems it slightly biases things upwards. ROUND_HALF_EVEN is better statistically, here you round to the even number so 7.5 and 8.5 both round to 8. You can see this by considering a uniform distribution of numbers between 0 and 10 with 1 dp. ROUND_HALF_UP gives a mean of 5.05 but ROUNUD_HALF_EVEN gives a mean of 5.0, which is the same as the mean of the original nubers.Topknot
In Java see docs.oracle.com/javase/8/docs/api/java/math/RoundingMode.htmlTopknot
G
0

For some algorithms you need a consistent bias when 'nearest' is a tie.

// round-to-nearest with mid-value bias towards positive infinity
int div_nearest( int n, int d )
   {
   if (d<0) n*=-1, d*=-1;
   return (abs(n)+((d-(n<0?1:0))>>1))/d * ((n<0)?-1:+1);
   }

This works regardless of the sign of the numerator or denominator.


If you want to match the results of round(N/(double)D) (floating-point division and rounding), here are a few variations that all produce the same results:

int div_nearest( int n, int d )
   {
   int r=(n<0?-1:+1)*(abs(d)>>1); // eliminates a division
// int r=((n<0)^(d<0)?-1:+1)*(d/2); // basically the same as @ericbn
// int r=(n*d<0?-1:+1)*(d/2); // small variation from @ericbn
   return (n+r)/d;
   }

Note: The relative speed of (abs(d)>>1) vs. (d/2) is likely to be platform dependent.

Gonzales answered 9/3, 2014 at 3:3 Comment(3)
As noted by @Jacobsen in a comment to another answer, overflow is a risk with this approach to rounding (since it modifies the numerator prior to the division), so this function isn't appropriate if you are pushing the range limits of int.Gonzales
By the way, if you happen to be dividing by a power of two (which also implies a positive divisor), you can take advantage of the fact that signed-shift-right has the effect of division with round-towards-negative infinity (unlike the division operator which rounds towards zero) to avoid the use of any conditional logic. So the formula becomes return (n+(1<<shift>>1))>>shift;, which simplifies to the form (n+C)>>shift (where C=(1<<shift>>1) if shift happens to be a constant.Gonzales
The "mid-value bias" concern only relates to the case of exactly 0.5 between integers, so is esoteric to be sure. For some kind of graphical representation, for example, you might want to see continuity around zero rather than symmetry.Gonzales
H
0

If you're dividing positive integers you can shift it up, do the division and then check the bit to the right of the real b0. In other words, 100/8 is 12.5 but would return 12. If you do (100<<1)/8, you can check b0 and then round up after you shift the result back down.

Herb answered 31/1, 2015 at 3:25 Comment(0)
C
0
double a=59.0/4;
int b=59/4;
if(a-b>=0.5){
    b++;
}
printf("%d",b);
  1. let exact float value of 59.0/4 be x(here it is 14.750000)
  2. let smallest integer less than x be y(here it is 14)
  3. if x-y<0.5 then y is the solution
  4. else y+1 is the solution
Crouton answered 24/9, 2016 at 9:38 Comment(1)
this is the worst solution. Doing 2 slow divisions are not people want to do. And b can be obtained by truncating a instead of doing another divisionToomin
T
0

Some alternatives for division by 4

return x/4 + (x/2 % 2);
return x/4 + (x % 4 >= 2)

Or in general, division by any power of 2

return x/y + x/(y/2) % 2;    // or
return (x >> i) + ((x >> i - 1) & 1);  // with y = 2^i

It works by rounding up if the fractional part ⩾ 0.5, i.e. the first digit ⩾ base/2. In binary it's equivalent to adding the first fractional bit to the result

This method has an advantage in architectures with a flag register, because the carry flag will contain the last bit that was shifted out. For example on x86 it can be optimized into

shr eax, i
adc eax, 0

It's also easily extended to support signed integers. Notice that the expression for negative numbers is

(x - 1)/y + ((x - 1)/(y/2) & 1)

we can make it work for both positive and negative values with

int t = x + (x >> 31);
return (t >> i) + ((t >> i - 1) & 1);
Toomin answered 18/3, 2019 at 16:53 Comment(0)
S
0

The fundamental rounding divide algorithm, as presented by previous contributors, is to add half the denominator to the numerator before division. This is simple when the inputs are unsigned, not quite so when signed values are involved. Here are some solutions that generate optimal code by GCC for ARM (thumb-2).

Signed / Unsigned

inline int DivIntByUintRnd(int n, uint d)       
{ 
    int sgn = n >> (sizeof(n)*8-1); // 0 or -1
    return (n + (int)(((d / 2) ^ sgn) - sgn)) / (int)d; 
}

The first code line replicates the numerator sign bit through an entire word, creating zero (positive) or -1 (negative). On the second line, this value (if negative) is used to negate the rounding term using 2's complement negation: complement and increment. Previous answers used a conditional statement or multiply to achieve this.

Signed / Signed

inline int DivIntRnd(int n, int d)      
{ 
    int rnd = d / 2;
    return (n + ((n ^ d) < 0 ? -rnd : rnd)) / d; 
}

I found I got the shortest code with the conditional expression, but only if I helped the compiler by computing the rounding value d/2. Using 2's complement negation is close:

inline int DivIntRnd(int n, int d)      
{ 
    int sgn = (n ^ d) >> (sizeof(n)*8-1);   // 0 or -1
    return (n + ((d ^ sgn) - sgn) / 2) / d; 
}

Division by Powers of 2

While integer division truncates toward zero, shifting truncates toward negative infinity. This makes a rounding shift much simpler, as you always add the rounding value regardless of the sign of the numerator.

inline int ShiftIntRnd(int n, int s)        { return ((n >> (s - 1)) + 1) >> 1; }
inline uint ShiftUintRnd(uint n, int s)     { return ((n >> (s - 1)) + 1) >> 1; }

The expression is the same (generating different code based on type), so a macro or overloaded function could work for both.

The traditional method (the way rounding division works) would be to add half the divisor, 1 << (s-1). Instead we shift one less, add one, and then do the final shift. This saves creating a non-trivial value (even if constant) and the machine register to put it in.

Siliculose answered 3/1, 2020 at 19:11 Comment(2)
int sgn = n >> (sizeof(n)*8-1); // 0 or -1: NO, the behavior is not defined by the C Standard. You should use int sgn = ~(n < 0);Playful
My concern is about speed and size for an ARM microcontroller. The expression ~(n < 0) generates one more instruction. Besides, the original expression will work on any architecture using 8-bit bytes and two's complement, which I think describes all modern machines.Siliculose
S
0

this answer is:

  • Positive and negative generic;
  • overflow prevention;
  • test set included;
  • detailed comments;
  • used in our production system;

Unfortunately, it won't work out of the box in your environment, but you only need to modify a few types.

code:

    static Result apply(A x, B d)
    {
        /// For division of Decimal/Decimal or Int/Decimal or Decimal/Int, we should round the result to make it compatible.
        /// basically refer to https://stackoverflow.com/a/71634489
        if constexpr (std::is_integral_v<Result> || std::is_same_v<Result, Int256>)
        {
            /// 1. do division first, get the quotient and mod, todo:(perf) find a unified `divmod` function to speed up this.
            Result quotient = x / d;
            Result mod = x % d;
            /// 2. get the half of divisor, which is threshold to decide whether to round up or down.
            /// note: don't directly use bit operation here, it may cause unexpected result.
            Result half = (d / 2) + (d % 2);

            /// 3. compare the abstract values of mod and half, if mod >= half, then round up.
            Result abs_m = mod < 0 ? -mod : mod;
            Result abs_h = half < 0 ? -half : half;
            if (abs_m >= abs_h)
            {
                /// 4. now we need to round up, i.e., add 1 to the quotient's absolute value.
                ///    if the signs of dividend and divisor are the same, then the quotient should be positive, otherwise negative.
                if ((x < 0) == (d < 0)) // same_sign, i.e., quotient >= 0
                    quotient = quotient + 1;
                else
                    quotient = quotient - 1;
            }
            return quotient;
        }
        else
            return static_cast<Result>(x) / d;
    }

a part of tests:

template <typename TYPE>
void doTiDBDivideDecimalRoundInternalTest()
{
    auto apply = static_cast<TYPE (*)(TYPE, TYPE)>(&TiDBDivideFloatingImpl<TYPE, TYPE, false>::apply);

    constexpr TYPE max = std::numeric_limits<TYPE>::max();
    // note: Int256's min is not equal to -max-1
    // according to https://www.boost.org/doc/libs/1_60_0/libs/multiprecision/doc/html/boost_multiprecision/tut/ints/cpp_int.html
    constexpr TYPE min = std::numeric_limits<TYPE>::min();

    // clang-format off
    const std::vector<std::array<TYPE, 3>> cases = {
        {1, 2, 1}, {1, -2, -1}, {-1, 2, -1}, {-1, -2, 1},

        {0, 3, 0}, {0, -3, 0}, {0, 3, 0}, {0, -3, 0},
        {1, 3, 0}, {1, -3, 0}, {-1, 3, 0}, {-1, -3, 0},
        {2, 3, 1}, {2, -3, -1}, {-2, 3, -1}, {-2, -3, 1},
        {3, 3, 1}, {3, -3, -1}, {-3, 3, -1}, {-3, -3, 1},
        {4, 3, 1}, {4, -3, -1}, {-4, 3, -1}, {-4, -3, 1},
        {5, 3, 2}, {5, -3, -2}, {-5, 3, -2}, {-5, -3, 2},

        // ±max as divisor
        {0, max, 0}, {max/2-1, max, 0}, {max/2, max, 0}, {max/2+1, max, 1}, {max-1, max, 1}, {max, max, 1},
        {-1, max, 0}, {-max/2+1, max, 0},  {-max/2, max, 0}, {-max/2-1, max, -1}, {-max+1, max, -1}, {-max, max, -1}, {min, max, -1},
        {0, -max, 0}, {max/2-1, -max, 0}, {max/2, -max, 0}, {max/2+1, -max, -1}, {max-1, -max, -1}, {max, -max, -1},
        {-1, -max, 0}, {-max/2+1, -max, 0},  {-max/2, -max, 0}, {-max/2-1, -max, 1}, {-max+1, -max, 1}, {-max, -max, 1}, {min, -max, 1},

        // ±max as dividend
        {max, 1, max}, {max, 2, max/2+1}, {max, max/2-1, 2}, {max, max/2, 2}, {max, max/2+1, 2}, {max, max-1, 1},
        {max, -1, -max}, {max, -2, -max/2-1}, {max, -max/2+1, -2}, {max, -max/2, -2}, {max, -max/2-1, -2}, {max, -max+1, -1},
        {-max, 1, -max}, {-max, 2, -max/2-1}, {-max, max/2+1, -2}, {-max, max/2, -2}, {-max, max/2-1, -2}, {-max, max-1, -1},
        {-max, -1, max}, {-max, -2, max/2+1}, {-max, -max/2-1, 2}, {-max, -max/2, 2}, {-max, -max/2+1, 2}, {-max, -max+1, 1},
    };
    // clang-format on

    for (const auto & expect : cases)
    {
        std::array<TYPE, 3> actual = {expect[0], expect[1], apply(expect[0], expect[1])};
        ASSERT_EQ(expect, actual);
    }
}

TEST_F(TestBinaryArithmeticFunctions, TiDBDivideDecimalRoundInternal)
try
{
    doTiDBDivideDecimalRoundInternalTest<Int32>();
    doTiDBDivideDecimalRoundInternalTest<Int64>();
    doTiDBDivideDecimalRoundInternalTest<Int128>();
    doTiDBDivideDecimalRoundInternalTest<Int256>();
}
CATCH
Southsoutheast answered 9/2, 2023 at 9:3 Comment(0)
F
-1

try using math ceil function that makes rounding up. Math Ceil !

Forebrain answered 25/4, 2014 at 21:9 Comment(0)
T
-1

I ran into the same difficulty. The code below should work for positive integers.

I haven't compiled it yet but I tested the algorithm on a google spreadsheet (I know, wtf) and it was working.

unsigned int integer_div_round_nearest(unsigned int numerator, unsigned int denominator)
{
    unsigned int rem;
    unsigned int floor;
    unsigned int denom_div_2;

    // check error cases
    if(denominator == 0)
        return 0;

    if(denominator == 1)
        return numerator;

    // Compute integer division and remainder
    floor = numerator/denominator;
    rem = numerator%denominator;

    // Get the rounded value of the denominator divided by two
    denom_div_2 = denominator/2;
    if(denominator%2)
        denom_div_2++;

    // If the remainder is bigger than half of the denominator, adjust value
    if(rem >= denom_div_2)
        return floor+1;
    else
        return floor;
}
Thimerosal answered 5/9, 2015 at 21:16 Comment(1)
Do not see a need for if(denominator == 1) return numerator;. What is its purpose?Overdye
N
-1

Safer C code (unless you have other methods of handling /0):

return (_divisor > 0) ? ((_dividend + (_divisor - 1)) / _divisor) : _dividend;

This doesn't handle the problems that occur from having an incorrect return value as a result of your invalid input data, of course.

Naominaor answered 29/10, 2015 at 23:44 Comment(0)
P
-1

In Go (but I'm sure you can easily re-write this to C):

func divideAndRound(n, d int) int {
    result, resultRamainder := n/d, n%d
    if abs(resultRamainder) > abs(d/2) {
        if (n > 0) == (d > 0) { // Same sign. a or b can never be 0 at this point.
            result++
        } else {
            result--
        }
    }

    return result
}

This is similar to @ericbn's answer but is also safe for big integers.

Prate answered 11/12, 2023 at 12:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.