use strict; use warnings; use List::Util qw/product/; use Time::HiRes qw/time/; use 5.010; programmatic( nParams => 3, nFixed => 2, step => 0.2 , start => 0, stop => 1, default => [qw/0.25 0.50 0.75 1 1/]); programmatic( nParams => 2, nFixed => 0, step => [0.25, 0.5], start => [0, 1], stop => [1, 0]); # not including the OP's version by default, due to time constraints; I ran it in the background over a couple hours (my solution or PC not as fast as BrowserUK's; a possible price of being more generic) #open my $fh, ">", "1208610.out" or die "1208610.out: $!"; #programmatic( fh => $fh, nParams => 11, nFixed => 2, step => 0.2, start => 0, stop => 1, default => [split ',', ("1,0.6,0.4,0.1,0.6,0,0.4,0.4,1,0.5,1,1,1")] ); sub programmatic { my %a = @_; my $t0 = time; # if you wrapped this all my $num_params = $a{nParams} // 3; # this is the number of params that varies; OP would use 1 my $num_fixed_params = $a{nFixed} // 2; # this is the number of params that stay 1 (the p[11] and p[12] from OP) $a{start} = 0 unless exists $a{start}; my @start = ref($a{start}) ? @{$a{start}} : ($a{start}) x $num_params; $a{stop} = 1 unless exists $a{stop}; my @stop = ref($a{stop}) ? @{$a{stop}} : ($a{stop}) x $num_params; $a{step} = 0.2 unless exists $a{step}; my @step = ref($a{step}) ? @{$a{step}} : ($a{step}) x $num_params; foreach (0 .. $#step) { # fix the sign $step[$_] = abs $step[$_]; $step[$_] = -$step[$_] if $stop[$_] < $start[$_]; } my @n = map { abs(($stop[$_] - $start[$_]) / $step[$_]) + 1 } 0 .. $num_params-1; my @default_p = ref($a{default}) ? @{$a{default}} : (1) x ($num_params + $num_fixed_params); my $fh = $a{fh} // \*STDOUT; my $last_iter = product(@n) - 1; for my $iter ( 0 .. $last_iter ) { my $remains = $iter; my @p = @default_p; for my $pidx ( reverse 0 .. $num_params-1 ) { my $mod = $remains % $n[$pidx]; # for the OP, this would be a number from 0 .. 5 each time $p[$pidx] = $mod * $step[$pidx] + $start[$pidx]; $remains -= $mod; $remains /= $n[$pidx]; } # this is where you would do your processing; in my example, I just print the parameter combination for this iteration printf {$fh} "#%12d# \@p = (%s)\n", $iter, join(', ', map { sprintf '%.1f', $_ } @p ); } print {$fh} "\n" unless $fh eq \*STDOUT; printf STDERR "time: %.3fs for %d\n\n", time()-$t0, $last_iter+1; } __END__ #### __RESULTS__ perl 1208610.pl # 0# @p = (0.0, 0.0, 0.0, 1.0, 1.0) # 1# @p = (0.0, 0.0, 0.2, 1.0, 1.0) # 2# @p = (0.0, 0.0, 0.4, 1.0, 1.0) # 3# @p = (0.0, 0.0, 0.6, 1.0, 1.0) # 4# @p = (0.0, 0.0, 0.8, 1.0, 1.0) # 5# @p = (0.0, 0.0, 1.0, 1.0, 1.0) # 6# @p = (0.0, 0.2, 0.0, 1.0, 1.0) ... # 208# @p = (1.0, 0.8, 0.8, 1.0, 1.0) # 209# @p = (1.0, 0.8, 1.0, 1.0, 1.0) # 210# @p = (1.0, 1.0, 0.0, 1.0, 1.0) # 211# @p = (1.0, 1.0, 0.2, 1.0, 1.0) # 212# @p = (1.0, 1.0, 0.4, 1.0, 1.0) # 213# @p = (1.0, 1.0, 0.6, 1.0, 1.0) # 214# @p = (1.0, 1.0, 0.8, 1.0, 1.0) # 215# @p = (1.0, 1.0, 1.0, 1.0, 1.0) time: 0.141s for 216 # 0# @p = (0.0, 1.0) # 1# @p = (0.0, 0.5) # 2# @p = (0.0, 0.0) # 3# @p = (0.2, 1.0) # 4# @p = (0.2, 0.5) # 5# @p = (0.2, 0.0) # 6# @p = (0.5, 1.0) # 7# @p = (0.5, 0.5) # 8# @p = (0.5, 0.0) # 9# @p = (0.8, 1.0) # 10# @p = (0.8, 0.5) # 11# @p = (0.8, 0.0) # 12# @p = (1.0, 1.0) # 13# @p = (1.0, 0.5) # 14# @p = (1.0, 0.0) time: 0.013s for 15