用perl计算累积分布函数

时间:2013-05-23 08:35:15

标签: perl

我从我的一个朋友那里得到了这个代码,但因为我没有使用perl,我不知道它是如何工作的。你能帮我理解吗?

此文件必须获取一个文件,其中包含一些显示延迟的数据,并在间隔内获得累积分布函数。

#!/usr/bin/perl


#print "Starting converter on file $ARGV[0]\n";

if ($#ARGV < 2 || $#ARGV > 3) {
    print "Usage: ac_hist_gen.pl <input file> <num intervals> <output file> [ <interval size> ]\n";
    exit(-1);
}

open(infile,"$ARGV[0]") || die "Couldn't open $ARGV[0] for reading.\n";
open(outfile,">$ARGV[2]") || die "Couldn't open $ARGV[2] for writing.\n";

for ($i=0; $i< 100 / $ARGV[1]; $i++) {
    $dist[$i] = 0;
    $acum[$i] = 0;
}

$max=0;



if ($#ARGV == 2) {

while (<infile>) {

    if ($_ > $max) {
    $max=$_;
    }    
}

$intsize = $max / $ARGV[1];
} else {
    $intsize= $ARGV[3];
}

close(infile);



#print "size is $numpkts, max is $max, div is $intsize , test is $test\n";


open(infile,"$ARGV[0]") || die "Couldn't open $ARGV[0] for reading.\n";

while (<infile>) {

    $val = int($_ / $intsize);

    if (($_ / $intsize) == $val) {
    $dist[$val-1]++;
    } else {
    $dist[$val]++;
    }

#  print "val is $val\n";


}

for ($i=0; $i< $ARGV[1]; $i++) {
    $limit = ($i+1) * $intsize;
    $acum[$i]+= $dist[$i];
    $acum[$i+1] = $acum[$i];   
    print outfile "$limit $acum[$i]\n";
}


close(outfile);

2 个答案:

答案 0 :(得分:1)

好的,首先快速讨论一下ARGV。这就像在C程序的main()声明中使用的char ** argv

perl中的ARGV被隐式声明为数组。在perl中,我们引用像这样的整个数组

@ARGV

以及像这样的数组大小

$#ARGV

以及像这样的数组中的单个元素

$ARGV[0]

数组从零开始索引,因此$ARGV[0]是数组的第一个元素@ARGV

这就是如何读取程序的命令行args,以及所有对ARGV的引用所关注的内容

下一个项目

open(infile,"$ARGV[0]") || die "Couldn't open $ARGV[0] for reading.\n";
open(outfile,">$ARGV[2]") || die "Couldn't open $ARGV[2] for writing.\n";

这是自我记录,考虑到我刚刚与ARGV讨论的内容。这使得一对输入和输出的文件句柄。双引号"中提到的变量将插值到它们的值。因此,如果$ARGV[0]是“filename1.txt”,则"ARGV[0]"将编译为“filename1.txt”

在perl和数组中,也允许使用简单的单值变量(称为标量)

$x=1与C中的x=1类似。

但是在perl中,可以在不分配内存的情况下分配字符串。这是自动的。字符串“类型”变量可以简单地转换为数字。一个简单的变量可以从一个数字开始,然后转换为一个字符串,然后根据上下文自动返回一个数字。声明变量也不是强制性的!在C中你必须说int x来声明它,这在perl中并没有严格执行

下一段代码

for ($i=0; $i< 100 / $ARGV[1]; $i++) {
    $dist[$i] = 0;
    $acum[$i] = 0;
}

这与C中的完全一样,除了变量前面有一些额外的$符号,并且不需要声明数组的大小@dist和@acum,或者它们的类型

下一点要考虑

while (<infile>) {

    if ($_ > $max) {
    $max=$_;
    }    
}

infile是一个文件句柄,构造<infile>从文件中读取一行。但是你会注意到,在perl程序中 where 读取数据并不清楚。 这里使用的perl技巧是有一个包含最后读取行的默认变量。变量是$_。所以这个循环所做的就是在文件中查找最大值。

我现在稍等一下,直到最后

for ($i=0; $i< $ARGV[1]; $i++) {
    $limit = ($i+1) * $intsize;
    $acum[$i]+= $dist[$i];
    $acum[$i+1] = $acum[$i];   
    print outfile "$limit $acum[$i]\n";
}

这是一个在数组@acum上执行操作的循环,类似于上面的for循环 打印行写入输出句柄。如上所述对变量进行插值。

希望这有助于您理解

答案 1 :(得分:1)

你得到的代码编写得不是很好。这是一个修订版本:

#!/usr/bin/perl

# pragmas
use strict;
use warnings;

# read command line arguments
if ($#ARGV < 2 || $#ARGV > 3) {
    print "Usage: perl $0 <input file> <num intervals> <output file> [<interval size>]\n";
    exit 1;
}
my ($input_file, $num_intervals, $output_file, $interval_size) = @ARGV;

# find interval_size if not specified
unless (defined $interval_size) {
    my $max = 0;
    process($input_file, sub { $max = $_[0] if $_[0] > $max });
    $interval_size = $max / $num_intervals;
}

# fill dist array
my @dist;
process($input_file, sub {
    my $q = $_[0] / $interval_size;
    my $val = int $q;
    $dist[$val == $q ? $val - 1 : $val]++;
});

open my $fh_out, '>', $output_file
    or die "cannot open (write) file '$output_file': $!\n";

# fill acum and generate output
my @acum;
for (0 .. $num_intervals - 1) {
    my $limit = ($_ + 1) * $interval_size;
    $acum[$_] += $dist[$_];
    $acum[$_+1] = $acum[$_];
    print $fh_out "$limit $acum[$_]\n";
}

close $fh_out;

#
# process 'filename', sub {
#     my ($line) = @_;
#     # do something with $line, it is chomped
# };
#
sub process {
    my ($file, $code) = @_;

    open my $fh, '<', $file
        or die "cannot open (read) file '$file': $!\n";

    local $_;
    while (<$fh>) {
        chomp;
        $code->($_);
    }

    close $fh;
}

问候,马蒂亚斯

PS:我没有测试代码,但perl -c没问题。