tags:

views:

508

answers:

5

I want to generate random hex values and those values should not be repetitive and it should be of 4 bytes (ie: 0x00000000 to 0xffffffff) and the display output should contain leading zeros.

For example: if I get the value 1 it should not represented as 0x1 but 0x00000001.

I want a minimum of 100 random values. Please tell me: how can I do that in Perl?

+3  A: 

To get a random integer:

int(rand(0x10000000))

To format it as 8 hexadecimal digits:

printf "%08x", int(rand(0x10000000))
dmazzoni
sorry about that - our answers were so similar that I accidentally edited the wrong one...
Alnitak
This does not avoid repeating values.
markusk
+4  A: 
perl -e 'printf "%08X\n", int rand 0xFFFFFFFF for 1 .. 100'
Alan Haggai Alavi
This does not avoid repeating values.
markusk
+1  A: 
use LWP::Simple "get";
use List::MoreUtils "uniq";
print for uniq map { s/\t//, "0x$_" } split /^/, LWP::Simple::get('http://www.random.org/integers/?num=220&min=0&max=65535&col=2&base=16&format=plain&rnd=date.2009-12-14');

Adjust the url (see the form on http://www.random.org/integers/?mode=advanced) to not always return the same list. There is a minuscule chance of not returning at least 100 results.

Note that this answer is intentionally "poor" as a comment on the poor question. It's not a single question, it's a bunch all wrapped up together, all of which I'd bet have existing answers already (how do I generate a random number in range x, how do I format a number as a hex string with 0x and 0-padding, how do I add only unique values into a list, etc.). It's like asking "How do I write a webserver in Perl?" Without guessing what part the questioner really wants an answer to, you either have to write a tome for a response, or say something like:

perl -MIO::All -e 'io(":80")->fork->accept->(sub { $_[0] < io(-x $1 ? "./$1 |" : $1) if /^GET \/(.*) / })'
ysth
Bonus points for the most ridiculous answer I've seen in a while.
dmazzoni
Please do not provide such answers. Not everyone will immediately catch that it is meant to be a joke, and will actually use it.
depesz
Ffiendishly bad code is a good way to catch homework cheats and pointless cubicle warmers. Unfortunately, it may harm a real acolyte who in fresh faced ignorance takes it at face value. Some kind of warning is in good taste--perhaps hidden in a JAPHish bit of code.
daotoad
It's worth noting that this is the only answer that actually returns random values. But yes, don't use it. I thought having the given url always return the same values was a good barrier for the thoughtless.
ysth
Why not do something like `@random_numbers = qw( 1 5 2 3 3 6 3 6 2 ); # random numbers determined by fair dice roll.` Obviously, the OP can't just use a 6 sided die, but he could roll 4D8 to get an octal value. ;)
daotoad
daotoad: the url is trivially modifiable to return new results
ysth
I like that someone actually provided a solution that gave real random numbers. I remember having to do something similar and making a radiation detector out a computer microphone. :)
brian d foy
I think there's a module interface to random.org, but I'm too lazy to look for it.
ysth
+10  A: 

To get a random number in the range 0 .. (2<<32)-1:

my $rand = int(rand(0x100000000));

To print it in hex with leading zeroes:

printf "%08x", $rand;

Do please note this from the Perl man page:

Note: If your rand function consistently returns numbers that are too large or too small, then your version of Perl was probably compiled with the wrong number of RANDBITS

If that's a concern, do this instead:

printf "%04x%04x", int(rand(0x10000)), int(rand(0x10000));

Note, also, that this does nothing to prevent repetition, although to be honest the chance of a repeating 32 bit number in a 100 number sequence is pretty small.

If it's absolutely essential that you don't repeat, do something like this:

my (%a);                       # create a hash table for remembering values
foreach (0 .. 99) {
    my $r;
    do {
        $r = int(rand(0x100000000));
    } until (!exists($a{$r})); # loop until the value is not found
    printf "%08x\n", $r;       # print the value
    $a{$r}++;                  # remember that we saw it!
}

For what it's worth, this algorithm shouldn't be used if the range of possible values is less than (or even near to) the number of values required. That's because the random number generator loop will just repeatedly pull out numbers that were already seen.

However in this case where the possible range is so high (2^32) and the number of values wanted so low it'll work perfectly. Indeed with a range this high it's about the only practical algorithm.

Alnitak
Note that if your random number generator is broken and always returns a small set of numbers, this will yield an infinite loop. You might want to think of an alternative to getting a new random number if the random number generator returned the same value twice, such as multiplying the two previous numbers. Note that this may result in lower entropy, but will solve the problem with infinite loops.
Nathan Fellman
@Nathan Fellman: even on windows, rand() will return way more than 100 values; what do you mean by "broken"?
ysth
+4  A: 

Alnitak explained it, but here's a much simpler implementation. I'm not sure how everyone starting reaching for do {} while since that's a really odd choice:

my $max = 0xFFFF_FFFF;

my( %Seen, @numbers );

foreach ( 1 .. 100 )
 {
 my $rand = int rand( $max + 1 );
 redo if $Seen{$rand}++;
 push @numbers, $rand;
 }

print join "\n", map { sprintf "0x%08x", $_ } @numbers;

Also, as Alnitak pointed out, if you are generating a lot of numbers, that redo might cycle many, many times.

These will only be pseudorandom numbers, but you're not really asking for real random number anyway. That would involve possible repetition. :)

brian d foy
`do { } while` isn't odd if you don't know about `redo` :) How long has that been there?
Alnitak
It's been there for well over a decade.
brian d foy
oh well, guess I ought to re-read the manpages (or even the odd Perl book) occasionally ;-)
Alnitak
although to be fair, whilst it may be idiomatic Perl many other languages don't have a similar construct
Alnitak
If we only used the things other languages had, we wouldn't need Perl.
brian d foy
I find do { } while easier to read than redo. Different strokes for different people, I guess. *shrug*
markusk
@markusk: with do {} while you introduce a variable scoping annoyance since you use another inner scope. In you're answer, you use a global variable for that. It's not simple a matter of taste: there are real and significant differences in effect.
brian d foy