DEV Community

PirateToken
PirateToken

Posted on

Why "1 in 700,000" breaks naive JavaScript (and your intuition)

Fortnite's Pirate Token (players also call it the Fortnite token) makes the Item Shop free for 14 days, and it drops from chests at a rate nobody outside Epic knows. Two estimates circulate: about 1 in 700,000 per chest, the figure most guides quote, and about 1 in 2,000, a dataminer's estimate reported by VICE. They're 350× apart.

I built a small odds calculator for it, and the math turned out to be a nice little lesson in probability and floating point.

The formula

Treat each chest as an independent roll with probability p. The chance of getting nothing from n chests is (1 − p)^n, so:

P(at least one) = 1 − (1 − p)^n
Enter fullscreen mode Exit fullscreen mode

The obvious JavaScript:

const naive = (p, n) => 1 - Math.pow(1 - p, n);
Enter fullscreen mode Exit fullscreen mode

Where naive breaks

1 - p is computed first, and when p is tiny most of its digits fall off the end of a 64-bit float. Then 1 - (something very close to 1) subtracts two nearly equal numbers, which throws away even more precision.

naive(1 / 700000, 1);  // 0.0000014285714285966478
1 / 700000;            // 0.0000014285714285714286  (the true answer for n = 1)

naive(1e-17, 1000);    // 0  (wrong: 1 - 1e-17 rounds to exactly 1)
Enter fullscreen mode Exit fullscreen mode

At 1 in 700,000 the error is small, but at smaller probabilities naive math returns a flat zero.

The stable version

Math.log1p(x) computes ln(1 + x) and Math.expm1(x) computes e^x − 1, both accurate for tiny x. Rewrite (1 − p)^n as e^(n · ln(1 − p)):

const chanceAtLeastOne = (p, n) => -Math.expm1(n * Math.log1p(-p));

chanceAtLeastOne(1 / 700000, 1); // 0.0000014285714285714286
chanceAtLeastOne(1e-17, 1000);   // 9.99999999999995e-15
Enter fullscreen mode Exit fullscreen mode

Same formula, no catastrophic cancellation. This is the line the calculator actually runs.

Plugging in real play

Squads count every teammate's chests, because guides report one find unlocks the token for the whole party:

How you play Chests that count At 1 in 700,000 At 1 in 2,000
Solo: 8 chests a match, 10 matches a day, 30 days 2,400 0.342% 69.9%
Squad of 4, same pace 9,600 1.36% 99.2%
Squad of 4, 25 chests each a match 30,000 4.2% >99.99%

Which estimate is right decides whether this is a lottery or a grind.

How many chests for a coin flip?

Solve 1 − (1 − p)^n = 0.5:

const chestsForChance = (p, target) => Math.log1p(-target) / Math.log1p(-p);
chestsForChance(1 / 700000, 0.5); // ≈ 485,203
chestsForChance(1 / 2000, 0.5);   // ≈ 1,386
Enter fullscreen mode Exit fullscreen mode

That's the median: half of all players would need more.

Why it still feels rigged

  1. No memory. Your 500th chest has the same odds as your first. "I'm due" is the gambler's fallacy.
  2. Survivorship. You see the clips of people who found it, not the millions who opened hundreds of chests and got nothing.

Try your own numbers

The Fortnite token odds calculator runs this exact code with both estimates side by side; pick your party size, chests and days. The math module is open source on GitHub.

Fan project, not affiliated with Epic Games.

Top comments (0)