Perl阶乘子例程不接受命令行参数

时间:2011-01-05 20:11:12

标签: perl

我正在尝试在Perl中创建一个简单的递归阶乘函数,它将从命令行中获取一个数字,然后返回它的阶乘,例如。

>./factorial.pl 3
>6

我的子程序似乎没有采用命令行参数。但是,如果我在没有子包装器的情况下使用完全相同的代码,它会采用命令行参数,但显然不能用作子例程。以下是代码:

#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;

sub fact() {
my $number = shift or return;
return 0 if $number < 0;

my $results = 1;

while ($number--) { $results *= $number--};
return $results;
}

5 个答案:

答案 0 :(得分:7)

子参数中的

shift默认从@_(子参数)转移;在sub之外,它默认从@ARGV(命令行参数)转移。

请在fact(shift)中致电shift(@ARGV)或明确说出fact

摆脱()原型:sub fact {...

答案 1 :(得分:5)

子程序参数打包在@_中。将@ARGV传递给子程序(并删除空原型 - 除非您确切知道它们的作用,否则不要使用原型):

#!/usr/bin/env perl

use warnings; use strict;

print fact(@ARGV), "\n";

sub fact {
    my ($number) = @_;
    # ...
}

答案 2 :(得分:1)

当您将代码包装在子例程中时,您的脚本没有主线程。你需要实际调用你的子程序,例如如下。

函数签名中的()是不必要的,因为你只按照Sinan传递一个参数

#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;

sub fact #() are unnecessary
{
  my $number = shift or return;
  return 0 if $number < 0;

  my $results = 1;

  while ($number--) { $results *= $number--};
  return $results;
}

my $number = shift;
return fact($number);

答案 3 :(得分:1)

函数logfac是一个非常精确的log(factorial)函数。

另外。 通常,当人们要求阶乘函数时,他们真的希望它计算二项式系数。自从我还是学生以来,我就一直在使用这个技巧(我只是这样说,所以我现在的雇主并不认为它是他们的知识产权)。

此代码在数值上非常准确且非常快。请注意“列表”版本的硬编码限制为20 ...您可以稍微调整一下或调整它以获得性能。我没有打扰。

对于“精确”公式,主要思想是在计算二项式系数时会有很多取消。例如

10!/(7!* 3) - &gt; 10 * 9 * 8 /(3 * 2 * 1)
。为了使它在数值上更稳定,计算最后一个残余为
10/3 * 9/2 * 8/1
当计数太大时,我使用的近似值比斯特林系列更好地收敛。我检查了1000左右。

只需通过

'choose(N,m)'

调用N中的选择m
#Approximation from Srinivasa Ramanujan (Ramanujan 1988)
# Much better than stirling.. when tested in R.
# copyright(c) Hugues Sicotte, 2012
# Permission to use without restriction, with no implied suitability for any purposes
# use at your own risk.
use constant PI    => 4 * atan2(1, 1);
sub logfac {
    my $logfac=0;
    my $n=shift(@_); 
    if($n&lt20) {
        my $fac=1;
        for(my $i=1;$i&lt=$n;$i++) {$fac=$fac*$i;}
        $logfac=log($fac);
    } else {
        $logfac=n*log(n)-n+log(n*(1+4*n*(1+2*n)))/6 +log(PI)/2;
    }
    return $logfac;
}
sub choose {
my $total=shift @_; # N
my $choose=shift @_; # m
if($choose==0) { # N!/(0!N!) == 1, even if N==0
    return 1;
} elsif($total==$choose) {#N!/N!*0!
    return 1;
}
if($choose&lt20 && $total&lt20) {
    my $min=$choose <$total-$choose ? $choose : $total-$choose;
    my $res=$total/$min;
    while($min&gt1) {
        $total--;
        $min--;
        $res = $res * $total/$min;
    }
    return $res;
} else {
    return exp(logfac($total)-logfac($choose)-logfac($total-$choose));
}

}

答案 4 :(得分:0)

我现在已修复它以便它可以工作并处理没有参数的情况。

#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;


sub fact {
    my $number = shift or return "Need argument!";
    return 0 if $number < 0;

    my $results = 1;

    while ($number--) { $results *= $number--};
    return $results;
}

my $number= shift;
print fact($number) . "\n";