C# Variables: float, double, and decimal
C# Variables: float, double, and decimal
C# provides three common types for storing numbers with fractional values: float, double, and decimal. The correct choice depends on the required precision, memory usage, performance, and whether the value represents money or another human-facing quantity.
The core difference
The core difference is how they represent fractions:
float and double are binary floating-point (base-2) — they approximate decimal fractions
decimal is base-10 — it stores decimal fractions exactly
float
Size: 4 bytes
Precision: Approximately 7 digits
Range: Approximately ±3.4 × 10³⁸
Base: Binary
Stores 0.1 exactly? No
Suffix: f
Use for: Graphics, games, and large arrays
double
Size: 8 bytes
Precision: Approximately 15–17 digits
Range: Approximately ±1.7 × 10³⁰⁸
Base: Binary
Stores 0.1 exactly? No
Suffix: Default; no suffix is required
Use for: General mathematics and science
decimal
Size: 16 bytes
Precision: 28–29 digits
Range: Approximately ±7.9 × 10²⁸
Base: Decimal
Stores 0.1 exactly? Yes
Suffix: m
Use for: Money, finance, and user-facing numbers
Why it matters — the classic example:
double a = 0.1 + 0.2;
Console.WriteLine(a == 0.3); // False! (0.30000000000000004)
decimal b = 0.1m + 0.2m;
Console.WriteLine(b == 0.3m); // True
float and double can't represent 0.1 exactly in binary (same reason you can't write ⅓ in base-10). The tiny error accumulates with every operation. decimal avoids this entirely because it works in base-10.
Rule of thumb:
Need speed and don't care about the last digit → double (it's the default)
Storing millions of values where memory matters → float
Calculating money or anything a human will read → decimal
Declaring the variables
A suffix tells C# which type a numeric literal should use:
float gameSpeed = 4.75f;
double distance = 149_600_000.0;
decimal productPrice = 19.99m;
A real-number literal without a suffix is a double. Therefore, this code is invalid:
// float value = 3.5; // Error: 3.5 is a double literal
float value = 3.5f; // Correct
The f suffix creates a float, while the m suffix creates a decimal. The double type is the default for unsuffixed fractional literals.
Usage and advantages
float
Use float when memory usage is important and extreme precision is unnecessary. It is common in games, 3D graphics, animation, colors, sensor data, and very large numerical arrays.
float x = 10.25f;
float y = 3.5f;
float total = x + y;
Its main advantage is that it uses only 4 bytes per value. Its disadvantage is lower precision and a greater chance of rounding error.
double
Use double for general mathematical, scientific, engineering, statistical, and geometric calculations.
double radius = 6.5;
double area = Math.PI * radius * radius;
double provides much more precision than float and supports a very large range of values. It is usually the best default for approximate calculations. However, it should not normally be used for financial calculations because binary rounding can produce unexpected results.
decimal
Use decimal for prices, invoices, account balances, taxes, interest rates, and other values where decimal precision is important.
decimal price = 89.95m;
decimal taxRate = 0.20m;
decimal total = price + price * taxRate;
Console.WriteLine($"Total: {total:C2}");
decimal provides high precision for decimal fractions, but it uses more memory than float or double and is generally less suitable for high-performance scientific or graphics calculations.
Variable scope
The scope of a variable determines where it can be accessed. The rules are the same for float, double, and decimal.
A variable declared inside a method is a local variable. It can be used only within its containing block:
static void CalculateArea(double radius)
{
double area = Math.PI * radius * radius;
Console.WriteLine(area);
}
A variable declared inside an if statement or loop has a narrower scope:
static void CalculateTotal(decimal price)
{
decimal total = price;
if (price > 0m)
{
decimal tax = price * 0.20m;
total += tax;
Console.WriteLine(tax);
}
Console.WriteLine(total);
// Console.WriteLine(tax); // Error: tax is out of scope
}
Parameters, such as radius and price, exist during the method call. Fields belong to an object or class and can be used by multiple methods according to their access modifier.
Conversions and comparisons
A float can be converted to double implicitly, but conversions involving decimal usually need an explicit cast:
float smallValue = 1.5f;
double largerValue = smallValue;
decimal price = 12.50m;
double rate = 1.2;
decimal total = price * (decimal)rate;
Conversions may lose precision, so they should be intentional. Also, use tolerance-based comparison for calculated float and double values:
double first = 0.1 + 0.2;
double second = 0.3;
bool nearlyEqual = Math.Abs(first - second) < 1e-12;
Final recommendation
Choose the type based on the meaning of the data:
Choose float for compact storage and large collections of approximate values.
Choose double for most general-purpose and scientific calculations.
Choose decimal for money and decimal quantities that users expect to calculate accurately.
Keep calculations in one numeric type whenever possible, add the correct literal suffix, and avoid using direct equality with calculated float or double values.

Comments
Post a Comment