How to use numbers and basic math in JavaScript
How to Use Numbers and Basic Math in JavaScript
JavaScript provides robust support for numerical operations and mathematical calculations, making it an excellent language for building applications that require computational functionality. Whether you're creating a simple calculator, processing financial data, or implementing complex algorithms, understanding how to work with numbers and perform mathematical operations is fundamental to JavaScript development.
This comprehensive guide will walk you through everything you need to know about using numbers and basic math in JavaScript, from fundamental concepts to advanced techniques and best practices.
Table of Contents
1. [Prerequisites](#prerequisites)
2. [Understanding JavaScript Numbers](#understanding-javascript-numbers)
3. [Number Types and Representation](#number-types-and-representation)
4. [Basic Arithmetic Operations](#basic-arithmetic-operations)
5. [The Math Object](#the-math-object)
6. [Number Methods and Properties](#number-methods-and-properties)
7. [Type Conversion and Parsing](#type-conversion-and-parsing)
8. [Working with Floating Point Numbers](#working-with-floating-point-numbers)
9. [Advanced Mathematical Operations](#advanced-mathematical-operations)
10. [Common Use Cases and Examples](#common-use-cases-and-examples)
11. [Troubleshooting Common Issues](#troubleshooting-common-issues)
12. [Best Practices](#best-practices)
13. [Conclusion](#conclusion)
Prerequisites
Before diving into JavaScript numbers and math operations, you should have:
- Basic understanding of JavaScript syntax and variables
- Familiarity with JavaScript data types
- Knowledge of how to run JavaScript code (browser console, Node.js, or code editor)
- Understanding of basic mathematical concepts
Understanding JavaScript Numbers
JavaScript uses a single number type to represent all numeric values, unlike many other programming languages that have separate types for integers and floating-point numbers. All numbers in JavaScript are stored as 64-bit floating-point values, following the IEEE 754 standard.
Number Declaration and Assignment
```javascript
// Different ways to declare numbers
let integer = 42;
let decimal = 3.14159;
let negative = -25;
let scientific = 2.5e6; // 2,500,000
let binary = 0b1010; // 10 in decimal
let octal = 0o755; // 493 in decimal
let hexadecimal = 0xFF; // 255 in decimal
console.log(integer); // 42
console.log(decimal); // 3.14159
console.log(scientific); // 2500000
```
Special Number Values
JavaScript includes several special numeric values:
```javascript
// Special values
console.log(Infinity); // Positive infinity
console.log(-Infinity); // Negative infinity
console.log(NaN); // Not a Number
// Examples of operations resulting in special values
console.log(1 / 0); // Infinity
console.log(-1 / 0); // -Infinity
console.log(0 / 0); // NaN
console.log("hello" * 2); // NaN
```
Number Types and Representation
Integer vs Floating Point
While JavaScript treats all numbers as floating-point internally, you can work with both integers and decimals:
```javascript
// Integers (whole numbers)
let count = 100;
let temperature = -5;
let zero = 0;
// Floating-point numbers (decimals)
let price = 19.99;
let percentage = 0.75;
let precise = 0.1 + 0.2; // 0.30000000000000004 (floating-point precision issue)
console.log(Number.isInteger(100)); // true
console.log(Number.isInteger(100.5)); // false
```
Number Limits and Precision
JavaScript numbers have specific limits and precision constraints:
```javascript
// Maximum and minimum safe integers
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
console.log(Number.MIN_SAFE_INTEGER); // -9007199254740991
// Maximum and minimum values
console.log(Number.MAX_VALUE); // 1.7976931348623157e+308
console.log(Number.MIN_VALUE); // 5e-324
// Checking if numbers are safe
console.log(Number.isSafeInteger(9007199254740991)); // true
console.log(Number.isSafeInteger(9007199254740992)); // false
```
Basic Arithmetic Operations
JavaScript supports all fundamental arithmetic operations with intuitive syntax:
Addition, Subtraction, Multiplication, and Division
```javascript
let a = 10;
let b = 3;
// Basic operations
let sum = a + b; // 13
let difference = a - b; // 7
let product = a * b; // 30
let quotient = a / b; // 3.3333333333333335
console.log(`${a} + ${b} = ${sum}`);
console.log(`${a} - ${b} = ${difference}`);
console.log(`${a} * ${b} = ${product}`);
console.log(`${a} / ${b} = ${quotient}`);
```
Modulus and Exponentiation
```javascript
let x = 17;
let y = 5;
// Modulus (remainder)
let remainder = x % y; // 2
console.log(`${x} % ${y} = ${remainder}`);
// Exponentiation
let power = x y; // 1419857 (17^5)
console.log(`${x} ${y} = ${power}`);
// Alternative exponentiation using Math.pow()
let powerAlt = Math.pow(x, y); // 1419857
console.log(`Math.pow(${x}, ${y}) = ${powerAlt}`);
```
Assignment Operators
```javascript
let num = 10;
// Compound assignment operators
num += 5; // num = num + 5; // 15
num -= 3; // num = num - 3; // 12
num = 2; // num = num 2; // 24
num /= 4; // num = num / 4; // 6
num %= 5; // num = num % 5; // 1
num = 3; // num = num 3; // 1
console.log(num); // 1
```
Increment and Decrement Operators
```javascript
let counter = 5;
// Pre-increment and post-increment
console.log(++counter); // 6 (increment first, then return)
console.log(counter++); // 6 (return first, then increment)
console.log(counter); // 7
// Pre-decrement and post-decrement
console.log(--counter); // 6 (decrement first, then return)
console.log(counter--); // 6 (return first, then decrement)
console.log(counter); // 5
```
The Math Object
The Math object provides a collection of mathematical constants and functions for more advanced calculations:
Mathematical Constants
```javascript
// Common mathematical constants
console.log(Math.PI); // 3.141592653589793
console.log(Math.E); // 2.718281828459045 (Euler's number)
console.log(Math.LN2); // 0.6931471805599453 (natural log of 2)
console.log(Math.LN10); // 2.302585092994046 (natural log of 10)
console.log(Math.LOG2E); // 1.4426950408889634 (base-2 log of E)
console.log(Math.LOG10E); // 0.4342944819032518 (base-10 log of E)
console.log(Math.SQRT2); // 1.4142135623730951 (square root of 2)
```
Basic Math Functions
```javascript
let num = -4.7;
// Absolute value
console.log(Math.abs(num)); // 4.7
// Rounding functions
console.log(Math.round(4.7)); // 5
console.log(Math.round(4.4)); // 4
console.log(Math.ceil(4.1)); // 5 (round up)
console.log(Math.floor(4.9)); // 4 (round down)
console.log(Math.trunc(4.9)); // 4 (remove decimal part)
// Min and max
console.log(Math.min(1, 3, 2)); // 1
console.log(Math.max(1, 3, 2)); // 3
console.log(Math.min(...[5, 2, 8, 1])); // 1 (using spread operator)
```
Power and Root Functions
```javascript
// Square root and cube root
console.log(Math.sqrt(16)); // 4
console.log(Math.cbrt(27)); // 3
// Power functions
console.log(Math.pow(2, 8)); // 256
console.log(Math.pow(9, 0.5)); // 3 (square root of 9)
// Exponential and logarithmic functions
console.log(Math.exp(1)); // 2.718281828459045 (e^1)
console.log(Math.log(Math.E)); // 1 (natural logarithm)
console.log(Math.log10(100)); // 2 (base-10 logarithm)
console.log(Math.log2(8)); // 3 (base-2 logarithm)
```
Trigonometric Functions
```javascript
// Trigonometric functions (angles in radians)
let angle = Math.PI / 4; // 45 degrees
console.log(Math.sin(angle)); // 0.7071067811865476
console.log(Math.cos(angle)); // 0.7071067811865476
console.log(Math.tan(angle)); // 0.9999999999999999
// Convert degrees to radians
function degreesToRadians(degrees) {
return degrees * (Math.PI / 180);
}
// Convert radians to degrees
function radiansToDegrees(radians) {
return radians * (180 / Math.PI);
}
console.log(Math.sin(degreesToRadians(30))); // 0.5
console.log(radiansToDegrees(Math.PI)); // 180
```
Random Number Generation
```javascript
// Generate random numbers
console.log(Math.random()); // Random number between 0 and 1
// Random integer between min and max (inclusive)
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
console.log(randomInt(1, 10)); // Random integer between 1 and 10
// Random float between min and max
function randomFloat(min, max) {
return Math.random() * (max - min) + min;
}
console.log(randomFloat(1.5, 5.5)); // Random float between 1.5 and 5.5
```
Number Methods and Properties
Number Constructor Methods
```javascript
// Check for various number types
console.log(Number.isInteger(42)); // true
console.log(Number.isInteger(42.0)); // true
console.log(Number.isInteger(42.5)); // false
console.log(Number.isFinite(42)); // true
console.log(Number.isFinite(Infinity)); // false
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN("hello")); // false (string is not NaN)
console.log(Number.isSafeInteger(42)); // true
console.log(Number.isSafeInteger(Math.pow(2, 53))); // false
```
Number Instance Methods
```javascript
let num = 123.456789;
// Convert to string with specified precision
console.log(num.toFixed(2)); // "123.46"
console.log(num.toFixed(0)); // "123"
// Convert to exponential notation
console.log(num.toExponential(2)); // "1.23e+2"
// Convert with specified precision
console.log(num.toPrecision(5)); // "123.46"
console.log(num.toPrecision(3)); // "123"
// Convert to string
console.log(num.toString()); // "123.456789"
console.log(num.toString(16)); // "7b.74bc6a7ef9db" (hexadecimal)
```
Type Conversion and Parsing
Converting Strings to Numbers
```javascript
// Using Number() constructor
console.log(Number("123")); // 123
console.log(Number("123.45")); // 123.45
console.log(Number("123abc")); // NaN
console.log(Number("")); // 0
console.log(Number(" ")); // 0
// Using parseInt() for integers
console.log(parseInt("123")); // 123
console.log(parseInt("123.45")); // 123
console.log(parseInt("123abc")); // 123
console.log(parseInt("abc123")); // NaN
// Using parseFloat() for floating-point numbers
console.log(parseFloat("123.45")); // 123.45
console.log(parseFloat("123.45abc")); // 123.45
console.log(parseFloat("abc123.45")); // NaN
```
Implicit Type Conversion
```javascript
// Automatic conversion in arithmetic operations
console.log("5" * 2); // 10 (string converted to number)
console.log("10" - 3); // 7
console.log("10" / 2); // 5
console.log("10" % 3); // 1
// Addition is special - it concatenates if either operand is a string
console.log("5" + 2); // "52" (number converted to string)
console.log(5 + "2"); // "52"
// Using unary + operator for conversion
console.log(+"123"); // 123
console.log(+true); // 1
console.log(+false); // 0
console.log(+null); // 0
console.log(+undefined); // NaN
```
Working with Floating Point Numbers
Precision Issues
```javascript
// Common floating-point precision issues
console.log(0.1 + 0.2); // 0.30000000000000004
console.log(0.1 + 0.2 === 0.3); // false
// Solutions for precision issues
function roundToPrecision(num, precision) {
return Math.round(num * Math.pow(10, precision)) / Math.pow(10, precision);
}
console.log(roundToPrecision(0.1 + 0.2, 2)); // 0.3
// Using Number.EPSILON for comparison
function isEqual(a, b, epsilon = Number.EPSILON) {
return Math.abs(a - b) < epsilon;
}
console.log(isEqual(0.1 + 0.2, 0.3)); // true
```
Working with Decimal Places
```javascript
// Rounding to specific decimal places
function roundToDecimals(num, decimals) {
return Number(Math.round(num + "e" + decimals) + "e-" + decimals);
}
console.log(roundToDecimals(1.005, 2)); // 1.01
console.log(roundToDecimals(1.234567, 3)); // 1.235
// Using toFixed() and converting back to number
let price = 19.999;
let rounded = Number(price.toFixed(2));
console.log(rounded); // 20
```
Advanced Mathematical Operations
Complex Calculations
```javascript
// Calculate compound interest
function compoundInterest(principal, rate, time, frequency) {
return principal Math.pow(1 + rate / frequency, frequency time);
}
let investment = compoundInterest(1000, 0.05, 10, 12);
console.log(`Investment value: $${investment.toFixed(2)}`);
// Calculate distance between two points
function distance(x1, y1, x2, y2) {
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
}
console.log(distance(0, 0, 3, 4)); // 5
// Calculate factorial
function factorial(n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
console.log(factorial(5)); // 120
```
Statistical Functions
```javascript
// Calculate average
function average(numbers) {
return numbers.reduce((sum, num) => sum + num, 0) / numbers.length;
}
// Calculate median
function median(numbers) {
const sorted = numbers.slice().sort((a, b) => a - b);
const middle = Math.floor(sorted.length / 2);
if (sorted.length % 2 === 0) {
return (sorted[middle - 1] + sorted[middle]) / 2;
} else {
return sorted[middle];
}
}
// Calculate standard deviation
function standardDeviation(numbers) {
const avg = average(numbers);
const squaredDiffs = numbers.map(num => Math.pow(num - avg, 2));
const avgSquaredDiff = average(squaredDiffs);
return Math.sqrt(avgSquaredDiff);
}
let data = [2, 4, 4, 4, 5, 5, 7, 9];
console.log(`Average: ${average(data)}`); // 5
console.log(`Median: ${median(data)}`); // 4.5
console.log(`Standard Deviation: ${standardDeviation(data).toFixed(2)}`); // 2.14
```
Common Use Cases and Examples
Building a Calculator
```javascript
class Calculator {
constructor() {
this.result = 0;
}
add(num) {
this.result += num;
return this;
}
subtract(num) {
this.result -= num;
return this;
}
multiply(num) {
this.result *= num;
return this;
}
divide(num) {
if (num === 0) {
throw new Error("Division by zero is not allowed");
}
this.result /= num;
return this;
}
power(num) {
this.result = Math.pow(this.result, num);
return this;
}
sqrt() {
if (this.result < 0) {
throw new Error("Square root of negative number is not allowed");
}
this.result = Math.sqrt(this.result);
return this;
}
clear() {
this.result = 0;
return this;
}
getValue() {
return this.result;
}
}
// Usage example
const calc = new Calculator();
const result = calc.add(10).multiply(2).subtract(5).divide(3).getValue();
console.log(result); // 5
```
Financial Calculations
```javascript
// Loan payment calculator
function calculateLoanPayment(principal, annualRate, years) {
const monthlyRate = annualRate / 12 / 100;
const numberOfPayments = years * 12;
if (monthlyRate === 0) {
return principal / numberOfPayments;
}
const monthlyPayment = principal *
(monthlyRate * Math.pow(1 + monthlyRate, numberOfPayments)) /
(Math.pow(1 + monthlyRate, numberOfPayments) - 1);
return monthlyPayment;
}
// Tax calculation
function calculateTax(income, taxBrackets) {
let tax = 0;
let remainingIncome = income;
for (let bracket of taxBrackets) {
if (remainingIncome <= 0) break;
const taxableAtThisBracket = Math.min(remainingIncome, bracket.max - bracket.min);
tax += taxableAtThisBracket * bracket.rate;
remainingIncome -= taxableAtThisBracket;
}
return tax;
}
// Example usage
const loanPayment = calculateLoanPayment(200000, 4.5, 30);
console.log(`Monthly payment: $${loanPayment.toFixed(2)}`);
const taxBrackets = [
{ min: 0, max: 10000, rate: 0.10 },
{ min: 10000, max: 40000, rate: 0.22 },
{ min: 40000, max: Infinity, rate: 0.32 }
];
const tax = calculateTax(50000, taxBrackets);
console.log(`Tax owed: $${tax.toFixed(2)}`);
```
Game Development Math
```javascript
// 2D Vector class for game development
class Vector2D {
constructor(x, y) {
this.x = x;
this.y = y;
}
add(vector) {
return new Vector2D(this.x + vector.x, this.y + vector.y);
}
subtract(vector) {
return new Vector2D(this.x - vector.x, this.y - vector.y);
}
multiply(scalar) {
return new Vector2D(this.x scalar, this.y scalar);
}
magnitude() {
return Math.sqrt(this.x this.x + this.y this.y);
}
normalize() {
const mag = this.magnitude();
if (mag === 0) return new Vector2D(0, 0);
return new Vector2D(this.x / mag, this.y / mag);
}
dotProduct(vector) {
return this.x vector.x + this.y vector.y;
}
angle() {
return Math.atan2(this.y, this.x);
}
}
// Usage in game physics
const velocity = new Vector2D(5, 3);
const acceleration = new Vector2D(0, -9.8);
const newVelocity = velocity.add(acceleration.multiply(0.016)); // 60 FPS
console.log(`New velocity: (${newVelocity.x}, ${newVelocity.y})`);
```
Troubleshooting Common Issues
NaN and Infinity Issues
```javascript
// Detecting and handling NaN
function safeCalculation(a, b, operation) {
// Validate inputs
if (!Number.isFinite(a) || !Number.isFinite(b)) {
throw new Error("Invalid input: numbers must be finite");
}
let result;
switch (operation) {
case 'add':
result = a + b;
break;
case 'subtract':
result = a - b;
break;
case 'multiply':
result = a * b;
break;
case 'divide':
if (b === 0) {
throw new Error("Division by zero");
}
result = a / b;
break;
default:
throw new Error("Unknown operation");
}
// Check result
if (!Number.isFinite(result)) {
throw new Error("Calculation resulted in invalid number");
}
return result;
}
// Safe usage
try {
console.log(safeCalculation(10, 3, 'divide')); // 3.3333333333333335
console.log(safeCalculation(10, 0, 'divide')); // Throws error
} catch (error) {
console.error(error.message);
}
```
Precision and Rounding Errors
```javascript
// Robust comparison function
function numbersEqual(a, b, tolerance = 1e-10) {
return Math.abs(a - b) < tolerance;
}
// Safe arithmetic operations
const SafeMath = {
add: (a, b, decimals = 10) => {
return Math.round((a + b) * Math.pow(10, decimals)) / Math.pow(10, decimals);
},
subtract: (a, b, decimals = 10) => {
return Math.round((a - b) * Math.pow(10, decimals)) / Math.pow(10, decimals);
},
multiply: (a, b, decimals = 10) => {
return Math.round(a b Math.pow(10, decimals)) / Math.pow(10, decimals);
},
divide: (a, b, decimals = 10) => {
if (b === 0) throw new Error("Division by zero");
return Math.round((a / b) * Math.pow(10, decimals)) / Math.pow(10, decimals);
}
};
console.log(SafeMath.add(0.1, 0.2)); // 0.3
console.log(numbersEqual(0.1 + 0.2, 0.3)); // true
```
Type Conversion Issues
```javascript
// Robust number validation and conversion
function parseNumber(value, defaultValue = 0) {
// Handle null and undefined
if (value == null) {
return defaultValue;
}
// Handle boolean
if (typeof value === 'boolean') {
return value ? 1 : 0;
}
// Handle string
if (typeof value === 'string') {
// Remove whitespace
value = value.trim();
// Handle empty string
if (value === '') {
return defaultValue;
}
// Parse the number
const parsed = Number(value);
return Number.isNaN(parsed) ? defaultValue : parsed;
}
// Handle number
if (typeof value === 'number') {
return Number.isNaN(value) ? defaultValue : value;
}
// Handle other types
const converted = Number(value);
return Number.isNaN(converted) ? defaultValue : converted;
}
// Test the function
console.log(parseNumber("123")); // 123
console.log(parseNumber("123.45")); // 123.45
console.log(parseNumber("abc")); // 0
console.log(parseNumber("abc", -1)); // -1
console.log(parseNumber(null)); // 0
console.log(parseNumber(true)); // 1
```
Best Practices
1. Use Appropriate Number Types
```javascript
// Use integers when possible for better precision
const count = 10; // Good
const percentage = 0.75; // Acceptable for percentages
// Be explicit about number conversion
const userInput = "123";
const number = Number(userInput); // Better than implicit conversion
const safeNumber = Number.isNaN(number) ? 0 : number;
```
2. Handle Edge Cases
```javascript
// Always validate inputs
function divide(a, b) {
if (!Number.isFinite(a) || !Number.isFinite(b)) {
throw new Error("Arguments must be finite numbers");
}
if (b === 0) {
throw new Error("Cannot divide by zero");
}
return a / b;
}
// Check for NaN and Infinity in calculations
function safeSquareRoot(x) {
if (!Number.isFinite(x)) {
throw new Error("Input must be a finite number");
}
if (x < 0) {
throw new Error("Cannot calculate square root of negative number");
}
return Math.sqrt(x);
}
```
3. Use Appropriate Precision
```javascript
// For financial calculations, use appropriate rounding
function formatCurrency(amount) {
return Number(amount.toFixed(2));
}
// For scientific calculations, be aware of precision limits
function scientificCalculation(value) {
if (Math.abs(value) > Number.MAX_SAFE_INTEGER) {
console.warn("Value exceeds safe integer range");
}
return value;
}
```
4. Optimize Performance
```javascript
// Cache expensive calculations
const expensiveCalculations = new Map();
function expensiveFunction(x) {
if (expensiveCalculations.has(x)) {
return expensiveCalculations.get(x);
}
// Simulate expensive calculation
const result = Math.pow(x, 3) + Math.sqrt(x) + Math.sin(x);
expensiveCalculations.set(x, result);
return result;
}
// Use bitwise operations for integer operations when appropriate
function isEven(n) {
return (n & 1) === 0; // Faster than n % 2 === 0
}
function multiplyByPowerOfTwo(n, power) {
return n << power; // Faster than n * Math.pow(2, power)
}
```
5. Error Handling and Validation
```javascript
// Create a utility class for safe math operations
class SafeMath {
static validate(value, name = 'value') {
if (typeof value !== 'number') {
throw new TypeError(`${name} must be a number`);
}
if (!Number.isFinite(value)) {
throw new RangeError(`${name} must be finite`);
}
return value;
}
static add(a, b) {
this.validate(a, 'first operand');
this.validate(b, 'second operand');
const result = a + b;
if (!Number.isFinite(result)) {
throw new RangeError('Addition result is not finite');
}
return result;
}
static divide(a, b) {
this.validate(a, 'dividend');
this.validate(b, 'divisor');
if (b === 0) {
throw new Error('Division by zero is not allowed');
}
return a / b;
}
}
// Usage with proper error handling
try {
const result = SafeMath.divide(10, 2);
console.log(result); // 5
} catch (error) {
console.error('Math operation failed:', error.message);
}
```
Conclusion
Understanding numbers and basic math operations in JavaScript is fundamental to building robust applications. This comprehensive guide has covered everything from basic arithmetic operations to advanced mathematical concepts, common pitfalls, and best practices.
Key Takeaways
1. JavaScript uses 64-bit floating-point numbers for all numeric values, which can lead to precision issues that need to be handled carefully.
2. The Math object provides extensive mathematical functionality including constants, basic operations, trigonometric functions, and random number generation.
3. Type conversion and validation are crucial for handling user input and ensuring reliable calculations.
4. Floating-point precision issues require special attention in financial and scientific applications.
5. Proper error handling and input validation prevent runtime errors and improve application reliability.
6. Performance considerations become important in computationally intensive applications.
Next Steps
To further develop your JavaScript math skills, consider:
- Exploring more advanced mathematical libraries like Math.js or D3.js
- Learning about BigInt for handling very large integers
- Studying numerical analysis techniques for scientific computing
- Implementing mathematical algorithms and data structures
- Building practical applications like calculators, games, or data visualization tools
By mastering these concepts and following the best practices outlined in this guide, you'll be well-equipped to handle numerical operations in your JavaScript applications with confidence and precision.