# Most effective approach when creating % chance of something

When dealing with % chance in a game what are the most effective ways to achieve this? When I use random.random()[python] or Math.random()[javascript] and use an if/elif/else conditional it seems like the things with a very low chance of happening, happened far more often than they should have.

For example, a python game I worked on used something like this:

qaul_eq = random.random()
if qual_eq <= .5:
quality = common
elif qual_eq <= .75:
quality = uncommon
elif qual_eq <=.9:
quality = rare
elif qual_eq <=.97:
quality = epic
else:
quality = legendary


Javascript DEMO

There is a 2% chance that quality will be legendary yet when printed 20 times every time it is run at least 1 item in almost every test run is legendary. In my python game it isn't uncommon for 2 or 3 of the items to be legendary. I'd chalk it up to good luck if not for the large amount of test runs I have conducted.

• To use an aphorism commonly credited to Einstein, "everything should be as simple as possible, but not simpler" – DMGregory Apr 28 '16 at 21:31
• It's important to think about the user's mental model: can they understand the algorithms? Ultimately, in RPGs, knowing (and sometimes mastering) algorithms can be a critical part of the game. – ashes999 Apr 28 '16 at 21:49
• @Philipp I looked around at other questions that were broad and unrelated to code that had + ratings and assumed it was okay to ask a question such as this. I'll take note that it isn't. I'll also edit my question to be focused on the second one. – Shniper Apr 28 '16 at 21:53
• With the code you show (Legendary has about a 3% chance, not 2%, since a roll of 0.970001 still goes to legendary), we would expect a batch of 20 drops to include at least 1 Legendary almost half the time (45.6%). We'd expect 2-3 Legendaries in a batch about 12% of the time, which matches your description that it "isn't uncommon." So, rather than a mysterious code glitch, this sounds like you might just need to recalibrate your expectations for how low you need to set an outcome's probability to get the desired result over repeated trials. – DMGregory Apr 28 '16 at 23:00
• Not a duplicate, but related: How can I make a “random” generator that is biased by prior events?. The techniques described in that question might be an inspiration for alternative methods than just rolling a random number whenever an event occurs. – Philipp Apr 29 '16 at 8:27

Your algorithm generates a "legendary" rarity whenever a random number in the range 0..1 rolls above 0.97. That's a 3% chance or a chance of one in 33. It's not a 2% chance because random() generates double-precision floating-point numbers. 0.970000000023 is just as likely as 0.9999998735.
If you want an event to happen every nth times on average, do if (random() < 1.0 / n). So to get something to happen once in 50, do random() < 0.02. Or random() > 0.98 when you prefer that form. Checking randomly-generated floating-point numbers for equality is quite pointless because of their high presision (by the way: this also applies to floating-point numbers in most other situations).