1 |
Kai Krakow <hurikhan77@×××××.com> schrieb: |
2 |
|
3 |
> Matti Nykyri <Matti.Nykyri@×××.fi> schrieb: |
4 |
> |
5 |
>> If you are looking a mathematically perfect solution there is a simple |
6 |
>> one even if your list is not in the power of 2! Take 6 bits at a time of |
7 |
>> the random data. If the result is 62 or 63 you will discard the data and |
8 |
>> get the next 6 bits. This selectively modifies the random data but keeps |
9 |
>> the probabilities in correct balance. Now the probability for index of |
10 |
>> 0-61 is 1/62 because the probability to get 62-63 out of 64 if 0. |
11 |
> |
12 |
> Why not do just something like this? |
13 |
> |
14 |
> index = 0; |
15 |
> while (true) { |
16 |
> index = (index + get_6bit_random()) % 62; |
17 |
> output << char_array[index]; |
18 |
> } |
19 |
> |
20 |
> Done, no bits wasted. Should have perfect distribution also. We also don't |
21 |
> have to throw away random data just to stay within unaligned boundaries. |
22 |
> The unalignment is being taken over into the next loop so the "error" |
23 |
> corrects itself over time (it becomes distributed over the whole set). |
24 |
|
25 |
It is worth noting that my approach has the tendency of generating random |
26 |
characters in sequence. I think there are several possibilities to fix this, |
27 |
one being swapping two elements in the char array on each access. That fixed |
28 |
this particular problem in my tests. Here's are quick ruby snippet I played |
29 |
with: |
30 |
|
31 |
$ cat random.rb |
32 |
# danger: ugly code ahead |
33 |
dist = [0] * 62 |
34 |
seq = [0, 0] |
35 |
chars = [*('A'..'Z'), *('a'..'z'), *('0'..'9')] |
36 |
orig_chars = chars.dup |
37 |
|
38 |
index = 0 |
39 |
old = nil |
40 |
(62 * 10).times do |
41 |
# generate random wrapped index |
42 |
index = (index + rand(64)) % 62 |
43 |
|
44 |
# swap two indexed positions and output the char |
45 |
chars[0], chars[index] = chars[index], chars[0] |
46 |
$stdout.write chars[0] |
47 |
|
48 |
# count the generated indexes |
49 |
dist[index] = dist[index] + 1 |
50 |
|
51 |
# count if indexes were generated in sequence by looking |
52 |
# them up in the original sorted chars array |
53 |
unless old.nil? |
54 |
seq[0] = seq[0] + 1 if old < orig_chars.index(chars[0]) |
55 |
seq[1] = seq[1] + 1 if old > orig_chars.index(chars[0]) |
56 |
end |
57 |
old = orig_chars.index(chars[0]) |
58 |
end |
59 |
puts |
60 |
|
61 |
# check the average, it should always equal the loop count |
62 |
# multiplicator |
63 |
avg = dist.inject(:+) / 62.0 |
64 |
|
65 |
# calculate if the algorithm preferred sequences |
66 |
seq = [*seq, seq[0] - seq[1]] |
67 |
|
68 |
# output some stats |
69 |
puts avg |
70 |
puts dist.inspect |
71 |
puts dist.map {|v| avg - v }.inspect |
72 |
puts seq.inspect |
73 |
|
74 |
|
75 |
-- |
76 |
Replies to list only preferred. |