10
\$\begingroup\$

One of the historical dice mechanics in AD&D that can be used is: 3d6 twice for each attribute and pick the best of each pair of rolls.

Normal 3d6 once gives a mean of 10.50. Rolling two sets of 3d6 and picking the best set of 3d6 for the attribute gives a mean of 12:00. The other aspect of that rolling mechanic is that, in a 3d6 once system, one bad roll can wreck an Attribute. However, using two 3d6 rolls, the low numbers that aren't playable is much less likely.

But I don't necessarily like the elevation of the mean from 10.50 to 12.00. So I thought I would try to find a middle ground.

My thought was:

3d6 once -> mean is 10.50. Adding another 3d6 once -> mean of 10.50 and averaging should result in an average of 10.50 (I think).

However: In AnyDice, I wrote:

output ((3d6+3d6)/2) named "avg of 3d6 + 3d6"

The outcome was a mean of 10.25, not 10.50.

I think something is incorrect with my line of code for AnyDice (and/or some understanding of how AnyDice operates), but I don't know what the issue is. I just feel that 10.50 mean + 10.50 mean averaged should have a mean of 10.50, which I'm not seeing.

Does anyone have any thoughts?

\$\endgroup\$
10
  • \$\begingroup\$ This is very interesting. One would assume that if the result of (3d6+3d6)/2 = 10.25 than only (3d6+3d6) would equal to 20.5. But it doesn't it equals 21. However ((3d6+3d6)/2)*2 is 20.5. \$\endgroup\$ Commented May 9 at 7:30
  • 1
    \$\begingroup\$ ... and this is one of the reasons why ones should use basic Maths and Probability instead of Anydice, resorting to use some valid programming language for checking the results (Python is not a valid programming language!) \$\endgroup\$
    – Eddymage
    Commented May 9 at 8:23
  • 12
    \$\begingroup\$ @Eddymage "Python is not a valid programming language!" a hot take for sure, haha \$\endgroup\$
    – justhalf
    Commented May 9 at 15:20
  • \$\begingroup\$ @justhalf Yes, I don't wanna start a flame... but... :-) \$\endgroup\$
    – Eddymage
    Commented May 9 at 16:41
  • 1
    \$\begingroup\$ Note that the described mechanic is from AD&D 2E (DMG p. 9, "Method II") and des not appear in 1E AD&D. On the other hand, 1E AD&D (DMG p. 11) suggests options like roll 12 times and take the best 6 (Method II), or roll 6 times per ability and take the best in each case (Method III). (!) \$\endgroup\$ Commented May 9 at 21:19

6 Answers 6

21
\$\begingroup\$

AnyDice division rounds towards zero

AnyDice only supports integer outcomes; accordingly, when you perform division it is an integer division similar to programming languages such as C. In particular, the result is rounded towards zero. For example, if you roll a 10 and a 13, the result is 11, not 11.5 or 12.

To illustrate the difference, my own Icepool probability package is written in Python, which distinguishes between integer division and "true" division:

