JavaScript Numbers and Math Object Complete Guide

Master number types, precision handling, Math methods, and formatting techniques

JavaScript Numbers and Math Object Complete Guide

Number handling in JavaScript is fundamental to daily development. This article covers various uses of number types and the Math object.

Number Types

Basic Concepts

// JavaScript has only one number type
const integer = 42;
const float = 3.14159;
const negative = -17;
const scientific = 1.5e6;  // 1500000

// Special values
const infinity = Infinity;
const negInfinity = -Infinity;
const notANumber = NaN;

// Type checking
typeof 42;         // 'number'
typeof 3.14;       // 'number'
typeof NaN;        // 'number'
typeof Infinity;   // 'number'

Number Literals

// Integers
const decimal = 255;       // Decimal
const hex = 0xff;          // Hexadecimal
const octal = 0o377;       // Octal
const binary = 0b11111111; // Binary

// Numeric separators (ES2021)
const billion = 1_000_000_000;
const bytes = 0xff_ff_ff_ff;
const fraction = 0.000_001;

// BigInt (large integers)
const bigInt = 9007199254740993n;
const bigFromString = BigInt('9007199254740993');

Number Range

// Safe integer range
Number.MAX_SAFE_INTEGER;  // 9007199254740991 (2^53 - 1)
Number.MIN_SAFE_INTEGER;  // -9007199254740991

// Maximum/minimum values
Number.MAX_VALUE;  // 1.7976931348623157e+308
Number.MIN_VALUE;  // 5e-324 (smallest positive)

// Check safe integer
Number.isSafeInteger(9007199254740991);  // true
Number.isSafeInteger(9007199254740992);  // false

// Precision issue example
9007199254740992 === 9007199254740993;  // true (dangerous!)

Number Conversion

String to Number

// parseInt - parse integer
parseInt('42');          // 42
parseInt('42.9');        // 42
parseInt('  42  ');      // 42
parseInt('42px');        // 42
parseInt('px42');        // NaN

// Specify radix
parseInt('ff', 16);      // 255
parseInt('1010', 2);     // 10
parseInt('777', 8);      // 511

// parseFloat - parse float
parseFloat('3.14');      // 3.14
parseFloat('3.14.15');   // 3.14
parseFloat('  3.14  ');  // 3.14

// Number() - strict conversion
Number('42');      // 42
Number('42.5');    // 42.5
Number('42px');    // NaN
Number('');        // 0
Number(null);      // 0
Number(undefined); // NaN

// Unary plus (most concise)
+'42';       // 42
+'3.14';     // 3.14
+'';         // 0
+null;       // 0
+undefined;  // NaN

Number to String

const num = 42.5;

// toString
num.toString();      // '42.5'
num.toString(2);     // '101010.1' (binary)
num.toString(16);    // '2a.8' (hexadecimal)

// String()
String(num);         // '42.5'

// Template literal
`${num}`;            // '42.5'

// toFixed - fixed decimal places
(3.14159).toFixed(2);    // '3.14'
(3.1).toFixed(3);        // '3.100'

// toExponential - scientific notation
(12345).toExponential(2);  // '1.23e+4'

// toPrecision - significant digits
(3.14159).toPrecision(3);  // '3.14'
(12345).toPrecision(3);    // '1.23e+4'

Number Checking

Validity Checks

// isNaN - global function (converts type)
isNaN(NaN);          // true
isNaN('hello');      // true (becomes NaN after conversion)
isNaN(42);           // false

// Number.isNaN - strict check
Number.isNaN(NaN);       // true
Number.isNaN('hello');   // false (no conversion)
Number.isNaN(42);        // false

// isFinite - check finite number
isFinite(42);         // true
isFinite(Infinity);   // false
isFinite(NaN);        // false

// Number.isFinite - strict check
Number.isFinite(42);      // true
Number.isFinite('42');    // false (no conversion)

// Number.isInteger - check integer
Number.isInteger(42);     // true
Number.isInteger(42.0);   // true
Number.isInteger(42.5);   // false

