Why Does num === num - 1 Sometimes Return True in JavaScript?
This article explains the special cases where the JavaScript expression num === num - 1 evaluates to true, covering Infinity, numbers beyond the safe integer range, how to detect unsafe values, and practical solutions using Number.isSafeInteger, BigInt, bignumber.js, and a custom big‑integer addition implementation.
Typical Scenarios
1. Infinity
When num is Infinity, any arithmetic operation leaves it unchanged, so num === num - 1 evaluates to true because Infinity - 1 is still Infinity.
const num = Infinity;
console.log(num === num - 1); // true
console.log(num - 1); // Infinity2. Numbers beyond the safe integer range
When num exceeds Number.MAX_SAFE_INTEGER (2^53‑1), the IEEE‑754 double‑precision format cannot represent consecutive integers uniquely, causing num and num - 1 to be stored as the same floating‑point value.
const num = Number.MAX_SAFE_INTEGER + 3;
console.log(num === num - 1); // false
console.log(num, num - 1); // 9007199254740994 9007199254740992
const num1 = Number.MAX_SAFE_INTEGER + 4;
console.log(num1 === num1 - 1); // true
console.log(num1, num1 - 1); // 9007199254740996 9007199254740996
// Values in [MAX_SAFE_INTEGER, MAX_SAFE_INTEGER+6] become chaotic:
console.log(Number.MAX_SAFE_INTEGER);
console.log(Number.MAX_SAFE_INTEGER + 1);
console.log(Number.MAX_SAFE_INTEGER + 2);
console.log(Number.MAX_SAFE_INTEGER + 3);
console.log(Number.MAX_SAFE_INTEGER + 4);
console.log(Number.MAX_SAFE_INTEGER + 5);
console.log(Number.MAX_SAFE_INTEGER + 6);How to Avoid Incorrect Equality
Validate the safe‑integer range
Use Number.isSafeInteger() to check whether a value lies within the safe range.
console.log(Number.isSafeInteger(666)); // true
console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER)); // true
console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 6)); // false
console.log(Number.isSafeInteger(9007199254740999)); // falseUse BigInt for large integers
Since ES2020 JavaScript supports the BigInt type, you can perform arbitrary‑precision integer arithmetic without losing precision.
const a = 123456789012345678901234567890n;
const b = BigInt("987654321098765432109876543210");
console.log(a + b); // 1111111110111111111011111111100n
console.log(a * b); // 12193263113702179522374638011189951891063930922378900n
// Mixing BigInt with Number throws an error; convert Number to BigInt first.
const c = 10;
// console.log(a + c); // TypeError
console.log(a + BigInt(c)); // worksNote: BigInt can only be used in pure integer operations.
High‑precision calculations with bignumber.js
bignumber.jsis a mature library for arbitrary‑precision decimal arithmetic.
import BigNumber from 'bignumber.js';
const x = new BigNumber("123456789.123456789");
const y = new BigNumber("987654321.987654321");
console.log(x.plus(y).toString()); // "1111111111.11111111"
console.log(x.multipliedBy(y).toFixed(2)); // "121932631137021795.22"Hand‑written big‑integer addition
The following function implements addition of two arbitrarily long decimal strings, handling alignment, carry, and fractional parts.
function addStrings(num1, num2) {
num1 = (num1 || "0") + "";
num2 = (num2 || "0") + "";
let dec1Len = num1.split(".")[1]?.length || 0,
dec2Len = num2.split(".")[1]?.length || 0;
if (dec1Len || dec2Len) {
if (!num1.includes(".")) num1 += ".";
if (!num2.includes(".")) num2 += ".";
const maxDecLen = Math.max(dec1Len, dec2Len);
num1 += "0".repeat(maxDecLen - dec1Len);
num2 += "0".repeat(maxDecLen - dec2Len);
}
let i = num1.length - 1,
j = num2.length - 1,
add = 0,
ans = "";
while (i >= 0 || j >= 0 || add !== 0) {
if (num1[i] === ".") { ans = "." + ans; i--; j--; continue; }
const x = i >= 0 ? num1.charAt(i) - "0" : 0;
const y = j >= 0 ? num2.charAt(j) - "0" : 0;
const result = x + y + add;
ans = (result % 10) + ans;
add = Math.floor(result / 10);
i--; j--;
}
return ans;
}
console.log(addStrings("11111111111111111111111111111.11111111111111111111", "11111111111111111111111111111.99999999999999999999")); // 22222222222222222222222222223.11111111111111111110
console.log(addStrings("11111111111111111111111111111.11111111111111111111", "11111111111111111111111111111")); // 22222222222222222222222222222.11111111111111111111
console.log(addStrings("9", "2")); // 11Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
ITPUB
Official ITPUB account sharing technical insights, community news, and exciting events.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
