Fundamentals 8 min read

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.

ITPUB
ITPUB
ITPUB
Why Does num === num - 1 Sometimes Return True in JavaScript?

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); // Infinity

2. 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)); // false

Use 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)); // works
Note: BigInt can only be used in pure integer operations.

High‑precision calculations with bignumber.js

bignumber.js

is 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")); // 11
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaScriptBIGINTInfinityArbitrary Precisionbignumber.jsNumber EqualitySafe Integer
ITPUB
Written by

ITPUB

Official ITPUB account sharing technical insights, community news, and exciting events.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.