Comparison Operations

// Equality comparison
42 === 42;     // true
NaN === NaN;   // false (special!)

// Use Object.is for comparison
Object.is(NaN, NaN);  // true
Object.is(0, -0);     // false

// Comparing floats (avoid direct comparison)
0.1 + 0.2 === 0.3;  // false!

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

// Or custom tolerance
function nearlyEqual(a, b, tolerance = 1e-10) {
  return Math.abs(a - b) < tolerance;
}

Math Object

Constants

Math.PI;      // 3.141592653589793
Math.E;       // 2.718281828459045
Math.LN2;     // 0.6931471805599453
Math.LN10;    // 2.302585092994046
Math.LOG2E;   // 1.4426950408889634
Math.LOG10E;  // 0.4342944819032518
Math.SQRT2;   // 1.4142135623730951
Math.SQRT1_2; // 0.7071067811865476

Rounding Methods

const num = 4.7;

// floor - round down
Math.floor(4.7);   // 4
Math.floor(-4.7);  // -5

// ceil - round up
Math.ceil(4.3);    // 5
Math.ceil(-4.3);   // -4

// round - round to nearest
Math.round(4.5);   // 5
Math.round(4.4);   // 4
Math.round(-4.5);  // -4 (note!)

// trunc - truncate decimals
Math.trunc(4.9);   // 4
Math.trunc(-4.9);  // -4

// Round to decimal places
function roundTo(num, decimals) {
  const factor = 10 ** decimals;
  return Math.round(num * factor) / factor;
}

roundTo(3.14159, 2);  // 3.14

Maximum/Minimum

// max / min
Math.max(1, 5, 3);     // 5
Math.min(1, 5, 3);     // 1

// Handle arrays
const arr = [1, 5, 3, 9, 2];
Math.max(...arr);      // 9
Math.min(...arr);      // 1

// Empty arguments
Math.max();  // -Infinity
Math.min();  // Infinity

// Clamp to range
function clamp(value, min, max) {
  return Math.min(Math.max(value, min), max);
}

clamp(15, 0, 10);  // 10
clamp(-5, 0, 10);  // 0
clamp(5, 0, 10);   // 5

Powers and Roots

// pow - exponentiation
Math.pow(2, 3);    // 8
2 ** 3;            // 8 (ES2016)

// sqrt - square root
Math.sqrt(16);     // 4
Math.sqrt(-1);     // NaN

// cbrt - cube root
Math.cbrt(27);     // 3

// Natural log and exponential
Math.exp(1);       // 2.718... (e^1)
Math.log(Math.E);  // 1
Math.log10(100);   // 2
Math.log2(8);      // 3

// hypot - hypotenuse length
Math.hypot(3, 4);  // 5

Random Numbers

// random - 0 to 1 (excluding 1)
Math.random();  // 0.xxx...

// Random integer in range
function randomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

randomInt(1, 10);  // between 1-10

// Random float in range
function randomFloat(min, max) {
  return Math.random() * (max - min) + min;
}

randomFloat(0, 100);  // between 0-100

// Random array element
function randomElement(arr) {
  return arr[Math.floor(Math.random() * arr.length)];
}

// Shuffle array
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;
}

Trigonometric Functions

// Basic trig functions (arguments in radians)
Math.sin(Math.PI / 2);  // 1
Math.cos(0);            // 1
Math.tan(Math.PI / 4);  // 1

// Inverse trig functions
Math.asin(1);   // 1.5707... (π/2)
Math.acos(0);   // 1.5707... (π/2)
Math.atan(1);   // 0.7853... (π/4)

// atan2 - angle between two points
Math.atan2(1, 1);  // 0.7853... (π/4)

// Hyperbolic functions
Math.sinh(0);  // 0
Math.cosh(0);  // 1
Math.tanh(0);  // 0

// Radians to degrees
function toDegrees(radians) {
  return radians * (180 / Math.PI);
}

