jypi
ExploreChatWays to LearnAbout

jypi

  • About Us
  • Our Mission
  • Team
  • Careers

Resources

  • Ways to Learn
  • Blog
  • Help Center
  • Community Guidelines
  • Contributor Guide

Legal

  • Terms of Service
  • Privacy Policy
  • Cookie Policy
  • Content Policy

Connect

  • Twitter
  • Discord
  • Instagram
  • Contact Us
jypi

© 2026 jypi. All rights reserved.

Courses/JavaScript Algorithms and Data Structures/JavaScript Foundations for Algorithmic Programming

JavaScript Foundations for Algorithmic Programming

13 views

Establish a JS toolkit tailored for writing correct, fast, and readable algorithmic code.

Content

1 of 15

Numbers and precision

The No-Chill Breakdown: Numbers, Precision, and JavaScript's Beautiful Chaos
2 views
intermediate
humorous
science
software engineering
gpt-5
2 views

Versions:

The No-Chill Breakdown: Numbers, Precision, and JavaScript's Beautiful Chaos

Chapter Study

JavaScript Numbers and Precision: The Drama You Did Not Know You Signed Up For

"0.1 + 0.2 = 0.30000000000000004" — JavaScript, being honest about floating point since forever.


Why You Should Care (Even If You Don't Yet)

You're writing algorithms — you live and die by comparisons, bounds, and counts. Numbers are your bread, butter, and occasionally your mortal enemy. If you do any of the following:

  • Binary search with floating thresholds
  • Count things bigger than a safe integer
  • Work with money (yikes)
  • Implement geometry, statistics, or physics sims

…then JavaScript's number system matters. A lot. Like "why is my equality check crying in the corner" a lot.

This is your guided tour through the chaos — precision, pitfalls, and the hacks that keep your code from faceplanting.


The One Number Type (Mostly)

In JavaScript, the default number type is: double-precision IEEE‑754 floating point. Translation: 64 bits split into sign, exponent, and fraction. It does a lot, but not everything.

  • Range: about ±1.79e308 (huge)
  • Precision: ~15–17 decimal digits (not infinite)
  • Safe integer range: exactly representable integers from −9,007,199,254,740,991 to +9,007,199,254,740,991
    • These are Number.MIN_SAFE_INTEGER and Number.MAX_SAFE_INTEGER.

Example:

Number.MAX_SAFE_INTEGER === 9007199254740991 // true
9007199254740992 === 9007199254740993        // true 😬 not safe

Rule of thumb: if you care about exact integers beyond 15 digits, do not use Number. See: BigInt.


BigInt: When Your Integers Are Absolutely Swole

BigInt represents whole numbers of arbitrary size. Perfect for huge counts, cryptography, factorials, and "I need exactness" vibes.

  • Create with 123n or BigInt("123").
  • You cannot mix Number and BigInt in arithmetic. Convert intentionally.
const a = 2n ** 100n; // big
// 1 + a // TypeError: Cannot mix BigInt and other types
Number(a) // be careful: may overflow

If you're storing counts, IDs, or factorials: BigInt. If you're doing trig, logs, or divisions with fractions: Number.


The Floating Point Plot Twist

Decimal fractions like 0.1 don't convert cleanly to binary. JS stores approximations.

0.1 + 0.2 === 0.3        // false
0.1 + 0.2                // 0.30000000000000004
(1.005).toFixed(2)       // '1.01'? '1.00'? Depends on binary representation

This is not a bug — it's math meeting binary storage. Your job is to work with it, not scream at your laptop. (You can still scream. Catharsis matters.)


Comparisons: The Zen of "Close Enough"

For floating point comparisons, never use strict equality unless numbers are, like, identical constants computed the same way. Instead, use a tolerance.

const nearlyEqual = (a, b, eps = Number.EPSILON * Math.max(1, Math.abs(a), Math.abs(b))) =>
  Math.abs(a - b) <= eps;

nearlyEqual(0.1 + 0.2, 0.3); // true
  • Number.EPSILON is the smallest difference where 1 + x !== 1 (~2.22e-16). Think of it as the machine's tiny whisper.
  • Scale eps relative to magnitude to compare big or small numbers fairly.

Rounding: Your Four Favorite Frenemies

  • Math.floor(x): round down (toward −∞)
  • Math.ceil(x): round up (toward +∞)
  • Math.round(x): round to nearest integer (ties at .5 go to +∞)
  • Math.trunc(x): drop the fractional part (toward 0)
Math.floor(-1.2) // -2
Math.ceil(-1.2)  // -1
Math.trunc(-1.2) // -1
(2.55).toFixed(1) // '2.6' (string!)

Caveats:

  • toFixed(n) and toPrecision(n) return strings, and they round — but binary imprecision can still surprise you.
  • For money, avoid toFixed for storage; it’s for display. Store scaled integers instead.

Money and Other Decimal Drama: Scale It

If you care about exact cents, meters, grams — store integers. Multiply by a scale factor, compute, then format.

// $19.99 + $0.10 => scale to cents
const sumCents = 1999 + 10; // 2009
const display = (cents) => (cents / 100).toFixed(2);
display(sumCents); // '20.09'

Alternatively, use a decimal library (e.g., Big.js, Decimal.js) when you need precise decimal arithmetic without scaling gymnastics.


The Remainder Operator: It’s Not True Modulo

In JS, % is the remainder, not mathematical modulo. It keeps the sign of the dividend.

5 % 3    // 2
-5 % 3   // -2 (not 1)

If you want a non-negative modulo result:

const mod = (n, m) => ((n % m) + m) % m;
mod(-5, 3) // 1

NaN, Infinity, and the Soap Opera of -0

  • NaN means "not a number" — a special number that is the messiest number of all time.
    • NaN !== NaN is true. Don’t equality-check it. Use Number.isNaN(x).
  • Infinity and -Infinity are results of overflow or division by zero (1/0 → Infinity).
  • -0 exists. It’s real. It matters in some algorithms (direction-sensitive things).
Number.isNaN(NaN) // true
isNaN('foo')      // true (coerces!) avoid; use Number.isNaN
Object.is(0, -0)  // false — Object.is can distinguish +0 and -0

Parsing and Formatting: Subtle Traps

  • Always pass a radix to parseInt.
parseInt('08')        // 8 (modern engines), but always do:
parseInt('08', 10)    // 8
parseFloat('3.14px')  // 3.14, stops at first non-number
Number('3.14')        // 3.14, but Number('3.14px') -> NaN
  • Numeric separators improve readability but not parsing:
const million = 1_000_000;     // ✅ valid
Number('1_000_000')            // NaN — not valid in strings
  • Exponent notation is your friend: 1e6 === 1000000.

Bitwise Ops: Secretly 32-bit

All bitwise operations in JS coerce to signed 32-bit integers. Useful for masks, hashes, but beware overflow.

(1 << 31)       // -2147483648 (sign bit)
(1 >>> 31)      // 1 (unsigned right shift)
(3.7 | 0)       // 3 (fast trunc in 32-bit range)

Never use bitwise tricks on values outside 32-bit or when you need exact floating math.


Summation Without Tears: Reduce Error Like a Pro

When summing lots of floats, small errors accumulate. Stable summation helps.

  • Naive sum can drift.
  • Kahan summation keeps a running compensation for lost low-order bits.
function kahanSum(arr) {
  let sum = 0;
  let c = 0; // compensation
  for (const x of arr) {
    const y = x - c;
    const t = sum + y;
    c = (t - sum) - y;
    sum = t;
  }
  return sum;
}

Use this when you care about accurate sums of many small terms (e.g., statistics).


Which Numeric Tool Do I Use?

Scenario Use Why
Geometry, physics, trig Number + tolerance Floating math with comparisons that allow wiggle room
Money, decimal counts Scaled integers or decimal lib Exact decimals; avoid binary rounding drama
Huge counters, factorials, IDs BigInt Exact integers beyond 2^53 − 1
Bit masks, flags Number with bitwise ops Works in 32-bit lane

Micro-Recipes You’ll Actually Use

  • Safe float compare:
const approxEq = (a, b, eps = 1e-12) => Math.abs(a - b) <= eps * Math.max(1, Math.abs(a), Math.abs(b));
  • Clamp with care:
const clamp = (x, lo, hi) => Math.min(hi, Math.max(lo, x));
  • Normalize angle to [0, 2π):
const TWO_PI = Math.PI * 2;
const normAngle = (θ) => ((θ % TWO_PI) + TWO_PI) % TWO_PI;
  • Big factorial (exact):
const fact = (n) => {
  let r = 1n;
  for (let i = 2n; i <= BigInt(n); i++) r *= i;
  return r;
};

Common Gotchas (A Non-Exhaustive Roast)

  • "But it's only two decimals!" — Binary doesn't care about your feelings or your cents.
  • toFixed returns strings. Accidentally concatenating? Welcome to '42.00' + 1 === '42.001' land.
  • % is remainder. You wanted modulo. Admit it.
  • NaN never equals anything, including itself, because it's chaos in numeric form.
  • Mixing BigInt and Number throws. Convert explicitly.
  • Bitwise ops shrink your world to 32 bits. If you overflow, that's on you and your hubris.

Wrap-Up: The Vibe Check

JavaScript numbers are powerful but… particular. Use them right, and your algorithms are fast and correct. Use them wrong, and your binary search becomes existentialist fiction.

Key takeaways:

  • Numbers are IEEE‑754 doubles. Great range, ~15–17 digits of precision.
  • Use BigInt for exact large integers. Don’t mix with Number carelessly.
  • Float comparisons need tolerances. Number.EPSILON is your friend.
  • For money/decimals: scale to integers or use a decimal library.
  • Understand %, NaN, Infinity, and -0 — or they will understand you.
  • When summing many floats, consider Kahan or other stable algorithms.

Final thought: Precision isn’t about perfection; it’s about controlling error so your code behaves predictably. Master that, and numbers stop being gremlins and start being tools.

0 comments
Flashcards
Mind Map
Speed Challenge

Comments (0)

Please sign in to leave a comment.

No comments yet. Be the first to comment!

Ready to practice?

Sign up now to study with flashcards, practice questions, and more — and track your progress on this topic.

Study with flashcards, timelines, and more
Earn certificates for completed courses
Bookmark content for later reference
Track your progress across all topics