from icepool import d
output((3 @ d(6) + 3 @ d(6)) // 2, 'integer division')
output((3 @ d(6) + 3 @ d(6)) / 2, 'floating-point division')

In Python, // is integer division (more properly, "floor division": for negative numbers Python rounds down rather than towards zero as C / AnyDice), whereas / produces a floating-point number out of two integers.

Graph of integer vs. floating point division.

You can try this in your browser here.

Stochastic rounding

One option for preserving the mean is to round up with 50% chance, and down with 50% chance. This is called stochastic rounding.

\ Only handles positive numbers. \
function: stochastic divide N:n by D:n {
 INT: N / D
 FRAC: N - INT * D
 result: INT + (dD <= FRAC)
}

output [stochastic divide 3d6 + 3d6 by 2]

AnyDice link.

Aside: floating-point and other non-integer numbers

Python uses double-precision floating-point numbers for its float type, and AnyDice also appears to use doubles for probabilities. For power-of-two denominators these can be exact, including the half-integers that appear in this particular case; however, no floating-point number can represent non-power-of-two denominators exactly. For example, at time of writing, if you enter output 3d6 in AnyDice and select "Export" and "At Most", you'll see that the last row is

18,100.00000000004599

not adding up exactly to 100% due to the limited precision of floating-point arithmetic.

An alternative is to use an exact rational type such as Python's fractions.Fraction, though rational numbers are not readily available in all environments, and they have their own tradeoffs in performance -- in particular, it's easy for denominators to overflow any common fixed-width integer type, all but requiring the use of variable-width "BigInt"s.

All of this is to say that implementing true division is not as simple as it may sound, and may result in yet more confusing surprises for users!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ I intuited that it was from the way AnyDice does what it does. I appreciate your icepool graphing and the stochastic division that I can use in any dice. Thanks for the insight and the solution to my problem. I suppose one could do the whole thing in a massive Excel (216^2 cells) and then you'd sum and could apply whatever rounding one wanted, but this icepool and anydice are both preferable to that. Appreciate your time, @HighDiceRoller. \$\endgroup\$ Commented May 9 at 17:13
  • \$\begingroup\$ Decimal floating point is a thing, found in C#, Java and Python, so certain non-power of two dividers can be exactly represented in commonly available floating point systems. \$\endgroup\$
    – prosfilaes
    Commented May 11 at 15:07
16
\$\begingroup\$

Your statistics intuition is right for what you are expecting from anydice but wrong for achieving what you want

Due to the Linearity of Expectation the expected value of the sum of 2 random variables is equal to the sum of their expectations. So the mean of 3d6 (10.50) is 3 times the mean of 1d6 (3.5) and the mean of 6d6 or, equivalently, 3d6 + 3d6 (21) is equal to 6 times the mean of 1d6 (3.5). Divide the expectation by 2 and you get 10.5. Bingo!

But anydice isn’t dividing the expection by 2, it’s dividing each individual value by 2, and, since it only works in integer values, it’s rounding all the odd ones down. That’s why, if you look carefully at the numbers, you’ll see it isn’t symmetrical - low numbers are preferred.

If you keep the half scores, you’ll find that you’ll have exactly the same mean as 3d6. And, because the variables are independent, exactly half the variance.

Which means, you’ve created a way of rolling a range of 3-18 including half numbers clustered more tightly towards the middle. You’re going to have to round those off and depending how you do it, you'll get slightly different distributions but they’ll all be damn close to just rolling 3d6, albeit with fewer high or low numbers. If you round down like anydice, the distribution will skew lower with a mean of 10.25. If you round up, higher with a mean of 10.75.

Notwithstanding, you can’t do what you want to do!. If you reduce the chance of rolling lower numbers you have to:

  1. Reduce the chance of rolling higher numbers, or
  2. Accept that the mean must be higher
\$\endgroup\$
2
  • \$\begingroup\$ Point 2 is absolutely important. Any "roll twice, take highest" will, by definition, increase the average value over a single roll. \$\endgroup\$ Commented May 9 at 13:53
  • \$\begingroup\$ I understand that I wanted a mechanic that was more the average of 10.5 and that I wanted less low values (and I was okay with less really high numbers). This step (of 3d6 + 3d6 / 2) was not the final answer, just a step along the way. I might choose something like (3d6 + [top 3 of 4d6])/2 or maybe (3d{2,2,3,4,5,6} + 3d{2,2,3,4,5,6})/2 as examples. I would like to find a resting point around a mean of 11.00 to 11.25 rather than either a mean 10.5 or 12.00, but I want an easy-with-dice approach so it can't be too ugly. Thanks for your explanation! \$\endgroup\$ Commented May 9 at 17:21
3
\$\begingroup\$

If keeping the mean of 10.5 is important, you could take the middle of three rolls and this would reduce the variance while keeping the mean:

output [middle 1 of 3d(3d6)] 
\$\endgroup\$
1
  • \$\begingroup\$ Funnily enough, that's just where I settled before seeing that. I hadn't seen the particular bit of grammar (mine does the same but is messier). Thanks for the extra thought! \$\endgroup\$ Commented May 12 at 2:11
2
\$\begingroup\$

Ignoring all the specifics of your question, and trying to intuit your apparent intent:

You can draw whatever distribution curve you want, free-hand on graph paper, then generate one random number that performs a look-up on that to give the actual result.

This method would work with real numbers but I'll illustrate with integers. Say just using your intuition you decide there should be 1-unit chance of a score being 8 or 9, doubly likely for each individual value of 10, 11, 12, 13, 14, and a trebly likely chance of 15, 16, 17, 18.

OK so that's a total of 24 units. So roll a d24. Value 1 means 8; 2 means 9; 3 or 4 means 10; all the way up to 22, 23, and 24 meaning 18.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ That reminds me of solving areas under curves using numerical methods as a good representation if you weren't needing exact numbers. The challenge is getting a D17.... (I have D16s, D24s, D30s, D18s, D14s, D7s, D5s... I like fun dice... but some are harder. D19... also difficult. Or just figure out how many units there are and what the distribution is and then scale and populate a D100 or D1000. That's a variation on your idea. \$\endgroup\$ Commented May 12 at 2:13
  • \$\begingroup\$ @user3055321 1d17 = (1d2)*10+1d7. 1d19 = (1d2)*10+(1d18)/2. Same principle as percentile dice. One die represents the tens digit and the other die represents the ones digit. \$\endgroup\$
    – 8bittree
    Commented May 13 at 18:27
  • 1
    \$\begingroup\$ For some reason, friends who played D&D back in the mid 1980s like to use D6 and D10 instead of D20. D6 1-3 +0, D6 4-6 +10 to the D10. Same idea. I mean, for a D7, you can roll a D7 and ignore 8. For D19 you can roll a D20 and throw 20 away. \$\endgroup\$ Commented May 14 at 21:15
2
\$\begingroup\$

HighDiceRoller and Dale have both given excellent reasons for why AnyDice is not giving you an expected answer.

This response is a suggestion on how to get your desired outcome of the odds of any particular result having similar odds to a single 3d6 roll.

As a reminder, any "roll twice, take highest" will, by definition, increase the average value over a single roll.

Below is option with which to maintain the 3d6 bell curve while removing the lower results.

Decide what value you consider to be unplayable. If you decide that 8 is the minimal allowable roll, then simply reroll any result under 8. The odds of any particular result will remain equivalent to the normal 3d6 bell curve, with the midrange values being most likely and the higher values remaining rare.

The average value will still increase from a normal 3d6, but not so much as from "roll twice, take highest" and so may satisfy your needs.

\$\endgroup\$
3
  • \$\begingroup\$ I think from a gameplay standpoint, this makes sense - if the goal is to eliminate "unplayable" stats, this solution does just that. However, the OP asked for some statistical properties, such as not increasing the mean. I think this answer would be improved if it addressed those concerns - such as by acknowledging that the mean will increase and then providing a justification for why that's not a bad thing. \$\endgroup\$
    – Tim C
    Commented May 10 at 21:48
  • 1
    \$\begingroup\$ @Michael Richardson: In my initial post, I mentioned "3d6, 3d6, average" which I meant to say roll 2 sets of 3d6 and average, not pick the higher. By using two sets of 3d6 and averaging, I get to keep a keep a lower mean (10.50) and then get a higher concentration of results in the middle and less at either end. \$\endgroup\$ Commented May 14 at 21:22
  • 1
    \$\begingroup\$ I found a better way though. Roll 3d6, 3d6, 3d6. Pick the middle outcome. It is very good at removing most low values and high values - most happens between one sigma boundaries and even the two sigma boundary is smaller and the third is very small compared to a single 3d6 roll. I'm looking for a) working class folk trying to get by, not characters that start heroic and b) it also leaves a lot of ways for characters to work their stats up over the levels. \$\endgroup\$ Commented May 14 at 21:22
-1
\$\begingroup\$

To get the results you want, use use 6d6, manually divide by 2 and then round towards even numbers. This will eliminate the bias towards rounding down.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .