Skip to content
VLSI Mentor

C Part I · Module 3 · Expressions and Operators

Integer Division and Remainder

This is the first result in the curriculum that is entirely correct and looks wrong. Divide 7 by 2 in C and you get 3. Beginners reliably read that as a bug, a rounding rule, or a strange economy, and it is none of those — it follows inevitably from the one sentence the previous chapter built toward. Once you see why it has to happen you will also be able to predict what C does with negative operands, which is where the difference between discarding and rounding finally becomes visible, and you will understand why the remainder operator takes its sign from the side it does rather than from the side that feels natural.

Foundation12 min readCPart IFundamentalsExpressions

Part I · Module 3 · Chapter 3.3 · Integer Division and Remainder

1. The Result That Looks Wrong

Azvya Education Pvt. Ltd.VLSI Mentor
divide seven by two
#include <stdio.h>

int main(void)
{
    int total = 7;
    int count = 2;

    printf("as int    : %d\n", total / count);
    printf("as double : %f\n", 7.0 / 2.0);
    return 0;
}

Output:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
as int    : 3
as double : 3.500000

The second line is what you expected. The first is what C gives you for int / int, and it is not a mistake.

2. Why It Has to Be 3

Chapter 3.2 ended on one sentence: when both operands are int, the result is an int. Follow it through:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  7 / 2            both operands are int
  → the result must be an int
  → an int holds whole numbers only
  → 3.5 is not a whole number
  → so 3.5 cannot be the result

Something has to go, and what goes is the fractional part. The result is 3.

Notice what did not happen. C did not look at the answer, see that it needed a fraction, and quietly switch to a type that could hold one. Chapter 3.2 said the result type is decided from the operands before the program runs, not from how the answer turns out — and this is that rule producing a visible consequence for the first time.

The second line of §1's output is the same rule in the other direction. 7.0 and 2.0 are double literals, Chapter 2.11 established, so both operands are double, so the result is a double, and a double has somewhere to put the half.

3. Discarding Is Not Rounding

So far, "it rounds down" would explain the answer just as well as "it discards the fraction". Those two models agree on 7 / 2 and disagree the moment a negative value appears:

Azvya Education Pvt. Ltd.VLSI Mentor
the example that separates the two models
#include <stdio.h>

int main(void)
{
    printf("7 / 2   = %d\n", 7 / 2);
    printf("-7 / 2  = %d\n", -7 / 2);
    printf("7 / -2  = %d\n", 7 / -2);
    return 0;
}

Output:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
7 / 2   = 3
-7 / 2  = -3
7 / -2  = -3

Look at the middle line. The exact answer is −3.5.

  • Rounding down would give −4, because −4 is below −3.5.
  • Discarding the fraction gives −3, because you simply drop the .5.

C gives −3. So the model is not rounding. The precise term is truncation toward zero: the result is the exact answer with its fractional part removed, which always moves it toward zero rather than in a fixed direction.

That is a guarantee, not an observation. Truncation toward zero has been required since C99, so on this curriculum's C17 baseline you may rely on it everywhere.

4. The Remainder Operator

% gives what is left over after that division:

Azvya Education Pvt. Ltd.VLSI Mentor
division and remainder together
#include <stdio.h>

int main(void)
{
    printf("7 %% 2   = %d\n", 7 % 2);
    printf("-7 %% 2  = %d\n", -7 % 2);
    printf("7 %% -2  = %d\n", 7 % -2);
    return 0;
}

Output:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
7 % 2   = 1
-7 % 2  = -1
7 % -2  = 1

The signs look arbitrary until you notice they are not a separate rule at all. % is defined so that this identity always holds:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  (a / b) * b  +  a % b   ==   a

Check it on the awkward case. With a = −7 and b = 2:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  (-7 / 2) * 2  +  (-7 % 2)
  = (-3)   * 2  +  (-1)
  = -6          +  (-1)
  = -7                        ✓

So once / truncates toward zero, % has no freedom left — its value is forced, and its sign follows the left operand. -7 % 2 is −1 rather than +1 because that is the only value that makes the identity work.

The practical consequence is worth stating plainly, because it is a real source of bugs:

% does not always give a non-negative result. If the left operand can be negative, the remainder can be negative.

Also note that % requires integer operands. It does not work on double, and the compiler will tell you so.

5. Where This Actually Bites

The behaviour is easy to accept in isolation and easy to forget in code. The classic is an average:

