Post Reply 
(11C) Roll "Four" Dice at Random
10-13-2018, 03:32 AM
Post: #1
(11C) Roll "Four" Dice at Random
Roll 4 dice at random program without using any store registers.

Procedure: f [USER] FIX 0

[D] display face 1st dice --> 2nd dice --> 3th dice --> 4th dice and display Total

Code:

LBL D
GSB 4
GSB 4
+
GSB 4
GSB 4
+
+
RTN
----------------------------
LBL 4
RAN#
6
x
1
+
INT
PSE
RTN

Gamo
Find all posts by this user
Quote this message in a reply
10-13-2018, 10:21 AM (This post was last modified: 10-14-2018 03:43 AM by Gamo.)
Post: #2
RE: (11C) Roll "Four" Dice at Random
This version used [LBL] D to identify both the beginning of the program and
subroutine within the program.

So I adapted this program from the
"Subroutines Section" on Page 125 of the HP-11C Owner's Handbook.

In the handbook state that
*While it is generally best to avoid the use of identical labels to reduce
the possibility of confusion or programming error, the following program
illustrates one way identical labels might be used, if necessary.

Procedure: f [USER] FIX 0

[D] display face 1st Dice --> 2nd --> 3th --> 4th and display Total

Program: Roll 4 Dice at Random
Code:

LBL D
CLx
GSB D
GSB D
GSB D
-----------------------
LBL D
RAN#
6
x
1
+
INT
PSE
+
RTN

Gamo
Find all posts by this user
Quote this message in a reply
10-13-2018, 09:43 PM
Post: #3
RE: (11C) Roll "Four" Dice at Random
(10-13-2018 10:21 AM)Gamo Wrote:  Program: Roll 4 Dice at Random

LBL D
CLx
GSB D
GSB D
GSB D
GSB D
RTN

LBL D
RAN#
6
x
1
+
INT
PSE
X<>Y
+
RTN

You can delete the 3 steps I highlighted in red in your code above, the first two because the second LBL D is right after them so merely falling through will achieve the same effect, and the third one because addition ("'+") is conmutative so no need to swap the two numbers being added.

V.
.
Find all posts by this user
Quote this message in a reply
10-14-2018, 03:48 AM
Post: #4
RE: (11C) Roll "Four" Dice at Random
Thanks Valentin

Now updated.

Gamo
Find all posts by this user
Quote this message in a reply
10-14-2018, 05:37 AM
Post: #5
RE: (11C) Roll "Four" Dice at Random
This version cheat a bit
by using Direct Exchange Storage Register as a Counter.

Code:

LBL D
4
X<>I
LBL 4
RCL I
RAN#
6
x
1
+
INT
PSE
R↑
+
DSE
GTO 4
RTN

Gamo
Find all posts by this user
Quote this message in a reply
10-14-2018, 09:55 PM
Post: #6
RE: (11C) Roll "Four" Dice at Random
(10-14-2018 05:37 AM)Gamo Wrote:  This version cheat a bit
by using Direct Exchange Storage Register as a Counter.

This will only work if register I happens to be zero on program start.
Otherwise its value is added to the result. Try it: 777 STO I, then run the program.

Also the RCL I and R↑ are no required. Just do it as simple as can be:

Code:
LBL D
4
STO I
CLX
LBL 4
RAN#
6
x
1
+
INT
PSE
+
DSE
GTO 4
RTN

Dieter
Find all posts by this user
Quote this message in a reply
10-15-2018, 07:48 AM
Post: #7
RE: (11C) Roll "Four" Dice at Random
(10-14-2018 09:55 PM)Dieter Wrote:  Also the RCL I and R↑ are no required. Just do it as simple as can be:

If only the sum of the dice is needed we can follow your suggestion from an older post:
(05-02-2018 08:03 PM)Dieter Wrote:  I just noticed you can save even two more steps if you remove both the CLX and the RCL+1. ;-)

Code:
LBL D
4
STO I
LBL 4
RAN#
6
x
INT
+
DSE
GTO 4
RTN



