DEV Community

Alex Chen
Alex Chen

Posted on

JavaScript Number Tricks Every Developer Should Know (2026)

JavaScript Number Tricks Every Developer Should Know (2026)

Numbers in JavaScript are weirder than you think. Here are the tricks that save me from bugs.

The Big Gotcha: Floating Point

0.1 + 0.2 === 0.3    // false!
0.1 + 0.2            // 0.30000000000000004
Enter fullscreen mode Exit fullscreen mode

This isn't a JavaScript bug — it's how IEEE 754 floating point works.

Fix #1: Comparing Numbers

// ❌ Never use == or === for floats
if (a === b) { ... }     // Dangerous!

// ✅ Use epsilon comparison
function approxEqual(a, b, epsilon = Number.EPSILON) {
  return Math.abs(a - b) < epsilon;
}

approxEqual(0.1 + 0.2, 0.3)   // true
Enter fullscreen mode Exit fullscreen mode

Fix #2: Currency (Never Use Floats!)

// ❌ WRONG
const price = 19.99;
const tax = price * 0.088;      // 1.7591200000000002
const total = price + tax;     // 21.7491200000000002

// ✅ Option A: Work in cents (integers)
const priceCents = 1999;
const taxCents = Math.round(priceCents * 88 / 1000); // 176
const totalCents = priceCents + taxCents; // 2175
console.log((totalCents / 100).toFixed(2)); // "21.75"

// ✅ Option B: Round at display time
const total = parseFloat((price * 1.088).toFixed(2)); // "21.75"

// ✅ Option C: Use a library (for serious financial apps)
// intl-numberformat, currency.js, or dinero.js
Enter fullscreen mode Exit fullscreen mode

Useful Number Methods

Rounding Done Right

const num = 42.6789;

Math.round(num);    // 43 (rounds to nearest)
Math.floor(num);    // 42 (always down)
Math.ceil(num);     // 43 (always up)
Math.trunc(num);    // 42 (removes decimal)

num.toFixed(2);     // "42.68" (returns STRING, not number!)
num.toPrecision(4); // "42.68" (significant digits)

// ⚠️ toFixed returns a string! Don't do math with it:
parseFloat(num.toFixed(2)) + 1; // 43.68 ✓
num.toFixed(2) + 1;            // "42.681" ✗ (string concat!)
Enter fullscreen mode Exit fullscreen mode

Clamping Values

// Keep number between min and max
function clamp(value, min, max) {
  return Math.min(Math.max(value, min), max);
}

clamp(-5, 0, 100);   // 0
clamp(50, 0, 100);   // 50
clamp(150, 0, 100);  // 100

// Or with Math.clamp (newer browsers/Node)
Math.clamp(-5, 0, 100); // 0
Enter fullscreen mode Exit fullscreen mode

Random Numbers

// Basic random
Math.random();                    // 0.123... (0 ≤ x < 1)

// Random integer between min and max (inclusive)
function randomInt(min, max) {
  min = Math.ceil(min);
  max = Math.floor(max);
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

randomInt(1, 10);   // 1-10 inclusive
randomInt(0, 1);    // 0 or 1 (coin flip)

// Random element from array
const items = ['rock', 'paper', 'scissors'];
items[Math.floor(Math.random() * items.length)];

// Shuffle array (Fisher-Yates)
function shuffle(arr) {
  const result = [...arr];
  for (let i = result.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [result[i], result[j]] = [result[j], result[i]];
  }
  return result;
}

shuffle([1, 2, 3, 4, 5]); // [3, 1, 5, 2, 4] (random order)

// Random hex color
'#' + Math.floor(Math.random()*16777215).toString(16).padStart(6, '0');
// "#a3f2c1"

// Random ID generator
Math.random().toString(36).substring(2, 10);
// "x7k2m9np"
Enter fullscreen mode Exit fullscreen mode

Number Formatting

// Add commas to large numbers
function formatNumber(num) {
  return num.toLocaleString('en-US');
}

formatNumber(1000000);       // "1,000,000"
formatNumber(1234567.89);    // "1,234,567.89"
formatNumber(0.9876);        // "0.988" (auto rounds)

// Currency formatting
function formatCurrency(amount, currency = 'USD') {
  return new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency,
  }).format(amount);
}