// Degrees to radians
function toRadians(degrees) {
  return degrees * (Math.PI / 180);
}

Other Methods

// abs - absolute value
Math.abs(-5);    // 5

// sign - sign
Math.sign(-5);   // -1
Math.sign(5);    // 1
Math.sign(0);    // 0

// Logarithms
Math.log(Math.E);    // 1
Math.log10(1000);    // 3
Math.log2(1024);     // 10
Math.log1p(0);       // 0 (ln(1+x))

// Float operations
Math.fround(1.5);    // 1.5 (32-bit float)
Math.imul(2, 3);     // 6 (32-bit integer multiplication)

Number Formatting

Intl.NumberFormat

// Basic formatting
const num = 1234567.89;

new Intl.NumberFormat('en-US').format(num);
// '1,234,567.89'

new Intl.NumberFormat('de-DE').format(num);
// '1.234.567,89'

// Currency format
new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD'
}).format(num);
// '$1,234,567.89'

new Intl.NumberFormat('ja-JP', {
  style: 'currency',
  currency: 'JPY'
}).format(num);
// '¥1,234,568'

// Percentage
new Intl.NumberFormat('en-US', {
  style: 'percent',
  minimumFractionDigits: 2
}).format(0.1234);
// '12.34%'

// Compact notation
new Intl.NumberFormat('en-US', {
  notation: 'compact'
}).format(1234567);
// '1.2M'

Custom Formatting

// Thousand separators
function formatNumber(num) {
  return num.toLocaleString();
}

// Fixed decimal places
function formatDecimal(num, digits = 2) {
  return num.toFixed(digits);
}

// File size
function formatBytes(bytes) {
  const units = ['B', 'KB', 'MB', 'GB', 'TB'];
  let i = 0;
  while (bytes >= 1024 && i < units.length - 1) {
    bytes /= 1024;
    i++;
  }
  return `${bytes.toFixed(2)} ${units[i]}`;
}

formatBytes(1234567890);  // '1.15 GB'

Precision Handling

Floating Point Issues

// Classic problem
0.1 + 0.2;  // 0.30000000000000004
0.1 + 0.2 === 0.3;  // false

// Reason: Binary cannot precisely represent some decimals

Solutions

// Solution 1: Use integer arithmetic
function addMoney(a, b) {
  // Convert to cents for calculation
  return (a * 100 + b * 100) / 100;
}

addMoney(0.1, 0.2);  // 0.3

// Solution 2: Fixed decimal comparison
function isEqual(a, b, precision = 10) {
  return a.toFixed(precision) === b.toFixed(precision);
}

// Solution 3: Use specialized libraries
// decimal.js, bignumber.js, big.js, etc.

// Solution 4: Epsilon comparison
function nearlyEqual(a, b, epsilon = Number.EPSILON) {
  return Math.abs(a - b) < epsilon;
}

Best Practices Summary

Number Handling Best Practices:
┌─────────────────────────────────────────────────────┐
│                                                     │
│   Type Conversion                                   │
│   ├── Simple conversion: use unary plus +          │
│   ├── Parse strings with units: parseInt/parseFloat│
│   └── Strict conversion: use Number()              │
│                                                     │
│   Value Checking                                    │
│   ├── Use Number.isNaN instead of isNaN            │
│   ├── Use Number.isFinite instead of isFinite      │
│   └── Check large integers: Number.isSafeInteger   │
│                                                     │
│   Precision Handling                                │
│   ├── Financial: use integers or specialized libs  │
│   ├── Float comparison: use epsilon                │
│   └── Display: use toFixed                         │
│                                                     │
└─────────────────────────────────────────────────────┘
OperationRecommended MethodExample
RoundingMath.floor/ceil/roundMath.round(4.5)
RandomMath.random()randomInt(1, 10)
FormattingIntl.NumberFormatformat(12345)
PrecisiontoFixed(3.14).toFixed(1)

Master number handling techniques to avoid common precision pitfalls.