【问题标题】:Perl factorial subroutine not taking command line argumentsPerl 阶乘子例程不采用命令行参数
【发布时间】:2011-01-05 20:11:12
【问题描述】:

我正在尝试在 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;
}

【问题讨论】:

    标签: perl


    【解决方案1】:

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

    所以要么打电话给fact(shift),要么在fact中明确说shift(@ARGV)

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

    【讨论】:

      【解决方案2】:

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

      #!/usr/bin/env perl
      
      use warnings; use strict;
      
      print fact(@ARGV), "\n";
      
      sub fact {
          my ($number) = @_;
          # ...
      }
      

      【讨论】:

      • 他还需要调用子
      【解决方案3】:

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

      函数签名中的 () 是不必要的,因为您只根据 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);
      

      【讨论】:

      • 你也应该消除空原型。
      【解决方案4】:

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

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

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

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

      10!/(7!*3) -> 10*9*8/(3*2*1)
      。为了使其在数值上更稳定,将最后一个剩余部分计算为
      10/3 * 9/2 * 8/1
      当计数太大时,我使用了一个比斯特林级数收敛性更好的近似值。我检查了多达1000个左右。

      只需调用choose m in N by

      'choose(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));
      }
      

      }

      【讨论】:

        【解决方案5】:

        我现在已经把它修好了,这样它就可以工作了,它可以处理没有参数出现的情况。

        #!/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";
        

        【讨论】:

        • P.S.感谢大家的帮助!
        • 这与您的原始问题无关,但是:1)您似乎每次迭代都会减少 $number 两次,因此您得到的不是阶乘,2)尝试调用您的带有参数的脚本,比如“1.5”。
        • fact 的第一行应该是die "fact() needs an argument!" unless @_; my $number = shift;。当一种语言提供异常时(如 Perl 那样),您应该使用该机制来报告异常情况,而不是将其编码为返回值(这只会使调用代码复杂化并检查错误)。此外,如所写,您的代码将不接受“0”作为参数,而是零将导致or 关键字评估其rhs,调用return "Need argument!"。这是因为 Perl 认为 undef, 0, '0', and '' 都是错误值
        猜你喜欢
        • 1970-01-01
        • 2016-01-20
        • 2020-01-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-07-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多