as decreasingly likely outcomes

Hiya!

Let’s face it, we all know what this would do: say "[one of]1[or]2[or]3[as decreasingly likely outcomes]"; 1 is most likely. 3 is least likely. 2 is somewhere in between. But his produces text (that happens to be a number), right?

Is there a way to do it with numbers, too? Values, even. A person has a number called age.
Or even more perfect, if there would be a way to make a sort of (fake) Gauss curve where the most likely values are in the middle and the extreme minimum and the extreme maximum are increasingly unlikely, evenly.

For use in Height, weight, age, etc…

What do I need it for?Secret. :slight_smile:

You can approximate a Gaussian distribution the Gygax way:

let N be (a random number between 0 and 5) plus (a random number between 0 and 5) plus (a random number between 0 and 5);

say "f---in['] genius![no line break]"; Is there a non-cheat way to do it, though?

let N be a random number on a gauss curve between 0 and 12;

It’s not cheating the way he did it.

Here’s a phrase for a decreasingly likely outcome:

To decide what number is a decreasingly likely random number between (x - a number) and (y - a number): if y is less than x: say "FAKE RUNTIME ERROR: illegal range for decreasingly likely numbers"; decide on x; otherwise: let n be y plus 1 minus x; let k be a random number between 1 and (n * (n + 1)) / 2; while k is greater than 0: now k is k minus n; now n is n minus 1; decide on y minus n.

I second the Gygax method. Easy to implement, easy to read, and you can tweak the distribution by changing the dice.

wow this looks really cool but i don’t really understand what’s going on. the while keeps going random narrowing the range further until the random bumps outside of the narrowing range border things? clever - i think. don’t really understand it but that’s the vibe i’m getting off of it.

Well, there’s probably a more elegant way to do it. But it’s easier to explain with an example. Let’s say that we’re doing a decreasingly likely random number between 1 and 4.

x = 1
y = 4
Initially, n = 4
Initially, k is a random number between 1 and 10. Let’s say it’s 8.

Here’s how the loops go:
k = 8 is greater than 0: true
subtract n = 4 from k = 8: now k is 4
subtract 1 from n: now n is 3

k = 4 is greater than 0: true
subtract n = 3 from k = 4: now k is 1
subtract 1 from n: now n is 2

k = 1 is greater than 0: true
subtract n = 2 from k = 1: now k is -1
subtract 1 from n: now n is 1

k = -1 is greater than 0: false
loop ends
decide on y - n = 4 - 1 = 3

If the initial value of k is between 1 and 4, then the first iteration of the loop (n = 4) will knock it down to 0 or below, n will get knocked down to 3 in that loop… and at the end we want to pick the first number in the range, so we decide on y - n = 4 - 3 = 1
If the initial value of k is between 5 and 7, then the first iteration of the loop knocks it down between 1 and 3, and the second iteration (n = 3) knocks it down to 0 or below while knocking n down to 2, and at the end we decide on y - n = 4 - 2 = 2
If the initial value of k is between 8 and 9, then we subtract 4, knocking k down to 4 or 5, we subtract 3, knocking it down to 1 or 2, and we subtract 2, which ends the loop with n = 1 as above and we decide on 3
If the initial value of k is 10, then we have to subtract 4, then 3, then 2, then 1 to get it to 0; going through the loop all four times pushes n all the way to 0, and we decide on y - n = y which is the last outcome of the range.

So you can see that there are four initial values of k that get us 1, three that get us 2, two that get us 3, and one that gets us 4, as desired.

…and of course I had to tinker this for a while, and to make sure it worked I had to write a script that ran it 1000 times and counted the outcomes so I could see it was falling roughly into 4:3:2:1 proportions. If you’re going to be doing this with massive numbers it might be quicker to just do a direct calculation, but that seemed like it might involve solving a quadratic equation and that gave me a headache. Also, meh, I just changed the script to make it run 1,000,000 times and it seemed to work within 20 seconds on my cranky five-years-old laptop, so this probably isn’t very computationally intensive even if it has a lot of subtractions. I guess subtraction is cheap.

[rant]

[/rant]Is there a way to make the average between the minimum and maximum limit most likely, like a gauss curve in reverse?

Well, looking around a bit, the Gaussian distribution is an approximation to the binomial distribution anyway. So if you want you can just do a binomial distribution, with a lot of virtual coin flips. I’ll write that up later, maybe. But at that point there’s little point in not going for zarf’s solution–the difference between 15d2-15 and 3d6-3 probably isn’t worth bothering with.

I kinda would love a graceful way to do huge chunks without actually having to write down one thousand rolls manually. ^^;

You can just do a loop to do the rolls without writing them out manually.

