数 MATH OF LUCK

Dice, priced exactly: the true win chance and return behind every target

Illustration for “Dice, priced exactly: the true win chance and return behind every target”
Each roll is one of 9,999 equally likely results, 0.01 to 99.99. Roll under 50 wins on 4,999 of them, so the true chance is 49.995%, not 50%, and a result of exactly 50.00 loses both Under and Over. The multiplier is 0.99 ÷ the shown chance floored to two decimals. Where that division lands exactly, as at 50 (×1.98), 25 (×3.96) or 10 (×9.90), the true return is 98.91–99.00%; where it does not, the floor adds cost — target 80 pays ×1.23 and returns 98.40%, and 97.06 pays ×1.01 and returns 98.03%, the worst setting on the slider. Across all 9,601 slider positions from 2.00 to 98.00 the average return is 98.72%. Typing the multiplier instead of dragging the slider picks the target that prices cleanly: ×2 returns 98.99%, ×10 98.91%, ×49.5 98.51%.
BETKYO RESEARCHPUBLISHED 2026-09-25UPDATED 2026-09-257 MIN READ

One roll, 9,999 results

Dice is the simplest game on the site: choose a target, choose Under or Over, and the roll either lands on your side of it or does not. The screen quotes a win chance and a multiplier for every target, and the two look like they multiply to exactly 99% — the stake back, less a 1% house edge. The engine is a little more particular than the screen, in two ways that both cost the player, and this article prices them exactly.

ENGINE-VERIFIEDOriginalBaseDiceService.kt: getResult() draws nextIntBelow(9999) + 1 and divides by 100, so the result is one of the 9,999 values 0.01 to 99.99 — 0.00 excluded, 99.99 included. getWinChance() is target ÷ 100 for Under and (100 − target) ÷ 100 for Over. checkAndGetMultiplier() is (1 − house edge) ÷ win chance, floored to two decimals. getEarned() compares strictly: Under wins when the result is below the target, Over when it is above. The random number is the first 13 hex digits of HMAC-SHA256 over “clientSeed-nonce-0”, keyed by the server seed, divided by 2⁵²; the client mirror is payoutMultiplier() in dice/diceApi.ts, and diceGame.tsx limits the slider to targets 2.00–98.00.

The house service carries its own test of this arithmetic, DiceHouseEdgeTest, which checks that no target ever returns more than 99% and that the floor never takes more than one rounding step. Both hold. What the test does not print is how much each target actually returns, and that is the table a player needs.

The shown chance and the true chance

The win chance on screen is computed as if the roll were a continuous number from 0 to 100. It is not: it is one of 9,999 steps. Roll under a target T wins on the results 0.01 up to T − 0.01, which is 100 × T − 1 of them, so the true chance is (100T − 1) ÷ 9,999. At most targets the difference is invisible; at the smallest ones it is not.

Roll under a target: winning results, shown chance and true chance
TARGET (UNDER)WINNING RESULTS OF 9,999SHOWN CHANCETRUE CHANCE
2.001992.00%1.9902%
5.004995.00%4.9905%
10.0099910.00%9.9910%
25.002,49925.00%24.9925%
50.004,99950.00%49.9950%
75.007,49975.00%74.9975%
90.008,99990.00%89.9990%
98.009,79998.00%97.9998%

True chance = (100 × target − 1) ÷ 9,999. Roll over a target T wins on 9,999 − 100T results, so Over T is priced exactly like Under (100 − T): Over 50 also wins on 4,999 results.

The gap is always one result. At a 50% target it costs 0.005 percentage points of chance, a hundredth of a percent of return; at the 2% target, the tightest the slider allows, one result out of 200 is about half a percent of the win chance, and the return drops from 99.00% to 98.51% for that reason alone. The same fact explains a small curiosity: a roll of exactly 50.00 loses Under 50 and Over 50 alike, because neither comparison includes the target. It happens once in 9,999 rolls.

The two-decimal floor

The second cost is the multiplier. The engine divides 0.99 by the win chance and keeps two decimals, always rounding down. When the division comes out exact — 0.99 ÷ 0.50 = 1.98, 0.99 ÷ 0.25 = 3.96 — nothing is lost. When it does not, the player is paid the truncated figure: 0.99 ÷ 0.80 = 1.2375, paid as ×1.23. At a high win chance the multiplier is close to 1, the hundredth that gets dropped is a large share of the profit, and the return falls much further than at the low end.

What a roll-under target pays and returns, 1% house edge
TARGET (UNDER)PAYSSHOWN CHANCE × PAYSTRUE RETURN
2.00×49.5099.00%98.51%
5.00×19.8099.00%98.81%
7.00×14.1498.98%98.85%
10.00×9.9099.00%98.91%
13.00×7.6198.93%98.86%
25.00×3.9699.00%98.97%
40.00×2.4798.80%98.79%
50.00×1.9899.00%98.99%
70.00×1.4198.70%98.70%
80.00×1.2398.40%98.40%
90.00×1.1099.00%99.00%
95.00×1.0498.80%98.80%
97.06×1.0198.03%98.03%
98.00×1.0198.98%98.98%

True return = multiplier × (100 × target − 1) ÷ 9,999. At 90.00 it is 98.999%, the highest on the slider; at 97.06 it is 98.030%, the lowest. Over targets mirror these rows: Over T returns what Under (100 − T) returns.

Read the two right-hand columns together and the two costs separate cleanly. At low targets the multiplier usually divides exactly and the whole shortfall is the missing result; at high targets the missing result is negligible and the shortfall is almost all floor. Target 80 is the clearest case: 0.99 ÷ 0.8 needs ×1.2375, the table pays ×1.23, and the return is 98.40% — a house edge of 1.6%, not 1%. Every target between 97.06 and 98.00 pays the same ×1.01, so the chance you give up by moving to 97.06 buys nothing.

Over the whole slider — every target from 2.00 to 98.00 in steps of 0.01, 9,601 settings — the true return averages 98.72%. Only 585 of those settings, 6.1%, return 98.95% or more; 1,453, 15.1%, return less than 98.50%.

Type the multiplier, not the percentage

The game has a second way to set a bet: type the multiplier you want, and it works out the target. It chooses the target whose floored payout is at least what you typed, so a typed multiplier always lands on a setting where 0.99 ÷ chance divides cleanly. That removes the floor cost entirely; only the one-result gap remains.

Typed multipliers and the targets they resolve to
TYPEDTARGET (UNDER)TRUE CHANCETRUE RETURN
×1.1090.0089.9990%99.00%
×1.2082.5082.4982%99.00%
×1.5066.0065.9966%98.99%
×249.5049.4949%98.99%
×333.0032.9933%98.98%
×519.8019.7920%98.96%
×109.909.8910%98.91%
×204.954.9405%98.81%
×49.502.001.9902%98.51%

targetForMultiplier() in dice/diceApi.ts floors the Under target (or ceils the Over target) so the chance never rises above the one the typed multiplier implies. Returns rounded to two decimals; ×1.10 is 98.999% and ×1.20 98.998%.

The practical rule is short. If you care about the last half-point, set the multiplier rather than the percentage, and prefer round multipliers at the low end of the payout range. A target chosen because it looks round as a percentage — 80, 70, 40 — is often a worse price than the target one tick away. None of this changes the long-run direction: every setting returns less than the stake, and the martingale, priced and risk of ruin explain why no sequence of bets fixes that.

Limbo avoids the floor by construction: the player names the payout directly and the drawn number is compared against that same figure, so there is no second rounding to pay for. Dice quotes a chance and derives the payout from it, and that derivation is where the floor enters.

Checking a roll yourself

  1. Before you play, the fairness panel shows the SHA-256 fingerprint of the server seed. Rotate your seed pair afterwards to reveal the seed and confirm the fingerprint.
  2. Compute HMAC-SHA256 with the server seed as the key and “clientSeed-nonce-0” as the message; a roll uses cursor 0 only.
  3. Read the first 13 hex digits of the digest as an integer and divide by 2⁵² to get u. The result is (floor(u × 9,999) + 1) ÷ 100. Compare it with your target, strictly, and the multiplier on your ticket with 0.99 ÷ chance floored to two decimals.

If the result matches, it was fixed before you chose a target — which, as what a hash commitment proves explains, is what the commitment guarantees and all it guarantees. The price of the target is not in the hash. It is in the two lines of arithmetic above, which is why this article exists.

FAQ

What are the real odds in a dice game that rolls 0 to 100?

Here the roll is one of 9,999 results from 0.01 to 99.99. Roll under T wins on 100 × T − 1 of them, so roll under 50 is 49.995%, roll under 10 is 9.991% and roll under 2 is 1.990%.

What is the house edge on dice?

The stated edge is 1%, but the true return depends on the target: from 99.00% at a target of 90 to 98.03% at 97.06. Averaged over every slider setting from 2.00 to 98.00 it is 98.72%, an effective edge of 1.28%.

Why does my dice multiplier look rounded down?

The engine pays 0.99 ÷ win chance floored to two decimals. At an 80% target that is 1.2375, paid as ×1.23, which returns 98.40% instead of 99%.

What is the best target to pick in dice?

Any target where 0.99 ÷ chance divides exactly, such as 50 (×1.98), 25 (×3.96), 90 (×1.10) or 66 (×1.50). Typing the multiplier instead of the percentage finds one automatically. No target returns more than 99%.

What happens if the dice roll lands exactly on my target?

It loses. Under wins only below the target and Over only above it, so a roll of exactly 50.00 loses both Under 50 and Over 50. It happens once in 9,999 rolls.

Can I verify a dice roll?

Yes. HMAC-SHA256 of “clientSeed-nonce-0” keyed by the revealed server seed; the first 13 hex digits over 2⁵² give u, and (floor(u × 9,999) + 1) ÷ 100 is the result.

SOURCES & REFERENCES
  • Betkyo engine source, house service: OriginalBaseDiceService.kt — getResult() (nextIntBelow(9999) + 1, over 100), getWinChance() (4-decimal floor), checkAndGetMultiplier() ((1 − house edge) ÷ win chance, 2-decimal floor), getEarned() (strict comparison); SeedPairRandom and PfHashUtils.normalize() (first 13 hex digits ÷ 2⁵²); DiceHouseEdgeTest.kt
  • Betkyo engine source, client mirror: payoutMultiplier() and targetForMultiplier() in dice/diceApi.ts; the 2.00–98.00 slider bounds in diceGame.tsx
  • Exact calculation written for this article: (100T − 1) ÷ 9,999 win chances and floored multipliers for all 9,601 slider targets, their true returns and distribution; cross-checked by replaying 400,000 rolls of the HMAC stream through the result derivation (roll under 50: 49.88% simulated vs 49.995% exact; results spanned 0.01 to 99.99)
THE GAMES IN THIS ARTICLE
Betkyo Research — written by the team that builds these games. Every probability quoted in the Journal is derived from our engine source or a cited reference, never copied from another site. Figures are re-checked whenever the engines change.

18+ · PLAY RESPONSIBLY · THE JOURNAL IS EDITORIAL CONTENT, NOT BETTING ADVICE