Q1What happens when you run console.log(10 / 4);?
Numbers and Arithmetic — the Number Type and Math
Learn the Number type: remainder and exponents, rounding with Math, aligning digits with toFixed, and decimal errors.
A lot of what a web app calculates comes down to numbers — an order subtotal, sales tax, shipping, points earned. JavaScript has no separate types for integers and decimals; it handles both with the same Number type.
This article covers the arithmetic operators, including remainder and exponents, rounding with Math, aligning digits with toFixed, and the decimal precision errors that trip people up in money calculations.
One Number Type — Number and Arithmetic Operators
Some languages split integers and decimals into separate types. This notion of "kind of value" is called a type (the classification of a value — whether it's a number, text, and so on).
JavaScript makes no distinction between integers and decimals — 1200 and 0.08 are both the same Number type (the type that represents numbers). You never choose a type when declaring a variable, but the tradeoff is that dividing two integers can leave a decimal result.
Symbols that direct a calculation are called arithmetic operators (symbols that represent a calculation between values). Beyond addition +, subtraction -, multiplication *, and division /, there's % for the remainder of a division and ** for exponents.
% returns the remainder, and ** returns the power.console.log(1200 + 300); // 1500
console.log(1200 - 300); // 900
console.log(1200 * 3); // 3600
// Even with two integers, a leftover decimal remains if it doesn't divide evenly
console.log(7 / 2); // 3.5
// % is the remainder, ** is exponentiation
console.log(7 % 2); // 1
console.log(2 ** 10); // 1024
% is handy for finding a leftover amount, or "the remainder when split into groups of a fixed size." For a total of 4380, 4380 % 100 gives you 80 — the amount left over once you count in units of 100.
** gives you exponents, letting you calculate things like 2 ** 10 — the number of bytes in a kilobyte.
Rounding with Math — Floor, Ceiling, and Nearest
You can't put the average, 1903.3333333333333, straight on an invoice. Amounts and counts need rounding to a whole number somewhere, and whether you round down, up, or to the nearest value depends on business rules.
JavaScript groups these rounding functions under Math.
Let's introduce the term function first (a named unit that runs a fixed process on a value you pass it, and returns a result). Getting a result back from a value you passed in is described as "calling" it and having it "return" a value.
A function under Math (a built-in JavaScript collection of numeric functions) is called by writing Math, a dot, and then the function name — like Math.floor(1903.33).
Math.floor rounds a decimal down, Math.ceil rounds it up, and Math.round rounds to the nearest whole number. All three just return a new number — the variable you passed in stays the same.
const points = 149.8; // Points calculated from the purchase amount
console.log(Math.floor(points)); // 149 round down
console.log(Math.ceil(points)); // 150 round up
console.log(Math.round(points)); // 150 round to nearest
console.log(points); // 149.8 the original value doesn't change
// max returns whichever value you pass it is larger
console.log(Math.max(0, 5000 - 5200)); // 0
Another one you'll reach for outside of rounding is Math.max. It returns whichever value you pass it is larger, so Math.max(0, -120) is 0.
That gives you a floor for a calculation you don't want dropping below zero — useful for something like "how much more until free shipping."
Aligning Digits with toFixed — It Returns a String
Sometimes, like with an average amount, you want to decide the number of digits shown up front. Displaying 1903.3333333333333 as-is is hard to read, so you clean it up to one decimal place and show 1903.3.
Use toFixed for that.
toFixed is a method (a function you call by writing a dot after a value) — you call it with a dot after a number. A value passed inside the parentheses is called an argument (a value passed inside a function's or method's parentheses). Pass it the number of decimal places to keep, as in toFixed(1), and it rounds at the next digit down and returns the result kept to that many places. But what comes back is a string, not a number. Use it only right before displaying a value — for further calculation, use the original number or Math.round instead.
Math.floor(value) passes a value to a function that lives inside the Math container; value.toFixed(digits) calls a function the value itself carries. What comes before the dot tells you which form you're looking at.
const averageOrder = 1903.3333333333333; // Average amount per order
console.log(averageOrder.toFixed(1)); // 1903.3 returned as a string
console.log(averageOrder.toFixed(0)); // 1903 returned as a string
// To keep calculating, round while staying a number
console.log(Math.round(averageOrder * 10) / 10); // 1903.3 still a number
toFixed's Result Is for Display Only
Since what toFixed returns is a string, adding or multiplying that result behaves differently than it would with a number. The difference between strings and numbers, and how to check which one you have, are covered in the type conversion article.
Decimal Precision Error — Why 0.1 + 0.2 Isn't 0.3
Chain enough calculations involving decimals, and the answer can drift slightly off. This is what causes bugs like a total that's off by a cent, so let's look at why it happens and how to avoid it before it bites you.
Computers store numbers in binary. 0.1 in decimal doesn't divide evenly in binary — it becomes an infinitely repeating fraction — so it gets stored as a different, very close value instead.
0.1 and 0.2 are both stored slightly off, so adding them lands slightly off from 0.3 too.
console.log(0.1 + 0.2); // 0.30000000000000004
// Scale up to integers first, calculate, then scale back down — no drift
console.log((0.1 * 10 + 0.2 * 10) / 10); // 0.3
Store Amounts as Whole Numbers
The more decimal additions you chain, the more the drift compounds. For amounts of money, store them as whole-number units and only divide right before display — that sidesteps this error entirely.
Values from Failed Calculations — NaN and Infinity
When a calculation doesn't work out, JavaScript doesn't stop — it returns a special value and keeps going. A lot of bugs where a total shows up blank or an amount displays wrong come from this kind of value getting mixed into a calculation that just kept running.
A result that can't be expressed as a number is NaN (short for Not a Number — a value meaning the result couldn't become a number). 0 / 0, from trying to average a day with zero orders, is one example.
Dividing by zero the other way, as in 5710 / 0, returns Infinity (a value representing infinity). Neither stops with an error, so you might not notice until it shows up on screen.
const orderTotal = 5710;
const orderCount = 0; // There were 0 orders that day
console.log(orderTotal / orderCount); // Infinity
console.log(0 / 0); // NaN
// Once NaN gets mixed in, every calculation after it becomes NaN too
console.log(0 / 0 + 1000); // NaN
Just like Math, Number groups together its own set of number-related functions. You can check whether a value is a whole number with Number.isInteger. Number.isInteger(3) returns true and Number.isInteger(2.5) returns false — a boolean (a value representing one of two choices: whether something holds true) — so it's useful for confirming a value like a count that shouldn't allow decimals.
How to check whether two values are equal is covered in the next article, but NaN is the one exception — it doesn't even equal itself using that method.
So checking for NaN uses a dedicated check instead. That's covered, along with converting strings to numbers, in the type conversion article.
console.log(Number.isInteger(3)); // true
console.log(Number.isInteger(2.5)); // false
console.log(Number.isInteger(6 / 2)); // true an even division is a whole number
NaN and Infinity flow into the next calculation without ever stopping on an error. When a total or average displays wrong, suspect a division by zero first — it's usually the fastest way to find the cause.
Knowledge Check
Answer each question one by one.
Q2What does calling toFixed(2) on a number return?
Q3What does console.log(0.1 + 0.2); display?