Arithmetic

The five arithmetic operators in C#, why 7 / 2 is 3, the sign rule for remainders, and which operator runs first.

Syntaxa + b a - b a * b a / b a % b

Arithmetic operators do sums on numbers. C# has five: + adds, - subtracts, * multiplies, / divides, and % gives what is left over after a division. That last one is called the remainder operator, or modulo. They exist because almost every program counts, totals or measures something.

Division cares about the types

When both sides of / are whole numbers, the result is a whole number. The fraction is thrown away, not rounded. So 13 / 5 is 2. The throwing away goes toward zero, so -13 / 5 is -2 and not -3. To keep the fraction, make one side a decimal number: 13 / 5.0 is 2.6.

% follows that same division. 13 % 5 is 3. A remainder that is not zero takes the sign of the left operand, so -5 % 4 is -1 and 5 % -4 is 1.

Which operator runs first

*, / and % run before + and -, so 2 + 2 * 2 is 6. Operators of equal rank run left to right, so 9 / 5 / 2 is 0. Round brackets override both rules.

What trips people up

Whole-number division by zero throws DivideByZeroException. The same division on double values throws nothing and produces Infinity. An int result too large for an int wraps round to a negative number without complaint, unless the expression sits in a checked block, which throws OverflowException instead.

Example

Example · csharp
int apples = 7;
int baskets = 2;

Console.WriteLine(apples + baskets);
Console.WriteLine(apples - baskets);
Console.WriteLine(apples * baskets);

// Both sides are whole numbers, so the answer is whole: the .5 is discarded.
Console.WriteLine(apples / baskets);

// % is what is left over after that division.
Console.WriteLine(apples % baskets);

// Making one side a decimal number keeps the fraction.
Console.WriteLine(apples / 2.0);

// Truncation goes toward zero, so this is -3 and not -4.
Console.WriteLine(-7 / 2);

// A non-zero remainder takes the sign of the left operand.
Console.WriteLine(-7 % 2);

// * / % run before + and -. Brackets change the order.
Console.WriteLine(2 + 3 * 4);
Console.WriteLine((2 + 3) * 4);

// Output:
// 9
// 5
// 14
// 3
// 1
// 3.5
// -3
// -1
// 14
// 20

When to use it

  • Work out a line total as quantity times unit price, then add tax.
  • Turn a row count into page numbers with / for the page and % for the position on it.
  • Shade every other row in a report by testing whether index % 2 is 0.
  • Convert a duration in seconds into hours, minutes and seconds for display.

More examples

Splitting one number with / and %

Integer division and remainder are a pair: one gives the whole units, the other gives what is left to break down further. This is the standard way to turn a count of seconds into hours and minutes, a count of items into pages, or a byte count into kilobytes. Reach for it whenever one number has to become several.

Example · csharp
int totalSeconds = 3725;

// / gives how many whole units fit, % gives the leftover to pass down.
int hours = totalSeconds / 3600;
int minutes = totalSeconds % 3600 / 60;   // left to right: (3725 % 3600) / 60
int seconds = totalSeconds % 60;

Console.WriteLine($"{hours}h {minutes}m {seconds}s");

// Output:
// 1h 2m 5s

When an int runs out of room

By default C# does not check whole-number arithmetic for overflow: the extra bits are dropped and you get a wrong answer rather than an error. Putting the expression in a checked block makes it throw OverflowException instead, which is what you want when the number came from outside your program. The last two lines show that an int division in the middle of a longer sum has already lost its fraction by the time the next operator sees it.

Example · csharp
int big = int.MaxValue;   // the largest value an int can hold

Console.WriteLine(big);

// One more does not throw by default. It wraps round to the smallest int.
Console.WriteLine(big + 1);

// Truncation happens the moment the / is evaluated, not at the end.
int narrow = 7;
Console.WriteLine(narrow / 2 * 2);

// Output:
// 2147483647
// -2147483648
// 6

double is approximate, decimal is not

The same + behaves differently depending on the type it is given. double is fine for measurements and physics, where a tiny error does not matter. It is the wrong choice for amounts of money, where the printed total must match to the penny; decimal, written with an m suffix on the literal, is the type for that. The m is required, because 0.1 on its own is a double.

Example · csharp
// double stores numbers in binary, so some decimal fractions are approximate.
double a = 0.1;
double b = 0.2;
Console.WriteLine(a + b);

// decimal keeps decimal digits exactly, at the cost of speed. Use it for money.
decimal price = 0.1m;
decimal tax = 0.2m;
Console.WriteLine(price + tax);

// Output:
// 0.30000000000000004
// 0.3

Discussion

  • Be the first to comment on this lesson.