[code]To decide what number is (x - a number) d (y - a number):
let total be 0;
repeat with index running from 1 to x:
now total is total plus a random number between 1 and y;
decide on total.

To decide what number is a gaussian number between (x - a number) and (y - a number):
let n be (y minus x) + 1;
decide on (n d 2) plus x minus n.[/code]

This is more computationally intensive, though, because of all those coin flips; I did something to do a million Gaussian numbers a couple minutes ago, to check the distribution, and it’s still running. If you don’t need to do a million numbers it’s probably fine.

EDIT: Fixed a few errors in the code. Here’s the result, with 100,000 trials of a Gaussian distribution between 1 and 100:

1: 0
2: 0
3: 0
4: 0
5: 0
6: 0
7: 0
8: 0
9: 0
10: 0
11: 0
12: 0
13: 0
14: 0
15: 0
16: 0
17: 0
18: 0
19: 0
20: 0
21: 0
22: 0
23: 0
24: 0
25: 0
26: 0
27: 0
28: 0
29: 0
30: 0
31: 3
32: 3
33: 6
34: 25
35: 46
36: 74
37: 159
38: 245
39: 427
40: 668
41: 1108
42: 1601
43: 2301
44: 3016
45: 3917
46: 4858
47: 5759
48: 6714
49: 7447
50: 7825
51: 7835
52: 7658
53: 7442
54: 6553
55: 5851
56: 4769
57: 4040
58: 2990
59: 2280
60: 1582
61: 1096
62: 670
63: 455
64: 265
65: 132
66: 89
67: 45
68: 24
69: 12
70: 6
71: 2
72: 0
73: 0
74: 2
75: 0
76: 0
77: 0
78: 0
79: 0
80: 0
81: 0
82: 0
83: 0
84: 0
85: 0
86: 0
87: 0
88: 0
89: 0
90: 0
91: 0
92: 0
93: 0
94: 0
95: 0
96: 0
97: 0
98: 0
99: 0
100: 0

Whether this is what you need is up to you.

The easiest way would be to take the zarfian code above and modularly shift the result, like so.

let N be (a random number between 0 and 4) plus (a random number between 0 and 4) plus (a random number between 0 and 4); increase N by 6; now N is the remainder after dividing N by 12;

Hope this helps.

If you are just dealing with a binomial distribution, you can also take values from pascal’s triangle directly. So for 2^n coin flips of n coins, you’ll get k heads (or tails) show up n!/k!(n-k)! times or (n!*100/k!(n-k)!2^n)%.

This has been doing great for now but what I’m really keen of figuring out involves 3 variables.

let’s call them X, Y and pancake. I mean Z.

X is the Lower Limit. The extreme smallest possible value.
Z is the Upper Limit. The extreme largest possible value.

Y’s out? Y? Because : Y’s the tricky one.

Y is the Average.

[code]To decide what number is (x - a number) d (y - a number):
let total be 0;
repeat with index running from 1 to x:
now total is total plus a random number between 1 and y;
decide on total.

To decide what number is a gaussian number between (x - a number) and (y - a number):
let n be (y minus x) + 1;
decide on (n d 2) plus x minus n.[/code]

This code always puts Y in the middle between X and Z.

But what if I want to simulate death ages? Some die young, some die ancient, but most die at… oh I’m too tired to Google the exact number. Let’s say the “average” here would be 80. Sad truth is that some die within days. (don’t mean to bring anyone down but this is the most practical example I can think of) So the lower limit would be 0. Upper limit would be the age of the oldest living human being. Which is, what? 120? Let’s say it is, so that we can get a move on with this.

So:

X 0
Y 80
Z 120

What trickery is this?! Difference between X and Y is exactly double of that between Y and Z.

That would make the curve drop from Y to Z twice as hard as the curve rises from X to Y.

IF we want curve in the opposite direction: SEX! (now that I have your attention, let’s move on to the next example)

let’s say we want a curve about how much sex people have. Or claim they have. Whatever.

Let’s start with the lower limit. This won’t be realistic but the real lower limit disgusts me.

X is 16. Nobody under sixteen fucks. Anywhere. Ever. Doesn’t happen. This is my example, sit down.

Let’s assume that people get lucky until the day they die. Since I made the upper limit of life 120, I readopt that value. Z is 120.

Let’s make it all wobbly. I started getting tired around 25. Fuck it. Y is 25.

So:

X 16
Y 25
Z 120

That makes a freakin’ steep pull up between 16 and 25 of [hums porn soundtrack] and then a very gentle decline that then becomes a bit of a drop and then becomes a gentle decline again until you reach 120.

Something like that - is that possible?

I lack the skill to include that third variable. :frowning:

What if we break it up?

X lower limit
Y forced average
Z upper limit

