When working with numerical data in JavaScript or TypeScript, you’ll often come across `Number.MAX_VALUE` and `Infinity`. These two constants serve different purposes and are useful in various scenarios. In this article, we’ll explore their differences, use cases, and demonstrate their practical applications through a common algorithmic problem from LeetCode.
The Basics: What Are Number.MAX_VALUE and Infinity?
- Number.MAX_VALUE: This is the largest finite number representable in JavaScript. Its value is approximately 1.7976931348623157 * 10^{308}. It’s used when you need to initialize variables to a very high value within the range of finite numbers.
- Infinity: This represents a value larger than any finite number and is a special value in JavaScript. It is used when you need to handle values beyond numerical limits.
Key Differences
1. Nature:
— `Number.MAX_VALUE` is a finite number.
— `Infinity` is not a finite number; it signifies an unbounded limit.
2. Arithmetic Operations:
— Adding any finite number to `Number.MAX_VALUE` results in `Infinity`.
— Arithmetic operations with `Infinity` follow specific rules, such as any finite number divided by `Infinity` yielding `0`, and any finite number multiplied by `Infinity` yielding `Infinity`.
Practical Example: Maximizing Stock Profits
Let’s dive into a practical example from LeetCode: finding the maximum profit from stock prices where you can buy and sell on the same day, but can only hold at most one share of the stock at any time.
The Problem
Given an array `prices` where `prices[i]` is the price of a given stock on the `i-th` day, determine the maximum profit you can achieve.
Initial Approach Using Infinity
Here’s an initial attempt to solve the problem using `Infinity`:
function maxProfit(prices: number[]): number {
let total = 0;
let peak = Infinity;
let valley = peak;
for (let i = 0; i < prices.length; i++) {
if (prices[i] < peak) {
total += (peak - valley);
valley = prices[i];
peak = prices[i];
} else {
peak = prices[i];
}
}
total += (peak - valley);
return total;
}
Why Infinity Doesn’t Work Well Here
Using `Infinity` for `peak` and `valley` can lead to issues because:
- The initial comparison `prices[i] < peak` will always be true for the first element, leading to incorrect profit calculations like `Infinity — Infinity`, which results in `NaN`.
Correct Approach Using Number.MAX_VALUE
Here’s how to solve the problem correctly by initializing `peak` and `valley` to `Number.MAX_VALUE`:
function maxProfit(prices: number[]): number {
let total = 0;
let peak = Number.MAX_VALUE;
let valley = peak;
for (let i = 0; i < prices.length; i++) {
if (prices[i] < peak) {
total += (peak - valley);
valley = prices[i];
peak = prices[i];
} else {
peak = prices[i];
}
}
total += (peak - valley);
return total;
}
// Test cases
let prices = [7, 1, 5, 3, 6, 4];
console.log(maxProfit(prices)); // Output: 7
prices = [1, 2, 3, 4, 5];
console.log(maxProfit(prices)); // Output: 4
prices = [7, 6, 4, 3, 1];
console.log(maxProfit(prices)); // Output: 0
prices = [];
console.log(maxProfit(prices)); // Output: 0
```
By using `Number.MAX_VALUE`, we avoid the pitfalls of arithmetic operations involving `Infinity` and ensure that comparisons and updates are handled correctly.
Real-World Scenarios
When to Use Number.MAX_VALUE
1. Finding Minimum Values: Initializing a variable to `Number.MAX_VALUE` ensures that any actual value in your dataset will be smaller. For example, finding the minimum stock price in an array.
2. Resource Allocation: When setting initial values for resource limits in optimization problems, you might use `Number.MAX_VALUE` to represent the maximum allowable resource usage within finite bounds.
When to Use Infinity
1. Mathematical Calculations: When dealing with limits, such as in calculus or certain algorithmic problems where you need to represent an unbounded upper limit.
2. Graph Algorithms: In shortest path algorithms (e.g., Dijkstra’s algorithm), `Infinity` is used to represent initially unreachable nodes.
Conclusion
Understanding the differences between `Number.MAX_VALUE` and `Infinity` can help you make better decisions in your JavaScript/TypeScript code. While both constants serve important roles, choosing the right one depends on the context of your problem. Through practical examples and real-world scenarios, we’ve seen how to apply these constants effectively to achieve the desired outcomes.
By leveraging the appropriate initialization techniques, you can ensure that your algorithms handle edge cases gracefully and avoid unexpected results like `NaN`.