Azvya Education Pvt. Ltd.VLSI Mentor
an average that is quietly wrong
int total = 7;
int count = 2;
int average = total / count;    /* 3, not 3.5 */

Nothing warns you. The program runs, produces 3, and 3 is a plausible-looking average — which is exactly the third kind of failure Chapter 1.5 described, where the compiler has nothing to object to and the answer is wrong anyway.

Two honest ways out, depending on what you actually want:

If you want a whole number, say so and mean it. Integer division is often precisely correct: the number of full boxes that fit, the number of complete groups, a midpoint index. In those cases 3 is the right answer and no fix is needed.

If you want the fraction, the operands must not both be integers. Chapter 3.12 covers the rules for mixed types properly, and it is the right place for it — the fix involves conversions that have not been taught yet, and applying one without understanding it is how the next bug gets written.

The useful skill now is recognising the situation: whenever you see / between two integer values, ask whether the fractional part mattered.

6. What You Should Be Able to Say Now

  1. int / int produces an int, so a fractional answer cannot be the result.
  2. C discards the fractional part. 7 / 2 is 3.
  3. Discarding is not rounding. -7 / 2 is −3, where rounding down would give −4.
  4. The precise rule is truncation toward zero, required since C99 and therefore guaranteed on this curriculum's baseline.
  5. % gives the remainder, and its value is forced by the identity (a / b) * b + a % b == a.
  6. So % takes its sign from the left operand: -7 % 2 is −1.
  7. % can produce a negative result, which matters whenever the left operand can be negative.
  8. % requires integer operands.
  9. Dividing by zero is undefined behaviour, as is % 0.
  10. Nothing warns you when integer division silently drops a fraction you needed.

7. Exercise

Exercise 1 — predict, then run. Give the exact output for each: 9 / 4, 9 % 4, -9 / 4, -9 % 4, 9 / -4, 9 % -4.

Exercise 2 — check the identity. For a = -9 and b = 4, compute (a / b) * b + a % b step by step and confirm it gives −9. Say which of / and % you had to decide first, and why.

Exercise 3 — distinguish the models. Explain in two sentences why 7 / 2 cannot tell you whether C rounds or truncates, and which single example can.

Exercise 4 — find the bug. This is meant to report the average score. Say what it prints for these values, whether the compiler warns, and what category of failure from Chapter 1.5 this is:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
int points = 17;
int games = 5;
int average = points / games;
printf("average: %d\n", average);

Exercise 5 — decide whether it is a bug at all. For each use, say whether integer division is wrong or exactly right: the number of full 8-hour shifts in 30 hours; the average of five test scores; the midpoint index between positions 0 and 7; the price per item when splitting a cost.

Exercise 6 — reason about the sign. A program uses value % 2 to decide whether a number is even, and value can be negative. Explain what results are possible, and why comparing the result against 1 would be a mistake.

8. Summary

  • int / int gives an int, so a fractional result is impossible and the fraction is discarded.
  • Discarding is not rounding. -7 / 2 is −3; rounding down would give −4. The rule is truncation toward zero, guaranteed since C99.
  • % is forced by an identity, not by a separate rule: (a / b) * b + a % b == a.
  • So % follows the left operand's sign, and can produce a negative result.
  • % needs integer operands, and division or remainder by zero is undefined behaviour.
  • Nothing warns you. A dropped fraction produces a plausible wrong answer, which is the hardest kind of failure to notice.
  • Ask, every time you see / between integers, whether the fraction mattered.

Every expression so far has produced a value and left its operands alone. Chapter 3.1 mentioned that some expressions do more than that — they change something — and the most common of them is one you have been using since Chapter 2.1 without ever being told it was an expression at all.

Standards & specifications

Governing standard
ISO/IEC 9899 (the C language standard)(opens ISO/IEC (JTC 1/SC 22/WG 14) in a new tab)

Defines the C language itself — the type system, expression semantics, object model, storage duration and the behaviour categories a conforming implementation must honour. It is a FAMILY of editions (C89/C90, C99, C11, C17, C23) and this curriculum names the edition wherever a claim depends on one. It does not define any foreign-function interface to a hardware description language, and it does not define platform behaviour: what a memory-mapped access does on real silicon is the implementation's and the device's contract, not this standard's. Working drafts published by WG14 are freely available and are what most engineers read day to day; a draft is not the published standard.

This page also covers RTL structure, verification approach and debugging technique. Those are engineering practice built on the standard, not requirements the standard itself imposes.

Where this fits

Part of the C Programming curriculum.