formatCurrency(1234.56);        // "$1,234.56"
formatCurrency(1234.56, 'EUR');  // "€1,234.56"
formatCurrency(1234.56, 'JPY');  // "¥1,235" (no decimals for JPY)

// Percentage
function formatPercent(num, decimals = 1) {
  return new Intl.NumberFormat('en-US', {
    style: 'percent',
    minimumFractionDigits: decimals,
    maximumFractionDigits: decimals,
  }).format(num);
}

formatPercent(0.867);   // "86.7%"
formatPercent(0.05);     // "5.0%"

// Compact notation (1.2K, 3.4M)
function formatCompact(num) {
  return new Intl.NumberFormat('en-US', {
    notation: 'compact',
    compactDisplay: 'short',
  }).format(num);
}

formatCompact(1500);     // "1.5K"
formatCompact(2500000);  // "2.5M"
formatCompact(999500);   // "1M" (not 999K)

// Bytes to human readable
function formatBytes(bytes, decimals = 2) {
  if (bytes === 0) return '0 Bytes';
  const k = 1024;
  const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return parseFloat((bytes / Math.pow(k, i)).toFixed(decimals)) + ' ' + sizes[i];
}

formatBytes(1024);           // "1 KB"
formatBytes(1048576);         // "1 MB"
formatBytes(1073741824);      // "1 GB"
formatBytes(15360000);       // "14.65 MB"
Enter fullscreen mode Exit fullscreen mode

Parsing Numbers Safely

// ❌ Dangerous
parseInt('123abc');    // 123 (silently ignores non-numbers!)
parseInt('');          // NaN
parseInt(null);        // NaN
parseInt(true);        // NaN
parseInt('0x10');      // 16 (hex! might not be what you want)
parseFloat('  42.5 ');   // 42.5 (trims whitespace)

// ✅ Safe parsing
function safeParseInt(val, fallback = 0) {
  const parsed = parseInt(val, 10);
  return isNaN(parsed) ? fallback : parsed;
}

function safeParseFloat(val, fallback = 0) {
  const parsed = parseFloat(val);
  return isNaN(parsed) ? fallback : parsed;
}

safeParseInt('123abc', 0);  // 123 (still accepts this)
safeParseInt('abc', 0);      // 0 ← fallback
safeParseInt('', -1);        // -1 ← fallback

// ✅ Even safer: validate first
function isNumeric(str) {
  if (typeof str === 'number') return !isNaN(str);
  if (typeof str !== 'string') return false;
  return !isNaN(str) && !isNaN(parseFloat(str)) && isFinite(str);
}

isNumeric('42');       // true
isNumeric('42px');      // false
isNumeric('');          // false
isNumeric(null);        // false
isNumeric(Infinity);    // false
Enter fullscreen mode Exit fullscreen mode

Math Tricks That Save Time

// Min/Max without Math.min/max (for small arrays)
const min = [3, 1, 4, 1, 5].sort((a,b)=>a-b)[0]; // 1
const max = [...[3, 1, 4, 1, 5]].sort((a,b)=>b-a)[0]; // 5

// But Math is faster for large arrays:
Math.min(...[3, 1, 4, 1, 5]); // 1
Math.max(...[3, 1, 4, 1, 5]); // 5

// ⚠️ Math.max/min spread can overflow the stack for huge arrays (>~65K elements)

// Power of 2 check
function isPowerOf2(n) {
  return n > 0 && (n & (n - 1)) === 0;
}
isPowerOf2(8);    // true
isPowerOf2(7);    // false
isPowerOf2(1024); // true

// Between two numbers
function between(n, min, max) {
  return n >= min && n <= max;
}
// Or clamp it: Math.min(max, Math.max(min, n))

// Distance between two numbers
function distance(a, b) {
  return Math.abs(a - b);
}

// Linear interpolation (lerp)
function lerp(start, end, t) {
  return start + (end - start) * t;
}
lerp(0, 100, 0.5); // 50
lerp(0, 100, 0.25); // 25

// Map value from one range to another
function mapRange(value, inMin, inMax, outMin, outMax) {
  return outMin + ((outMax - outMin) * (value - inMin)) / (inMax - inMin);
}
mapRange(5, 0, 10, 0, 100); // 50
mapRange(7, 0, 10, 0, 1);   // 0.7

// Average
function average(...nums) {
  return nums.reduce((a, b) => a + b, 0) / nums.length;
}
average(1, 2, 3, 4, 5); // 3

// Median
function median(nums) {
  const sorted = [...nums].sort((a, b) => a - b);
  const mid = Math.floor(sorted.length / 2);
  return sorted.length % 2 !== 0
    ? sorted[mid]
    : (sorted[mid - 1] + sorted[mid]) / 2;
}
median([1, 2, 3, 4, 5]); // 3
median([1, 2, 3, 4]);    // 2.5

// Sum
function sum(nums) {
  return nums.reduce((a, b) => a + b, 0);
}
sum([1, 2, 3, 4, 5]); // 15

// Percent change
function percentChange(oldVal, newVal) {
  if (oldVal === 0) return newVal > 0 ? Infinity : 0;
  return ((newVal - oldVal) / Math.abs(oldVal)) * 100;
}
percentChange(100, 150);   // 50 (% increase)
percentChange(100, 50);    // -50 (% decrease)
percentChange(0, 50);      // Infinity (from zero)
Enter fullscreen mode Exit fullscreen mode

Weird JavaScript Number Facts

// These are all TRUE in JavaScript:

typeof NaN === 'number'              // NaN IS a number type!
NaN === NaN                        // false (NaN is never equal to itself)
Number.isNaN(NaN)                   // true (correct way to check)

Infinity === 1/0                     // true
-Infinity === -1/0                  // true
1 / 0 === Infinity                 // true
0 / 0 === NaN                      // true

Number.MAX_VALUE + 1 === Number.MAX_VALUE  // true (overflow stays at MAX)
Number.MIN_VALUE > 0                       // true (smallest positive fraction)
Number.MAX_SAFE_INTEGER === 9007199254740991  // 2^53 - 1
Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2  // true (precision lost!)

Number.isInteger(42)    // true
Number.isInteger(42.0)  // true
Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 1)  // false

// ParseInt quirks:
parseInt(1e21);        // 1 (too big for int)
parseInt('1e21');      // 1 (same)
parseInt('0x10');      // 16 (hex detected)
parseInt('010');       // 10 (old behavior was octal, now decimal)
parseInt('');           // NaN
parseInt(null);         // NaN
parseInt([]);           // 0 (!!! coerces to "")
parseInt([5]);         // 5 (!!! coerces to "5")

// Bitwise operators truncate to 32-bit integers:
| 0;                    // 0 (fast floor for positive numbers)
~~1.9;                 // 1 (double tilde = fast Math.floor for positives)
1.9 | 0;               // 1
Enter fullscreen mode Exit fullscreen mode

Quick Reference Card

Task Code
Round to 2 decimals +(n.toFixed(2)) or Math.round(n*100)/100
Integer from float Math.trunc(n) or `n \
Clamp {% raw %}Math.min(max, Math.max(min, n))
Random int 1-10 Math.floor(Math.random() * 10) + 1
Is integer? Number.isInteger(n)
Is safe int? Number.isSafeInteger(n)
Is NaN? Number.isNaN(n) (NOT global isNaN!)
Format as $ n.toLocaleString('en-US',{style:'currency'})
Parse safely parseInt(str, 10) always specify radix!
Sum array arr.reduce((a,b)=>a+b, 0)
Unique random IDs Math.random().toString(36).slice(2)

What's your favorite number trick?

Follow @armorbreak for more practical JS guides.

Top comments (0)