However if you want to use RAN# only once as suggested by
(05-02-2018 05:06 AM)Joe Horn Wrote:  THE QUESTION: Is there a direct way to return the sum of a roll of N dice without generating N random numbers and adding them together?

… you can use this translation of my program for the HP-42S:
Code:
001▸LBL D
002 6
003 x<>y
004 yˣ
005 LSTx
006 x<>y
007 RAN#
008 ×
009 INT
010 +
011 0
012▸LBL 0
013 LSTx
014 x=0
015 GTO 1
016 6
017 ÷
018 INT
019 +
020 GTO 0
021▸LBL 1
022 R↓
023 5
024 ×
025 -
026 RTN

Just be aware that you have to enter the number of dice (here 4) prior to running the program:

4
GSB D

Cheers
Thomas
Find all posts by this user
Quote this message in a reply
10-15-2018, 04:29 PM (This post was last modified: 10-15-2018 06:16 PM by Albert Chan.)
Post: #8
RE: (11C) Roll "Four" Dice at Random
If tried to pull multiple dice rolls from a single RAN#, the bias might be too high.

For example, my Casio RAN# can produce between 0.000 to 0.999 (hopefully, unbiased)

For 1 dice roll, dice distribution = 167 + 167 + 166 + 167 + 167 + 166 (3 or 6 is less likely)
Ideally, we wanted even distribution, but 167/166 = 1.006 may be good enough.

For 3 dice rolls, dice distribution = 80*4 + 136*5. 5/4 = 1.25 is unacceptably bad.

To produce unbiased multiple dice roll, remove random below a threshold.
For my casio, remove RAN# below 0.136 should do it.

>>> total = 1000 # Casio RAN# 0.000 to 0.999
>>> dice3 = 6**3 # treble dice rolls
>>> unbiased = [ i % dice3 for i in range(total % dice3, total) ]
>>> [ unbiased.count(i) for i in range(dice3) ]
[4, 4, 4, 4, 4 ... ]
Find all posts by this user
Quote this message in a reply
10-15-2018, 06:33 PM
Post: #9
RE: (11C) Roll "Four" Dice at Random
(10-15-2018 04:29 PM)Albert Chan Wrote:  For 3 dice rolls, dice distribution = 80*4 + 136*5. 5/4 = 1.25 is unacceptably bad.

How did you come up with this distribution?

Because I get the following result:

>>> dice_dist(1000, 1)
{0: 167, 1: 167, 2: 166, 3: 167, 4: 167, 5: 166}

>>> dice_dist(1000, 2)
{0: 335, 1: 333, 2: 332, 3: 335, 4: 333, 5: 332}

>>> dice_dist(1000, 3)
{0: 503, 1: 501, 2: 496, 3: 503, 4: 501, 5: 496}

While this isn't an exact equal distribution I wouldn't say it's biased.

However when we roll more dice the imbalance increases:

>>> dice_dist(1000, 4)
{0: 671, 1: 669, 2: 664, 3: 671, 4: 669, 5: 656}

>>> dice_dist(1000, 5)
{0: 839, 1: 837, 2: 832, 3: 839, 4: 837, 5: 816}

>>> dice_dist(1000, 6)
{0: 1007, 1: 1005, 2: 1000, 3: 1007, 4: 1005, 5: 976}

This is not a big surprise. There are now gaps between consecutive numbers and thus some of the values aren't hit as last digit.

Thus as a rule of thumb we should use it only if \(6^k < n\).
Therefore \(6^3 = 216 < 1000\) is still okay while \(6^4 = 1296 > 1000\) starts getting problematic.

This is the Python function I used to calculate the distribution of the dice:
Code:
def base6(n, k):
    for i in range(k):
        n, d = divmod(n, 6)
        yield d

def dice_dist(n, k):
    dist = dict(zip(range(6), [0] * 6))
    for i in range(n):
        roll = 6 ** k * i / n
        for d in base6(roll, k):
            dist[d] += 1
    return dist

