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

C#
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
Output
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:

C#
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
Output
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:

C#
int items = 10;
int boxes = 0;
Console.WriteLine(items / boxes);
Output
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:

C#
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}");
}
Output
-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:

C#
double x = 0.1 + 0.2;
Console.WriteLine(x);
Console.WriteLine(x == 0.3);
Console.WriteLine(Math.Abs(x - 0.3) < 1e-9);
Output
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":

C#
Console.WriteLine(1.0 / 0);
Console.WriteLine(-1.0 / 0);
Console.WriteLine(0.0 / 0);
Console.WriteLine(double.IsNaN(0.0 / 0));
Output
∞
-∞
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:

C#
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);
Output
0.3
True
59.97

Use double for scientific and physical quantities (distances, temperatures, statistics) and decimal for money.

The Math class

C#
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));
Output
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:

C#
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));
Output
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:

C#
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:

C#
var rng = new Random(42);
for (int i = 0; i < 5; i++)
{
    Console.Write(rng.Next(1, 7) + " ");
}
Console.WriteLine();
Output
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.

Try it yourself · Program.cs
Edit the code, copy it into Program.cs and run it with dotnet run Program.cs (.NET 10 or later). How to set up .NET
Output
Total with tip: 100.5100
Each person pays: 33.50