Learning Goals
3 minBy the end of this lesson you will be able to:
- Use
+ - * /and the remainder operator%. - Round a price to two decimal places with
.toFixed(2). - Explain why
0.1 + 0.2does not print0.3. - Turn text like
'12'into a real number withNumber().
Warm-Up · Splitting the Bill
5 minLast lesson you built receipts with template literals. Now four friends split a bill of RM 47.
const bill = 47;
const friends = 4;
console.log(bill / friends);Predict together
- What exactly will the console print?
- Is that an amount you could actually hand over in cash?
Reveal
11.7511.75 is fine here — 75 sen exists. But 47 / 3 gives 15.666666666666666, which you cannot pay. Today you learn to round it sensibly.
New Concept · Doing Sums Properly
12 minA calculator has a handful of buttons that cover almost everything. JavaScript is the same — five symbols do the bulk of the work, and one of them is probably new to you.
The five operators
console.log(7 + 3); // add
console.log(7 - 3); // subtract
console.log(7 * 3); // multiply
console.log(7 / 3); // divide
console.log(7 % 3); // remainder10
4
21
2.3333333333333335
1% is the remainder (often called modulo). It answers “what is left over?”. Seven roti canai shared between three people: each gets 2, and 1 is left on the plate.
The most common use is testing whether a number divides evenly. If n % 2 is 0, n is even.
const tables = 12;
console.log(tables % 2); // 0, so an even number of tablesOrder matters
JavaScript follows the same rules you use in maths: multiply and divide before add and subtract. Brackets win over everything.
console.log(2 + 3 * 4); // 3*4 first
console.log((2 + 3) * 4); // brackets first14
20The floating-point surprise
Type this into the console. The answer is famously wrong:
console.log(0.1 + 0.2);0.30000000000000004This is not a bug in your code. Computers store numbers in binary, and some decimals — like 0.1 — cannot be written exactly in binary, just as one third cannot be written exactly as a decimal. The tiny error shows up when you add them.
Every programming language does this. The fix is not to avoid decimals, but to round when you display.
Rounding
const share = 47 / 3;
console.log(share.toFixed(2)); // 2 decimal places, as text
console.log(Math.round(share)); // nearest whole number
console.log(Math.ceil(share)); // always up
console.log(Math.floor(share)); // always down15.67
16
16
15.toFixed(2)
Gives back a string, not a number.
Perfect for showing money: RM 15.67.
Never do further maths on the result.
Math.round()
Gives back a number.
Use it when you still need to calculate.
Math.ceil up, Math.floor down.
Text that looks like a number
Anything a visitor types into a form arrives as a string, even if it looks numeric. Number() converts it.
const typed = '12';
console.log(typed + 3); // string joining
console.log(Number(typed) + 3); // real addition
console.log(Number('nasi lemak')); // not a number at all123
15
NaNNaN means Not a Number. It is what you get when a sum makes no sense. Seeing NaN on a page nearly always means text sneaked into your maths.
Why it matters
Your Level 2 capstones total a shopping basket and score a quiz. Both break in exactly these two ways: text that should have been a number, and prices that need rounding before you show them.
Worked Example · Splitting a Mamak Bill
12 minBuild this in split.js. Aisyah, Wei Jie and Priya are splitting supper three ways.
Step 1 — The order
// split.js — supper for three
const nasiLemak = 5.5;
const rotiCanai = 1.5;
const milo = 3.0;
const friends = 3;
const subtotal = nasiLemak + rotiCanai + milo;
console.log(`Subtotal: RM ${subtotal}`);Subtotal: RM 10Step 2 — Add service charge
Ten per cent means multiplying by 0.1:
const SERVICE_RATE = 0.1; // 10% — a constant, so name it clearly
const service = subtotal * SERVICE_RATE;
const total = subtotal + service;
console.log(`Service: RM ${service}`);
console.log(`Total: RM ${total}`);Service: RM 1
Total: RM 11Step 3 — Split it, and meet the ugly number
const each = total / friends;
console.log(`Each pays: RM ${each}`);Each pays: RM 3.6666666666666665Correct, but nobody can pay that. Round it for display:
console.log(`Each pays: RM ${each.toFixed(2)}`);Each pays: RM 3.67Step 4 — The rounding gap
Three people paying RM 3.67 hand over RM 11.01 — one sen too much. Real tills give the remainder to one person. Work it out in sen, where everything is whole numbers:
const totalSen = Math.round(total * 100); // 1100 sen
const baseSen = Math.floor(totalSen / friends); // 366 sen each
const leftover = totalSen % friends; // 2 sen left over
console.log(`Two pay RM ${(baseSen / 100).toFixed(2)}`);
console.log(`One pays RM ${((baseSen + leftover) / 100).toFixed(2)}`);Two pay RM 3.66
One pays RM 3.68What changed? By counting in sen, the maths stayed on whole numbers and the floating-point problem disappeared. The % operator told us exactly how many sen were left to hand to somebody. Real payment systems store money in the smallest unit for exactly this reason.
Try It Yourself
13 minWork in split.js or a new maths.js.
Task 1 — Your own supper
Change the order to four items of your choosing, split between five friends. Print the subtotal, the service charge and the amount each person pays, rounded to two decimal places.
Task 2 — Change from RM 50
Add a variable
paid = 50. Print how much change is due, and use%to work out how many whole RM 10 notes are in that change.const change = paid - total; const tenNotes = Math.floor(change / 10);Print both, with a sentence explaining each.
Task 3 — Odd or even seats
A cinema numbers its seats 1 to 20. Using
%, print whether seat number 13 is on the odd or even side of the aisle.You do not know
ifstatements yet — that is next lesson. For now just print the result ofseat % 2and say in a comment what it means.
🔥 Mini-Challenge · The NaN Receipt
8 minKavitha's till is showing nonsense. Find two problems.
// kavitha-till.js — buggy
const priceTyped = '8.50'; // came from a form
const quantity = 3;
const total = priceTyped * quantity + 'RM';
console.log('Total: ' + total);
const each = total / 2;
console.log('Half each: RM ' + each.toFixed(2));It works if: the console shows a total of RM 25.50 and a half-share of RM 12.75, with no NaN anywhere.
Reveal the answer
Problem 1 — the currency is glued onto the number.
priceTyped * quantity actually works — JavaScript is helpful and converts the string for multiplication, giving 25.5. But then + 'RM' turns the answer back into the string '25.5RM'.
So total / 2 is '25.5RM' / 2, which is NaN, and NaN.toFixed(2) prints NaN.
Total: 25.5RM
Half each: RM NaNProblem 2 — no conversion and no rounding.
Rely on Number() rather than JavaScript guessing, and keep currency in the display string only.
// kavitha-till.js — fixed
const priceTyped = '8.50';
const price = Number(priceTyped); // convert once, on the way in
const quantity = 3;
const total = price * quantity; // stays a number
console.log(`Total: RM ${total.toFixed(2)}`);
const each = total / 2;
console.log(`Half each: RM ${each.toFixed(2)}`);Total: RM 25.50
Half each: RM 12.75The rule worth keeping: convert on the way in, format on the way out. In between, keep everything as numbers.
Recap
3 min+ - * /work as expected;%gives the remainder.n % 2 === 0is the usual test for “is it even?”.- Multiply and divide happen before add and subtract; brackets win.
0.1 + 0.2is not exactly0.3— that is binary, not a bug..toFixed(2)gives a string for display;Math.round()gives a number for maths.- Form input is text —
Number()it before calculating, or you getNaN. - For money, counting in sen keeps the sums on whole numbers.
New words
- Operator — a symbol that combines values (
+,%). - Remainder / modulo — what is left after dividing.
- Floating point — how computers store decimals, with tiny rounding errors.
- NaN — “Not a Number”, the result of a sum that makes no sense.
📦 Homework
4 min to brief · ~20 min to doRequired
- Write
tickets.jsfor a cinema. Given a ticket price, a number of tickets and a 6% SST rate, print the subtotal, the tax and the grand total — each on its own line, each rounded to two decimals. - Add one line using
%that prints how many seats are left over when your group is seated in rows of 4. Bring the file next lesson.
Optional stretch
- Try
Number.isInteger(4.0)andNumber.isInteger(4.5)in the console. Write one sentence on when that would be useful. - Search for
Intl.NumberFormatand see if you can printRM 1,234.50with the comma in the right place.