Quote:To produce unbiased multiple dice roll, remove random below a threshold.
For my casio, remove RAN# below 0.136 should do it.

That means 0 (i.e. [1, 1, 1]) can never happen?
How is that not biased?

Kind regards
Thomas
Find all posts by this user
Quote this message in a reply
10-16-2018, 12:17 AM
Post: #10
RE: (11C) Roll "Four" Dice at Random
(10-15-2018 06:33 PM)Thomas Klemm Wrote:  
(10-15-2018 04:29 PM)Albert Chan Wrote:  For 3 dice rolls, dice distribution = 80*4 + 136*5. 5/4 = 1.25 is unacceptably bad.

How did you come up with this distribution?

My mistake. I was assuming a dice with 216 faces.
When the numbers are split back into 3 dice rolls, the distribution is not as bad.

1000 = 216 * 4 + 136 = (216-136) * 4 + 136*5 = 80*4 + 136*5

Doing sum of 3 dice rolls in Mathematica (again, assume RAN# = 0.000 to 0.999):

Code:
dice3[n_] := 3 + Plus @@ IntegerDigits[Mod[n, 216], 6]

biased = Table[dice3[i], {i, 0, 999}]
biased = Table[Count[biased, i], {i, 3, 18}]  (* list should sum to 1000 *)
==> {5, 15, 30, 50, 74, 102, 120, 128, 125, 113, 93, 64, 41, 24, 12, 4}

unbiased = Table[dice3[i], {i, 136, 999}]     (* drop 1000 % 216 numbers *)
unbiased = Table[Count[unbiased, i], {i, 3, 18}]
==> {4, 12, 24, 40, 60, 84, 100, 108, 108, 100, 84, 60, 40, 24, 12, 4}

ratio = biased * (1-0.136) / unbiased

ratio = {1.08, 1.08, 1.08, 1.08, 1.07, 1.05, 1.04, 1.03, 1., 0.98, 0.96, 0.92, 0.89, 0.86, 0.86, 0.86}

Biased distribution is skew to the small side, as expected.
Also, roll sum of 16,17,18 is much less likely ... So, bet small Big Grin

Quote:That means 0 (i.e. [1, 1, 1]) can never happen?

To get random integers from RAN#, I do not use INT(216 RAN#); I use (1000 RAN#) % 216 instead.
If generated random range is divisible by 216, all are equally likely.
That was the reason to drop 1000 % 216 = 136 small cases.

Had I done above biased simulation with INT(216 RAN#), distribution is better (relative to unbiased)
It seems INT(...) produce enough randomness to compensate ...

ratio = {1.08, 1.08, 0.97, 0.95, 1.07, 0.99, 0.97, 1.03, 1.02, 0.97, 1.00, 1.05, 0.93, 0.97, 1.08, 0.86}
Find all posts by this user
Quote this message in a reply
10-16-2018, 08:37 AM
Post: #11
RE: (11C) Roll "Four" Dice at Random
(10-15-2018 07:48 AM)Thomas Klemm Wrote:  However if you want to use RAN# only once (…) you can use this translation of my program for the HP-42S
It turns out that multiplying the random number by 64 and then translating the integer part to base 6 is the same as multiplying it continuously by 6, chopping off the integer part and continue with the remainder.

Thus just forget about that program and use this instead:
Code:
001▸LBL D
002 4
003 STO I
004 RAN#
005▸LBL 0
006 6
007 *
008 +
009 INT
010 LSTx
011 FRAC
012 DSE
013 GTO 0
014 R↓
015 RTN

But then it's slightly longer and a bit biased so rather don't use it at all.

Cheers
Thomas
Find all posts by this user
Quote this message in a reply
10-16-2018, 04:20 PM (This post was last modified: 10-16-2018 06:13 PM by Albert Chan.)
Post: #12
RE: (11C) Roll "Four" Dice at Random
(10-15-2018 06:33 PM)Thomas Klemm Wrote:  >>> dice_dist(1000, 1)
{0: 167, 1: 167, 2: 166, 3: 167, 4: 167, 5: 166}

I noticed that for decimal random numbers, (i.e n = 10^k, k positive), dice of 3 and 6 is biased down.
(assumed generated dice = INT(6 RAN#) + 1, so below 0 meant dice face of 1)

>>> dice_dist(10000, 1)
{0: 1667, 1: 1667, 2: 1666, 3: 1667, 4: 1667, 5: 1666}

>>> dice_dist(100000, 1)
{0: 16667, 1: 16667, 2: 16666, 3: 16667, 4: 16667, 5: 16666}

>>> dice_dist(1000000, 1)
{0: 166667, 1: 166667, 2: 166666, 3: 166667, 4: 166667, 5: 166666}

Is this always true ?

(10-16-2018 08:37 AM)Thomas Klemm Wrote:  It turns out that multiplying the random number by 64 and then translating the integer part to base 6 is the same as
multiplying it continuously by 6, chopping off the integer part and continue with the remainder ...

But then it's slightly longer and a bit biased so rather don't use it at all.

Comparing against unbiased distribution, I was unable to measure a bias difference.
This is my reference unbiased distribution (first number for sum of 4, last for 24)

unbiased = [ 1 4 10 20 35 56 80 104 125 140 146 140 125 104 80 56 35 20 10 4 1 ]

this pattern look familiar ...

Update: above match coefficient of expanded (x^5 + x^4 + x^3 + x^2 + x + 1)^4
Find all posts by this user
Quote this message in a reply
10-16-2018, 09:17 PM (This post was last modified: 10-17-2018 09:38 PM by Albert Chan.)
Post: #13
RE: (11C) Roll "Four" Dice at Random
Prove: For RAN# = 0, 1/10^n, 2/10^n, ... (10^n-1)/10^n, evenly distributed,
and Dice = INT(6 RAN#) + 1, then dice face 3,6 will appear slightly less often.

10^n - 1 sum of digits = 0, thus divisible by 9, thus divisible by 3
10^n - 1 is odd

=> 10^n - 1 (mod 6) = 3, so 10^n = 6 k + 4 = 6(k + 2/3), for some integer k

Below, use Python definition of range(a,b), i.e. a <= integer value < b:

Dice face 1: range(0, k+2/3) = range(0, k+1), total k+1 cases
Dice face 2: range(k+1, 2k+4/3) = range(k+1, 2k+2), total k+1 cases
Dice face 3: range(2k+2, 3k+6/3) = range(2k+2, 3k+2), total k cases
Dice face 4: range(3k+2, 4k+8/3) = range(3k+2, 4k+3), total k+1 cases
Dice face 5: range(4k+3, 5k+10/3) = range(4k+3, 5k+4), total k+1 cases
Dice face 6: range(5k+4, 6k+12/3) = range(5k+4, 6k+4), total k cases

QED

Edit: above assumed calculation had enough precision to avoid rounding issue.
If calculation is also carried to n digits precision, dice face 2,4 will appear less often.
Upper range limit reduced a bit due to possible half-round-up

Dice face 1: range(0, k+2/3-0.5/6) = range(0, k+1), total k+1 cases
Dice face 2: range(k+1, 2k+4/3-5/6) = range(k+1, 2k+1), total k cases
Dice face 3: range(2k+1, 3k+6/3-5/6) = range(2k+1, 3k+2), total k+1 cases
Dice face 4: range(3k+2, 4k+8/3-5/6) = range(3k+2, 4k+2), total k cases
Dice face 5: range(4k+2, 5k+10/3-5/6) = range(4k+2, 5k+3), total k+1 cases
Dice face 6: range(5k+3, 6k+12/3-5/6) = range(5k+3, 6k+4), total k+1 cases

Example, k=166, (2k+1)/(6k+4) = 0.333, 0.333 * 6 = 1.998, rounded-up to 2.00 (dice face 3)
Find all posts by this user
Quote this message in a reply
Post Reply 




User(s) browsing this thread: 1 Guest(s)