1arryb
User
May 27, 2009, 8:10 AM
Post #2 of 4
(526 views)

Re: [katomich] C to Perl conversion
[In reply to]

Can't Post


Hi katomich, My first reaction to your post was, "what, like we need another pseudorandom number generator in Perl?" A quick search on CPAN yields 10 or 20 random number generation packages. Surely one of them will work for you. But maybe you are just curious or there's something special about this function that I'm too ignorant about numerical methods to appreciate, so we carry with the analysis. First of all, your question about pointers is just a distraction. It has nothing to do with why your program doesn't work. If you are curious about how variables and references work in perl, read the perlvar and perlref perldocs. But before you jump down that rabbit hole, fix the bugs in your script: 1. You are always calling ran2() with the same value (the loop in your main program is on $m but you call ran2($idum). 2. Even after I fixed this problem, ran2() always returns the same value, no matter what the argument is. I stepped through the function using the perl debugger (perl d). Here are a couple of problems that jumped out at me:
main::ran2(tmp.pl:55): $j=$iy/NDIV; # $iy is zero here. main::ran2(tmp.pl:56): $iy=$iv[$j]$idum2; # @iv is an empty array here. Also, $j has no value. Note: I reformatted your script so I could figure out what was going on. Line numbers above refer to my version, not yours.
#!/usr/bin/perl use constant IM1 => 2147483563; use constant IM2 => 2147483399; use constant AM => (1.0/IM1); use constant IMM1 => (IM11); use constant IA1 => 40014; use constant IA2 => 40692; use constant IQ1 => 53668; use constant IQ2 => 52774; use constant IR1 => 12211; use constant IR2 => 3791; use constant NTAB => 32; use constant NDIV => (1+IMM1/NTAB); use constant EPS => 1.2e7; use constant RNMX => (1.0&EPS); sub ran2 { my $idum = $_[0]; $idum2 = 123456789; $iy = 0; my @iv = (); if ($idum <= 0) { if (($idum) < 1) { $idum=1; # How will ($idum) ever be < 1 here? } else { $idum = ($idum); } $idum2=($idum); for ($j=NTAB+7; $j>=0; $j) { $k=($idum)/IQ1; $idum=IA1*($idum$k*IQ1)$k*IR1; if ($idum < 0) { $idum += IM1; } if ($j < NTAB) { $iv[$j] = $idum; } } $iy=$iv[0]; } $k=$idum/IQ1; $idum=IA1*($idum$k*IQ1)$k*IR1; if ($idum < 0) { $idum += IM1; } $k=$idum2/IQ2; $idum2=IA2*($idum2$k*IQ2)$k*IR2; if ($idum2 < 0) { $idum2 += IM2; } $j=$iy/NDIV; $iy=$iv[$j]$idum2; $iv[$j] = $idum; if ($iy < 1) { $iy += IMM1; } if (($temp=AM*$iy) > RNMX) { return RNMX; } else {return $temp;} } #my $idum=1; for($m=1; $m<=10; $m++) { $x = ran2($m); print "idum=" . $m . ", " . "output=" . $x . "\n"; } Cheers, Larry
