Skip to content

Instantly share code, notes, and snippets.

@benmathes
Last active December 8, 2022 10:45
Show Gist options
  • Save benmathes/33a10c20796792673676eea4aa8335d3 to your computer and use it in GitHub Desktop.
Save benmathes/33a10c20796792673676eea4aa8335d3 to your computer and use it in GitHub Desktop.
n-sided dice to m-sided dice
# rand(n) is a random number 0-(n-1)
# e.g. [1,0,0] => 4
def bit_array_to_integer(bit_array)
return bit_array.join.to_i(2)
end
def uniform_bit_from_n_sided_dice(n)
roll = rand(n)+1
if n.odd?
# e.g. if n = 5, ignore 5 and roll again.
# correct but inefficient.
while roll == n
roll = rand(n)+1
end
end
return roll[0]
end
def rand_with_dice(target_sides: 8, source_sides: 6)
# roll the source-sided dice once for each bit in
# the target distribution.
bit_array = []
num_bits_in_target = Math.log(target_sides, 2)
for i in 0...num_bits_in_target do
bit_array[i] = uniform_bit_from_n_sided_dice(source_sides)
end
# + 1 to shift from zero-based to one-based
return bit_array_to_integer(bit_array) + 1
end
# double check the outcomes appear uniform
histogram = {}
for i in 1...100000
# ... we should really parallelize this histogram generation...
target_roll = rand_with_dice(target_sides: 7, source_sides: 5)
if histogram[target_roll].nil?
histogram[target_roll] = 1
else
histogram[target_roll] += 1
end
end
puts histogram
@mousetail
Copy link

Unfortunately doesn't work if the target_sides is not a power of 2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment