Generate all numbers 0 .. N randomly using as little memory as possible as fast as possible
The general problem here is that the more numbers you choose, the larger the number of possible misses becomes.
My ideas for a solution were numerous variations on:
I did learn a bit about bitstrings and bit operators, but not enough to be succesful at my task. The following code is my latest variation which is the most memory efficient, but not the fastest.
#!/usr/bin/perl use strict; use warnings; my $next = Gen_Iter( $ARGV[0] || 10 ); while ( defined( my $rand = $next->() ) ) { print "$rand\n"; } sub Gen_Iter { my $wrk = shift; # Create initial bitstring my $bytes = int ( $wrk / 8 ); my $pad = 8 - $wrk % 8; $pad += $pad == 8 ? -8 : 0; $bytes++ if $pad; my $str = "\0" x $bytes; vec($str, $_, 1) = 1 for $wrk .. $bytes * 8 - 1; # Establish initial boundaries my $beg = 0; my $end = $wrk; # return magic sub return sub { return () if ! $wrk--; my $num = Get_Random->($str, $beg, $end); $beg = Post_Zero( $str, $num ) if $num == $beg; $end = Prev_Zero( $str, $num ) if $num == $end; vec($str, $num, 1) = 1; return $num; }; } # Count leading 1s in a bitstring sub Leading { my $str = shift; $str =~ /^(\xFF*)/; my $skip = length $1; return -1 if $skip == length $str; my $byte = unpack("x${skip}A1", $str); my $extra = -1; while ( $extra++ < 6 ) { last if ! vec($byte, $extra, 1); } return $skip * 8 + $extra; } # Count trailing 1s in a bitstring sub Trailing { my $str = shift; my $len = length $str; $str =~ /(\xFF*)$/; my $match = length $1; return -1 if $len == $match; my $skip = $len - $match - 1; my $byte = unpack("x${skip}A1", $str); my $extra = 8; while ( $extra-- ) { last if ! vec($byte, $extra, 1); } return ($len - $skip - 1) * 8 + (7 - $extra); } # Find a 0 before current location (-1 if none) sub Prev_Zero { my ($str, $orig) = @_; my $cur = $orig; my $pos = $cur % 8; if ( $pos ) { while ( $pos-- ) { return $cur if ! vec($str, --$cur, 1); } } my $length = int($orig / 8); my $prev = substr($str, 0, $length); return -1 if ! $prev; my $gap = Trailing( $prev ); return -1 if $gap == -1; return $orig - (1 + $gap + $orig % 8); } # Find a 0 after current location (-1 if none) sub Post_Zero { my ($str, $orig) = @_; my $cur = $orig; my $pos = $cur % 8; if ( $pos < 7 ) { for ( $pos + 1 .. 7 ) { return $cur if ! vec($str, ++$cur, 1); } } my $byte = int($orig / 8); return -1 if $byte == length( $str ) - 1; my $tail = substr($str, $byte + 1); my $gap = Leading( $tail ); return -1 if $gap == -1; return $orig + $gap + ( 8 - $orig % 8 ); }; # Generate a random number within a specified range sub Gen_Random { return $_[0] + int( rand( $_[1] - $_[0] ) ); } # Select an available number randomly accounting for ghost sub Get_Random { my ($str, $beg, $end) = @_; my $guess = Gen_Random($beg, $end); my $dir = int rand 2; while ( $guess != -1 && vec($str, $guess, 1) ) { $guess = $dir ? Post_Zero( $str, $guess ) : Prev_Zero( $st +r, $guess ) ; } $guess = $dir ? $beg : $end if $guess == -1; return $guess; }
The idea was to keep shrinking the search space and to not keep guessing at random on a unsuccessful match.
It also has a bug or two that I didn't bother tracking down as I have given up. I was hoping I might learn a few things from how others solved the same problem using the same restrictions. It will also be interesting to see if people have the same general idea (bitstring), but are capable of making it work.Cheers - L~R
Update:
This post is not a request for a code critique, but a solicitation for your ideas on how to solve the same problem with the same constraints.
While I do appreciate critiques, I have already admitted this is a failure, but not for some of the faulty assumptions others have made. Please take the time to understand the code if you are going to provide a critique.
I fully acknowledge that this approach will not produce a statistically uniform distribution. While not a primary goal, it would have been nice and is one of the reasons I said it was a failure and asked how else someone might try to solve this problem.
In reply to Generating 0 .. N Randomly and Efficiently by Limbic~Region
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |