Numbers and Math
Arithmetic in C# mostly works the way you'd expect, but a few details trip up every beginner: dividing two integers drops the fraction, integers can overflow, and double can't represent some decimals exactly. This lesson covers those rules, when to use decimal, the Math class and generating random numbers.
Arithmetic operators
int a = 17, b = 5; Console.WriteLine(a + b); Console.WriteLine(a - b); Console.WriteLine(a * b); Console.WriteLine(a / b); // integer division Console.WriteLine(a % b); // remainder
22 12 85 3 2
Integer division
When both operands are integers, / gives an integer result and throws away the fractional part. To get a fractional answer, make at least one operand a floating-point number:
int total = 7; int people = 2; Console.WriteLine(total / people); Console.WriteLine((double)total / people); Console.WriteLine(total / 2.0); Console.WriteLine(-7 / 2); // truncates towards zero Console.WriteLine(-7 % 2); // remainder takes the sign of the left operand
3 3.5 3.5 -3 -1
The remainder operator % is useful for checking divisibility (n % 2 == 0 means even) and for wrapping values around, like hours on a clock.
Dividing an integer by zero throws an error at run time:
int items = 10; int boxes = 0; Console.WriteLine(items / boxes);
Unhandled exception. System.DivideByZeroException: Attempted to divide by zero.
You'll learn to catch exceptions like this in lesson 52.
Overflow
If an integer calculation goes past the type's limit, it silently wraps around by default. Inside a checked block (or expression), overflow throws an exception instead:
int max = int.MaxValue; int wrapped = max + 1; Console.WriteLine(wrapped); try { int safe = checked(max + 1); Console.WriteLine(safe); } catch (OverflowException e) { Console.WriteLine($"Caught: {e.Message}"); }
-2147483648 Caught: Arithmetic operation resulted in an overflow.
If your numbers might get big, use long — or System.Numerics.BigInteger, which has no limit at all.
Floating-point precision
double stores numbers in binary, and many decimal fractions (such as 0.1) have no exact binary form. Tiny rounding errors appear:
double x = 0.1 + 0.2; Console.WriteLine(x); Console.WriteLine(x == 0.3); Console.WriteLine(Math.Abs(x - 0.3) < 1e-9);
0.30000000000000004 False True
Never compare doubles with == after calculations; check whether they're within a small tolerance instead. Dividing a double by zero doesn't throw — it produces infinity or "not a number":
Console.WriteLine(1.0 / 0); Console.WriteLine(-1.0 / 0); Console.WriteLine(0.0 / 0); Console.WriteLine(double.IsNaN(0.0 / 0));
∞ -∞ NaN True
decimal for money
decimal works in base 10, so values like 0.1 are stored exactly. It's slower than double, but it's the right choice for prices, balances and anything financial:
decimal a = 0.1m + 0.2m; Console.WriteLine(a); Console.WriteLine(a == 0.3m); decimal price = 19.99m; decimal total = price * 3; Console.WriteLine(total);
0.3 True 59.97
Use double for scientific and physical quantities (distances, temperatures, statistics) and decimal for money.
The Math class
Console.WriteLine(Math.Sqrt(144)); Console.WriteLine(Math.Pow(2, 10)); Console.WriteLine(Math.Abs(-7.5)); Console.WriteLine(Math.Max(3, 9)); Console.WriteLine(Math.Min(3, 9)); Console.WriteLine(Math.Clamp(150, 0, 100)); Console.WriteLine(Math.Floor(4.7)); Console.WriteLine(Math.Ceiling(4.2)); Console.WriteLine(Math.Truncate(-4.7)); Console.WriteLine(Math.PI); Console.WriteLine(Math.Round(Math.PI, 3));
12 1024 7.5 9 3 100 4 5 -4 3.141592653589793 3.142
Rounding surprises
Math.Round uses banker's rounding by default: a value exactly halfway rounds to the nearest even number. This avoids a bias when rounding many values, but it isn't what you learned at school. Pass MidpointRounding.AwayFromZero for the usual rule:
Console.WriteLine(Math.Round(2.5)); Console.WriteLine(Math.Round(3.5)); Console.WriteLine(Math.Round(2.5, MidpointRounding.AwayFromZero)); Console.WriteLine(Math.Round(2.345m, 2)); Console.WriteLine(Math.Round(2.345m, 2, MidpointRounding.AwayFromZero));
2 4 3 2.34 2.35
Random numbers
Random.Shared is a ready-to-use random number generator. Next(min, max) returns an integer from min up to but not including max:
int dice = Random.Shared.Next(1, 7); // 1 to 6 double fraction = Random.Shared.NextDouble(); // 0.0 up to 1.0 Console.WriteLine($"You rolled {dice}");
If you create a Random with a fixed seed, it produces the same sequence every run, which is useful for repeatable tests and simulations:
var rng = new Random(42); for (int i = 0; i < 5; i++) { Console.Write(rng.Next(1, 7) + " "); } Console.WriteLine();
5 1 1 4 2
For passwords, tokens or anything security-related, use System.Security.Cryptography.RandomNumberGenerator instead — Random is predictable.
Try it yourself
Split a restaurant bill between friends. Try changing the number of people, and see what happens if you use int instead of decimal.
Total with tip: 100.5100 Each person pays: 33.50