How to round numbers up, down, or to nearest
Control how JavaScript rounds decimal numbers when formatting with different rounding modes
Introduction
When you format numbers for display, you often need to round decimal values. A price of $2.567 needs to become $2.57. A measurement of 3.891 meters might display as 4 meters. The way you round these numbers affects accuracy, user expectations, and business logic.
Different situations call for different rounding strategies. Sometimes you need to round up to ensure you charge enough for a product. Sometimes you need to round down to stay within a budget. Most often, you round to the nearest value to maintain accuracy.
JavaScript provides nine different rounding modes through the Intl.NumberFormat API. These modes control how numbers round when they fall between two possible values. This lesson explains the three most common rounding modes and shows when to use the others.
How JavaScript rounds numbers by default
When you format a number without specifying a rounding mode, JavaScript uses a strategy called halfExpand. This mode rounds values to the nearest possible value, and when a number falls exactly halfway between two values, it rounds away from zero.
const formatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 0
});
console.log(formatter.format(2.4));
// Output: "2"
console.log(formatter.format(2.5));
// Output: "3"
console.log(formatter.format(2.6));
// Output: "3"
The value 2.4 is closer to 2 than to 3, so it rounds down to 2. The value 2.6 is closer to 3 than to 2, so it rounds up to 3. The value 2.5 falls exactly halfway between 2 and 3, so the halfExpand mode rounds it away from zero to 3.
This default behavior matches what most people learn in school and expect in everyday calculations. It distributes rounding errors evenly over many calculations, making it suitable for general purpose number formatting.
Understanding what away from zero means
The phrase "away from zero" describes the direction of rounding for numbers that fall exactly halfway between two possible values. For positive numbers, rounding away from zero means rounding up. For negative numbers, rounding away from zero means rounding down to a larger magnitude.
const formatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 0
});
console.log(formatter.format(2.5));
// Output: "3"
console.log(formatter.format(-2.5));
// Output: "-3"
Both 2.5 and -2.5 round away from zero. For 2.5, away from zero means toward positive infinity, producing 3. For -2.5, away from zero means toward negative infinity, producing -3. In both cases, the magnitude increases.
Rounding up with ceil
The ceil rounding mode always rounds toward positive infinity. For positive numbers, this means rounding up. For negative numbers, this means rounding toward zero.
const formatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 0,
roundingMode: "ceil"
});
console.log(formatter.format(2.1));
// Output: "3"
console.log(formatter.format(2.9));
// Output: "3"
console.log(formatter.format(-2.1));
// Output: "-2"
console.log(formatter.format(-2.9));
// Output: "-2"
This mode is useful when you need to ensure a number is never smaller than necessary. For example, if you calculate that a box can hold 2.3 items, you need 3 boxes. If you calculate that a task takes 1.1 days, you need to plan for 2 days.
const boxFormatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 0,
roundingMode: "ceil"
});
const itemsPerBox = 5;
const totalItems = 12;
const boxesNeeded = totalItems / itemsPerBox;
console.log(boxFormatter.format(boxesNeeded));
// Output: "3"
The calculation produces 2.4 boxes, but you cannot order a fraction of a box. Rounding up ensures you have enough capacity.
Rounding down with floor
The floor rounding mode always rounds toward negative infinity. For positive numbers, this means rounding down. For negative numbers, this means rounding away from zero.
const formatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 0,
roundingMode: "floor"
});
console.log(formatter.format(2.1));
// Output: "2"
console.log(formatter.format(2.9));
// Output: "2"
console.log(formatter.format(-2.1));
// Output: "-3"
console.log(formatter.format(-2.9));
// Output: "-3"
This mode is useful when you need conservative estimates or when you want to stay within limits. For example, if you have a budget of $100.87, you might display it as $100 to avoid accidentally overspending.
const budgetFormatter = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
maximumFractionDigits: 0,
roundingMode: "floor"
});
const availableBudget = 100.87;
console.log(budgetFormatter.format(availableBudget));
// Output: "$100"
Rounding down ensures the displayed amount is always achievable with the actual budget.
Rounding to nearest with halfExpand
While halfExpand is the default, you can specify it explicitly to make your intent clear in the code. This mode rounds to the nearest value and handles halfway cases by rounding away from zero.
const formatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 1,
roundingMode: "halfExpand"
});
console.log(formatter.format(2.14));
// Output: "2.1"
console.log(formatter.format(2.15));
// Output: "2.2"
console.log(formatter.format(2.16));
// Output: "2.2"
The value 2.14 is closer to 2.1, so it rounds to 2.1. The value 2.16 is closer to 2.2, so it rounds to 2.2. The value 2.15 falls exactly halfway, so it rounds away from zero to 2.2.
This mode works well for most number formatting tasks because it minimizes the total rounding error across many calculations. Each halfway value has an equal chance of being the positive or negative side of zero, so the rounding direction balances out over time.
Combining rounding modes with fraction digits
Rounding modes work together with fraction digit settings to control the final output. The maximumFractionDigits option determines how many decimal places appear, and the roundingMode determines how to handle values that fall between representable numbers.
const ceilFormatter = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
minimumFractionDigits: 2,
maximumFractionDigits: 2,
roundingMode: "ceil"
});
console.log(ceilFormatter.format(10.001));
// Output: "$10.01"
console.log(ceilFormatter.format(10.999));
// Output: "$11.00"
With two decimal places, 10.001 needs to round to either 10.00 or 10.01. The ceil mode rounds up, producing 10.01. The value 10.999 rounds up to 11.00.
Rounding toward zero with trunc
The trunc rounding mode rounds toward zero, which means it removes the fractional part of the number. For positive numbers, this rounds down. For negative numbers, this rounds up.
const formatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 0,
roundingMode: "trunc"
});
console.log(formatter.format(2.1));
// Output: "2"
console.log(formatter.format(2.9));
// Output: "2"
console.log(formatter.format(-2.1));
// Output: "-2"
console.log(formatter.format(-2.9));
// Output: "-2"
This mode effectively truncates the decimal portion. It is useful when you want to show only the integer part of a number without considering the fractional value for rounding purposes.
Rounding away from zero with expand
The expand rounding mode rounds away from zero. For positive numbers, this rounds up. For negative numbers, this rounds down to a larger magnitude.
const formatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 0,
roundingMode: "expand"
});
console.log(formatter.format(2.1));
// Output: "3"
console.log(formatter.format(2.9));
// Output: "3"
console.log(formatter.format(-2.1));
// Output: "-3"
console.log(formatter.format(-2.9));
// Output: "-3"
This mode ensures that rounding always increases the magnitude of the number. It can be useful in financial contexts where you want to be conservative in a direction that favors accuracy over underestimation.
Understanding halfway rounding modes
The five modes that start with half all round to the nearest value, but they differ in how they handle exact halfway cases. These modes give you fine control over tie-breaking behavior when values fall exactly between two representable numbers.
The halfCeil mode rounds halfway values toward positive infinity.
const formatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 0,
roundingMode: "halfCeil"
});
console.log(formatter.format(2.5));
// Output: "3"
console.log(formatter.format(-2.5));
// Output: "-2"
The halfFloor mode rounds halfway values toward negative infinity.
const formatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 0,
roundingMode: "halfFloor"
});
console.log(formatter.format(2.5));
// Output: "2"
console.log(formatter.format(-2.5));
// Output: "-3"
The halfTrunc mode rounds halfway values toward zero.
const formatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 0,
roundingMode: "halfTrunc"
});
console.log(formatter.format(2.5));
// Output: "2"
console.log(formatter.format(-2.5));
// Output: "-2"
The halfEven mode rounds halfway values to the nearest even number. This mode is sometimes called banker's rounding because it reduces bias in financial calculations.
const formatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 0,
roundingMode: "halfEven"
});
console.log(formatter.format(2.5));
// Output: "2"
console.log(formatter.format(3.5));
// Output: "4"
console.log(formatter.format(4.5));
// Output: "4"
The value 2.5 rounds to 2 because 2 is even. The value 3.5 rounds to 4 because 4 is even. The value 4.5 also rounds to 4 because 4 is even.
Choosing a rounding mode for your application
The rounding mode you choose depends on your business requirements and the nature of the data you display. Different contexts call for different strategies.
Use ceil when you need to ensure sufficiency. Capacity planning, inventory counts, and time estimates often require rounding up to guarantee adequate resources.
Use floor when you need to stay within limits. Budget displays, quota tracking, and discount calculations often require rounding down to avoid exceeding available resources.
Use halfExpand for general purpose display where accuracy matters but extreme precision is not critical. This is the default for a reason and works well for most number formatting tasks.
Use halfEven for financial calculations where you need to minimize cumulative rounding bias. This mode ensures that, over many calculations, rounding errors do not consistently favor one direction.
Use trunc when you want to display only the integer portion of a number without applying rounding logic to the fractional part.
Using rounding modes with currency formatting
Rounding modes interact naturally with currency formatting. Different businesses have different rules about how to round currency values, and the roundingMode option lets you implement those rules.
const retailPrice = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
minimumFractionDigits: 2,
maximumFractionDigits: 2,
roundingMode: "ceil"
});
const wholesalePrice = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
minimumFractionDigits: 2,
maximumFractionDigits: 2,
roundingMode: "floor"
});
const calculatedPrice = 19.874;
console.log(retailPrice.format(calculatedPrice));
// Output: "$19.88"
console.log(wholesalePrice.format(calculatedPrice));
// Output: "$19.87"
A retailer might round prices up to ensure profitability, while a wholesaler might round down to stay competitive. The same calculated price produces different displayed values based on the business rules encoded in the rounding mode.