1. What kinds of numbers are there?
In programming, we're always working with numbers — from a user's age to the number of stars in a galaxy or cents in a bank account. But different tasks need different kinds of numbers: sometimes you only need to store whole numbers, sometimes super-precise fractions, and sometimes you need numbers "without negatives."
Integers (int and others)
An integer is a number without a fractional part.
In C#, the most common type is int, but there are a few more options that differ in size and range.
- int — the main "workhorse" type for integers. It can hold really big (and small) values, and doesn't take up much memory.
For example, for counting likes, age, number of days in a year, you'll almost always use int. - long — use this if your values might get huge (like billions or trillions).
Example: storing the total number of YouTube views ever. - short — a memory-saving but rarely used type. Good when you have lots of small, similar values (like audio data, color components).
- byte — for even smaller values, especially in graphics and file work where memory savings matter.
Floating-point numbers (double, float, decimal)
Sometimes you need to work with numbers that have a fractional part. For example, air temperature, a student's GPA, or a product price with cents.
- double — this is the "default" type for storing floating-point numbers. Accurate enough for most calculations (example: 3.1415926535…).
- float — a lighter and less precise type, more common in computer graphics or when processing huge data arrays where memory savings are important.
- decimal — meant for financial and accounting stuff, when you need to keep accuracy down to the last cent, so you don't "lose" anything because of how floating-point numbers are stored. For example, for storing account balances, product prices, exchange rates.
Special numeric types
C# has extra numeric types for special cases:
- uint, ulong, ushort — "unsigned" types, only let you use positive values, but the range is twice as big compared to their "signed" twins.
- sbyte — a small, signed type (for compact storage of negative and positive values from -128 to 127).
- BigInteger — if you need to work with gigantic numbers that go beyond the standard ranges, like in cryptography or astronomy calculations.
2. Signed and unsigned numbers
A signed type can store both positive and negative numbers. That's handy when values can be "above or below zero": like temperature, account balance, altitude relative to sea level.
An unsigned type — only zero and positive numbers. Good when negatives just don't make sense — like number of people in a room, bytes in a file, time.
Example:
- int (signed): -10, 0, 50
- uint (unsigned): 0, 10, 1000
By using an unsigned type, you can fit twice the max value in a variable (since there's no "negative half of the range"). They're used when you know for sure the value can't be negative.
Signed integer types
| Type | Size | Value range | Example usage |
|---|---|---|---|
|
1 byte | -128 to 127 | -128, 0, 127 |
|
2 bytes | -32,768 to 32,767 | -1000, 0, 32000 |
|
4 bytes | -2,147,483,648 to 2,147,483,647 | -1000000, 0, 2000000 |
|
8 bytes | -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 |
-10_000_000_000, 1 |
Unsigned integer types
| Type | Size | Value range | Example usage |
|---|---|---|---|
|
1 byte | 0 to 255 | 0, 128, 255 |
|
2 bytes | 0 to 65,535 | 1000, 65000 |
|
4 bytes | 0 to 4,294,967,295 | 100, 4000000000 |
|
8 bytes | 0 to 18,446,744,073,709,551,615 | 1, 18_000_000_000_000 |
Floating-point types
| Type | Size | Example values | Description |
|---|---|---|---|
|
4 bytes | 3.14f, -0.001f | single precision (7 digits) |
|
8 bytes | 3.1415, -1.7E+308 | double precision (15-16 digits) |
|
16 bytes | 0.1m, 12345.6789m | high precision for finance |
3. Number suffixes
Sometimes you gotta say exactly what type you want your number to be. You do this with suffixes:
- L or l — for long (like 10000000000L)
- U or u — for uint (like 123U)
- F or f — for float (like 3.14f)
- D or d — for double (usually not needed, because floating-point numbers without a suffix are double)
- M or m — for decimal (like 99.99m — super important for money!)
If you don't use a suffix, by default an integer is int, and a floating-point number is double. For example, 42 is int, and 3.14 is double.
Why bother? For example, so you don't get an error when assigning a big number to a long variable:
long bigNumber = 9000000000L; // if you remove the L, you'll get a compile error
And for money, you should always use decimal with the m suffix:
decimal price = 999.99m;
4. Underscore separator _
When numbers get long, it's easy to get lost in the zeros. For readability and style, C# lets you use underscores inside numbers.
int population = 146_700_000;
long stars = 100_000_000_000L;
This is totally legit: the compiler ignores underscores, and it's way easier for you to see the digits at a glance. Just don't put an underscore at the start, end, after a dot, or before a suffix.
5. Character type char
Sometimes in your program you need to work not with numbers, but with individual characters: a letter, a digit, a symbol, even a space. For that, there's a special type — char.
What's char?
It's a variable that stores one character:
- a Latin or Cyrillic letter ('A', 'я')
- a digit ('5')
- a special symbol ('#', '%', '@')
- a control character ('\\n' — newline)
Features:
- The value of a char is written in single quotes: char letter = 'B';
- Actually, inside char is the numeric code of the character (in Unicode), so you can compare chars, convert them to int, and even do simple math:
char a = 'A';
char b = (char)(a + 1); // 'B'
int code = a; // 65 — code for 'A'
You can use special characters, for example: char tab = '\\t'; // tab character
Why use char?
For working with text one character at a time (like checking the first letter in a string, finding punctuation, reading a password character by character).
GO TO FULL VERSION