Code Comments
Programming Forum and web based access to our favorite programming groups.I need to generate a string of random characters, say about 20,000
characters long. And I need to do it quickly! I tried the obvious:
for( my $i=0; $i<20000; $i++ ) {
$str .= chr(int(rand(256)));
}
which works, but I have a feeling there must be a faster way than doing
20,000 string concatenations...?
Post Follow-up to this message
"Derek Fountain" wrote in message
> I need to generate a string of random characters, say about 20,000
> characters long. And I need to do it quickly! I tried the obvious:
>
> for( my $i=0; $i<20000; $i++ ) {
> $str .= chr(int(rand(256)));
> }
>
> which works, but I have a feeling there must be a faster way than doing
> 20,000 string concatenations...?
If speed actually matters (which it may not), you'll have to benchmark this
solution, comparing it to yours. They may turn out to be reasonably close
to each other in speed.
my $string = join '', map { chr int rand(256) } 1 .. 20_000;
Here's another solution that pre-generates the 'chr' possibilities, and
thus, MAY be a little more efficient.
my @characters = map { chr $_ } 0 .. 255;
my $string = join '', map { $characters[ rand 256 ] } 1 .. 20_000;
Dave
Post Follow-up to this messageDerek Fountain wrote:
> I need to generate a string of random characters, say about 20,000
> characters long. And I need to do it quickly! I tried the obvious:
>
> for( my $i=0; $i<20000; $i++ ) {
> $str .= chr(int(rand(256)));
> }
>
> which works, but I have a feeling there must be a faster way than doing
> 20,000 string concatenations...?
I didn't benchmark, but I would guess it's faster to call chr() 256
times instead of 20000 times:
# untested code
my @list = map chr, 0 .. 256;
my $str = '';
$str .= $list[rand @list] for 1 .. 20_000;
--Ala
Post Follow-up to this messageDerek Fountain <nospam@example.com> wrote:
> I need to generate a string of random characters, say about
> 20,000 characters long. And I need to do it quickly! I tried the
> obvious:
>
> for( my $i=0; $i<20000; $i++ ) {
> $str .= chr(int(rand(256)));
> }
>
> which works, but I have a feeling there must be a faster way
> than doing 20,000 string concatenations...?
my $str = "\000" x 20_000;
my @chr = map { chr $_ } 0 .. 255;
substr $str, $_, 1, $chr[rand 256] for 1 .. 20_000;
Peter
--
#!/local/bin/perl5 -wp -*- mode: cperl; coding: iso-8859-1; -*-
# matlab comment stripper (strips comments from Matlab m-files)
s/^((?:(?:[])}\w.]'+|[^'%])+|'[^'\n]*(?:''[^'\n]*)*')*).*/$1/x;
Post Follow-up to this messageDerek Fountain (nospam@example.com) wrote on MMMMLXXII September MCMXCIII
in <URL:news:417b232b$0$13761$5a62ac22@per-qv1-newsreader-01.iinet.net.au>:
<> I need to generate a string of random characters, say about 20,000
<> characters long. And I need to do it quickly! I tried the obvious:
<>
<> for( my $i=0; $i<20000; $i++ ) {
<> $str .= chr(int(rand(256)));
<> }
<>
<> which works, but I have a feeling there must be a faster way than doing
<> 20,000 string concatenations...?
Write it in C.
#!/usr/bin/perl
use strict;
use warnings;
no warnings qw /syntax/;
use Inline 'C';
sub r_string;
print r_string (20_000), "\n";
__END__
__C__
char * r_string (int l) {
char * str;
int i;
srand (time ((time_t) NULL));
if ((str = (char *) malloc (l * sizeof (char))) == (char *) NULL) {
perror (malloc);
exit (-1);
}
for (i = 0; i < l; i ++) {
str [i] = rand () % 255;
}
return (str);
}
--
sub f{sprintf'%c%s',$_[0],$_[1]}print f(74,f(117,f(115,f(116,f(32,f(97,
f(110,f(111,f(116,f(104,f(0x65,f(114,f(3
2,f(80,f(101,f(114,f(0x6c,f(32,
f(0x48,f(97,f(99,f(107,f(101,f(114,f(10,
q ff)))))))))))))))))))))))))
Post Follow-up to this messageAla Qumsieh wrote: >I didn't benchmark, but I would guess it's faster to call chr() 256 >times instead of 20000 times: > > # untested code > my @list = map chr, 0 .. 256; > my $str = ''; > $str .= $list[rand @list] for 1 .. 20_000; It's also not very random. I don't think it's the idea to have a repeat period of 256 cycles. -- Bart.
Post Follow-up to this messageDerek Fountain wrote:
>I need to generate a string of random characters, say about 20,000
>characters long. And I need to do it quickly! I tried the obvious:
>
> for( my $i=0; $i<20000; $i++ ) {
> $str .= chr(int(rand(256)));
> }
>
>which works, but I have a feeling there must be a faster way than doing
>20,000 string concatenations...?
I have the following basic 3 ideas:
1) prebuild a string of 20000 bytes, and use substr to replace the
concatenation:
$x = " " x 20000;
substr($x, $_, 1) = chr rand 256 for 0 .. 19999;
2) ditto, but use vec() (bypasses chr()):
$x = " " x 20000;
vec($x, $_, 8) = rand 256 for 0 .. 19999;
3) use pack 'C*' to replace all of the chr() calls + concat/join:
$x = pack 'C*', map int rand 256, 1 .. 20000;
--
Bart.
Post Follow-up to this messageBart Lateur wrote: > Ala Qumsieh wrote: > > > > > It's also not very random. I don't think it's the idea to have a repeat > period of 256 cycles. Neither suggestion does. -- John W. Kennedy "The poor have sometimes objected to being governed badly; the rich have always objected to being governed at all." -- G. K. Chesterton. "The Man Who Was Thursday"
Post Follow-up to this messageOn Sun, 24 Oct 2004 11:38:30 +0800, Derek Fountain
<nospam@example.com> wrote:
>I need to generate a string of random characters, say about 20,000
>characters long. And I need to do it quickly! I tried the obvious:
OK, here are the benchmarks of some of the proposed solutions along
with some other idea.
BTW: I'm to say the least in a rush and I could absoultely NOT verify
that my 'Pack2' solution is correct. But in case it is notm then I
guess that it can be easily corrected.
#!/usr/bin/perl
use strict;
use warnings;
use Benchmark qw/:all/;
cmpthese 500, {
Loop1 => \&Loop1,
Loop2 => \&Loop2,
Map1 => \&Map1,
Map2 => \&Map2,
Subst => \&Subst,
Vec => \&Vec,
Pack1 => \&Pack1,
Pack2 => \&Pack2,
S => \&S
};
sub Loop1 {
my $str = '';
$str .= chr int rand 256 for 1..20_000;
$str;
}
sub Loop2 {
my @chrs = map chr, 0..255;
my $str = '';
$str .= $chrs[rand 256] for 1..20_000;
$str;
}
sub Map1 {
join '', map { chr int rand 256 } 1..20_000;
}
sub Map2 {
my @chrs = map chr, 0..255;
join '', map $chrs[rand 256], 1..20_000;
}
sub Subst {
my $str = "\000" x 20_000;
my @chrs = map chr, 0..255;
substr $str, $_, 1, $chrs[rand 256] for 0..19_999;
$str;
}
sub Vec {
my $str = ' ' x 20000;
vec($str, $_, 8) = rand 256 for 0..19_999;
$str;
}
sub Pack1 {
pack 'C*', map int rand 256, 1..20_000;
}
sub Pack2 {
# Is this OK, BTW?
pack 'L*', map rand ~0, 1..5_000;
}
sub S {
local $_ = ' ' x 20_000;
s/ /chr int rand 256/ge;
$_;
}
__END__
Rate Map2 Map1 S Subst Vec Pack1 Loop1 Loop2 Pack2
Map2 47.8/s -- -1% -5% -32% -36% -39% -44% -48% -84%
Map1 48.3/s 1% -- -4% -32% -35% -38% -43% -47% -84%
S 50.2/s 5% 4% -- -29% -33% -36% -41% -45% -84%
Subst 70.6/s 48% 46% 41% -- -5% -9% -17% -22% -77%
Vec 74.6/s 56% 54% 49% 6% -- -4% -12% -18% -76%
Pack1 78.0/s 63% 61% 55% 10% 5% -- -8% -14% -75%
Loop1 84.7/s 77% 75% 69% 20% 14% 9% -- -7% -72%
Loop2 91.1/s 91% 89% 81% 29% 22% 17% 7% -- -70%
Pack2 307/s 542% 535% 511% 334% 311% 293% 262% 237% --
Any correction/cmt/etc. welcome!
HTH,
Michele
--
{$_=pack'B8'x25,unpack'A8'x32,$a^=sub{po
p^pop}->(map substr
(($a||=join'',map--$|x$_,(unpack'w',unpack'u','G^<R<Y]*YB='
.'KYU;*EVH[.FHF2W+#"\Z*5TI/ER<Z`S(G.DZZ9OX0Z')=~/./g)x2,$_,
256),7,249);s/[^\w,]/ /g;$ \=/^J/?$/:"\r";print,redo}#JAPH,
Post Follow-up to this messageMichele Dondi wrote:
> sub Pack2 {
> # Is this OK, BTW?
> pack 'L*', map rand ~0, 1..5_000;
> }
I don't think you'll ever see "\xFF\xFF\xFF\xFF" there. Better add 1 to
it.
--
Bart.
Post Follow-up to this message
Show a Printable Version
Email This Page to Someone!
Receive updates to this thread
Powered by vBulletin
Copyright 2000-2006 Jelsoft Enterprises Limited.