We do X to Y where the edges flatten out (if possible) where Y is more likely than approaching y , more likely than approaching X, more likely than X, and then we do Y to Z, same fashion but in reverse?

anything to get that damn bell curve skewed the way i need it.

[rant]

I change it into this:To decide what number is a decreasingly likely random number between (x - a number) and (y - a number): if y is less than x: let z be x; now x is y; now y is z; let n be y plus 1 minus x; let k be a random number between 1 and (n * (n + 1)) / 2; while k is greater than 0: now k is k minus n; now n is n minus 1; decide on y minus n;been working fine (so far)[/rant]

Well, there are lots and lots of possible probability functions that could meet the description you have there. For instance, the life expectancy curve is really not a peak in the middle that slopes down but one peak around infant mortality and another one for adults with a trough for teenagers or young adults. If you wanted to model that you would probably want to randomly choose one of two Gaussian distributions–like a one in 10 chance of assigning to a Gaussian between, eh, -50 and 50 (and then you round the negative numbers up to 0) and otherwise a Gaussian between 40 and 120. That probably will put the trough in the wrong place but oh well.

If you want an asymmetrical curve with a peak in the middle, you could just do a Gaussian around the true average and then adjust one half of it. Like this:

To decide what number is the foob plomber: let N be a Gaussian number between 0 and 160; if N is greater than 80: now N is N minus ((N - 80) / 2); decide on N.

This works more nicely than it would for some similar cases because we get to exactly halve the difference on the top end. If we had a more irregular fraction then that adjustment might yield a lumpy distribution, since we only allow integer values.

As always, you will have to weigh how important it is to get the probability distribution exactly the way you want against how annoying this turns out to be to code.

I’ve never been very good at picking the most efficient choices.

Thanks for all the assistance already, too!

i’m working on it right now and well i’ll give it a whirl.

EDIT: ooh looks extremely promising!

[code]To decide what number is (x - a number) d (y - a number):
let total be 0;
repeat with index running from 1 to x:
now total is total plus a random number between 1 and y;
decide on total;

To decide what number is a gaussian number between (x - a number) and (y - a number):
let n be (y minus x) + 1;
decide on (n d 2) plus x minus n;

To decide what number is a false-gaussian between (x - a number) and (y - a number) considering (z - a number):
let N be a Gaussian number between x and y;
if N is greater than z:
now N is N minus ((N - z) / 2);
decide on N;[/code]

And I’m using this to test:[code]testnumber is a number that varies.

to say GAUSSTEST:
now testnumber is a false-gaussian between 55 and 75 considering 60;
say “[testnumber]”;[/code]

is there an easy way to make it run a hundred thousand times and give me the amounts of times any number has been permitted? like earlier in this thread?

EDIT: hold on. it’s only ever showing up things larger than Z. never anything between X and Z… strange.
EDIT: ooh, is it because i gotta see whether or not Z is closer to X or to Y?

This was my test script:

[code]When play begins:
repeat with k running from 1 to 100:
choose row k in the Table of Random Outcomes;
now the index entry is k;
now the frequency entry is 0;
repeat with k running from 1 to 100000:
let n be a gaussian number between 1 and 100;
choose row n in the Table of Random Outcomes;
increment the frequency entry;
repeat through the Table of Random Outcomes:
say “[index entry]: [frequency entry][line break]”.

Table of Random Outcomes
index (a number) frequency (a number)
with 100 blank rows[/code]

You’ll want to change this depending on how many outcomes you actually have (if you’re testing from 55 to 75, you only need 21 rows, and the first loop to set up the table should have k running from 55 to 75–though if you want to see whether your function is messing up you could use the full table so you can record results outside the desired range).

And yeah, you have to see whether Z is closer to X or Y, and adjust things accordingly. It’s going to be something like this, which I’ll let you translate into Informese:

If Z is closer to Y than to X:
choose a gaussian between X and X + 2 * (Z - X) [starting at X, centered on Z]
if that gaussian, call it N, is greater than Z:
now N is N minus (N - Z) * ((Z - X) / (Y - X)) [scale the top half of the gaussian down so the top end of the range lands at Z]

actually I haven’t checked this but I have to post it and run to class.

That’s all very valuable information, for which you have my thanks. But not my Double Cheese (hold the pickle). I don’t share that. Get your own.

But yeah, i got strange results.
lower limit 55
upper limit 75
consider (forced average) 59
however, it does NOT work out correctly…55: 0 56: 2 57: 8 58: 51 59: 280 60: 3655 61: 15096 62: 30940 63: 30842 64: 15131 65: 3674 66: 313 67: 8 68: 0 69: 0 70: 0 71: 0 72: 0 73: 0 74: 0 75: 0the average is off
the last half is incorrectly stacked

i still have to keep looking for my answer.
but i know now for certain inform can handle this sort of thing.