【问题标题】:Ruby factorial functionRuby 阶乘函数
【发布时间】:2011-01-26 22:19:33
【问题描述】:

我快疯了:Ruby 的阶乘函数在哪里?不,我不需要教程实现,我只想要库中的函数。它不在数学中!

我开始怀疑,它是标准库函数吗?

【问题讨论】:

  • 我喜欢6.downto(1).inject(:*)
  • @mckeed: 或者 (1..6).inject(:*) 更简洁一点。
  • 为什么会有一个?
  • 我想知道 Ruby 的数学和科学库的现状如何。
  • 只是对所提供的使用注入示例的注释。 (1..num).inject(:*)num == 0 的情况下失败。 (1..(num.zero? ? 1 : num)).inject(:*) 给出 0 情况的正确答案,返回 nil 负参数。

标签: ruby math factorial


【解决方案1】:

标准库中没有阶乘函数。

【讨论】:

【解决方案2】:

它不在标准库中,但您可以扩展 Integer 类。

class Integer
  def factorial_recursive
    self <= 1 ? 1 : self * (self - 1).factorial
  end
  def factorial_iterative
    f = 1; for i in 1..self; f *= i; end; f
  end
  alias :factorial :factorial_iterative
end

注意出于明显的性能原因,迭代阶乘是更好的选择。

【讨论】:

  • 他明确表示,他不想要实现。
  • 他可能不会;但是搜索“Ruby factorial”的人可能会。
  • rosettacode.org/wiki/Factorial#Ruby 是错误的。 0 没有案例
  • 递归版本真的慢吗?这可能取决于 Ruby 是否进行尾递归优化。
  • 我不相信递归版本实际上是递归的。它调用factorial,别名为factorial_iterative。它永远不会递归到自身。所以它是间接迭代的。
【解决方案3】:

您还可以使用Math.gamma 函数,该函数归结为整数参数的阶乘。

【讨论】:

  • 来自文档:“请注意,对于整数 n > 0,gamma(n) 与 fact(n-1) 相同。但是 gamma(n) 返回浮点数并且可以是近似值”。如果考虑到这一点,它会起作用,但 reduce 解决方案似乎更直接。
  • 谢谢!我的直觉说尽可能使用标准库而不是自定义编写的 reduce。分析可能会提出其他建议。
  • 注意:对于0..22,它是 O(1),并且是精确的:MRI Ruby 实际上会查找这些值(参见 source 中的 static const double fact_table[])。除此之外,它是一个近似值。例如,23! 需要一个 56 位尾数,而使用具有 53 位尾数的 IEEE 754 double 无法精确表示。
【解决方案4】:

我自己写的:

def fact(n)
  if n<= 1
    1
  else
    n * fact( n - 1 )
  end
end

此外,您可以定义下降阶乘:

def fall_fact(n,k)
  if k <= 0
    1
  else
    n*fall_fact(n - 1, k - 1)
  end
end

【讨论】:

    【解决方案5】:

    无耻抄袭http://rosettacode.org/wiki/Factorial#Ruby,我个人最喜欢的是

    class Integer
      def fact
        (1..self).reduce(:*) || 1
      end
    end
    
    >> 400.fact
    => 64034522846623895262347970319503005850702583026002959458684445942802397169186831436278478647463264676294350575035856810848298162883517435228961988646802997937341654150838162426461942352307046244325015114448670890662773914918117331955996440709549671345290477020322434911210797593280795101545372667251627877890009349763765710326350331533965349868386831339352024373788157786791506311858702618270169819740062983025308591298346162272304558339520759611505302236086810433297255194852674432232438669948422404232599805551610635942376961399231917134063858996537970147827206606320217379472010321356624613809077942304597360699567595836096158715129913822286578579549361617654480453222007825818400848436415591229454275384803558374518022675900061399560145595206127211192918105032491008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
    

    这个实现也恰好是 Rosetta Code 中列出的变体中最快的。

    更新 #1

    添加了|| 1 来处理零情况。

    更新 #2

    感谢Mark Thomas,这是一个更高效、更优雅、更晦涩的版本:

    class Integer
      def fact
        (2..self).reduce(1,:*)
      end
    end
    

    【讨论】:

    • 这到底是什么意思?!是的,它很快,但它非常不友好
    • 0 也是不正确的! - 应该是这样的: if self
    • @allen - 如果你听不懂语言,不要责怪它。它只是意味着,取范围 1 到 self,然后从中删除第一个元素 (1)(即,这就是函数式编程中 reduce 的含义)。然后删除剩下的第一个元素 (2) 并将它们相乘 (:*)。现在从剩下的 (3) 中删除第一个元素并将其与运行总数相乘。继续前进,直到一无所有(即您已经处理了整个范围)。如果reduce失败(因为数组在0的情况下为空!)那么无论如何都只返回1。
    • 也可以通过在reduce:(1..self).reduce(1,:*)中指定初始值来处理零的情况。
    • 其实你可以使用(2..self).reduce(1,:*),如果你喜欢微效率:)
    【解决方案6】:

    这样更好

    (1..n).inject(:*) || 1
    

    【讨论】:

    • 或者直接指定初始值:(1..n).reduce(1, :*).
    【解决方案7】:
    class Integer
      def factorial
        return self < 0 ? false : self==0 ? 1 : self.downto(1).inject(:*)
        #Not sure what other libraries say, but my understanding is that factorial of 
        #anything less than 0 does not exist.
      end
    end
    

    【讨论】:

      【解决方案8】:

      使用Math.gamma.floor 是一种生成近似值然后将其向下舍入为正确整数结果的简单方法。应该适用于所有整数,如有必要,请包括输入检查。

      【讨论】:

      • 更正:在n = 22 之后,它不再给出准确的答案并产生近似值。
      【解决方案9】:

      我愿意

      (1..n).inject(1, :*)
      

      【讨论】:

        【解决方案10】:

        只是另一种方法,虽然它确实没有必要。

        class Factorial
           attr_reader :num
           def initialize(num)
              @num = num
           end
        
           def find_factorial
              (1..num).inject(:*) || 1
           end
        end
        
        number = Factorial.new(8).find_factorial
        puts number
        

        【讨论】:

          【解决方案11】:

          还有另一种方式(=

          def factorial(number)
            number = number.to_i
            number_range = (number).downto(1).to_a
            factorial = number_range.inject(:*)
            puts "The factorial of #{number} is #{factorial}"
          end
          factorial(#number)
          

          【讨论】:

            【解决方案12】:

            您可能会发现 Ruby feature request 很有用。它包含一个重要的patch,其中包括一个demo Bash script。简单循环与批处理中提供的解决方案之间的速度差异实际上可以是 100 倍(百倍)。全部用纯 Ruby 编写。

            【讨论】:

              【解决方案13】:

              只要调用这个函数

              def factorial(n=0)
                (1..n).inject(:*)
              end
              

              例子

              factorial(3)
              factorial(11)
              

              【讨论】:

                【解决方案14】:

                这是我的版本,即使不是那么干净,我似乎也很清楚。

                def factorial(num)
                    step = 0
                    (num - 1).times do (step += 1 ;num *= step) end
                    return num
                end
                

                这是我的 irb 测试线,显示了每个步骤。

                num = 8;step = 0;(num - 1).times do (step += 1 ;num *= step; puts num) end;num
                

                【讨论】:

                  【解决方案15】:
                  class Integer
                    def !
                      (1..self).inject(:*)
                    end
                  end
                  

                  例子

                  !3  # => 6
                  !4  # => 24
                  

                  【讨论】:

                  • class Integer ; def ! ; (1..self).inject(:*) ; end ; end 有什么问题?
                  • @mudasobwa 我喜欢它,为了简单起见我进行了重构。
                  • 我恭敬地建议,重写并入所有 Ruby 对象的 instance method 以返回一个真实的值,而不是一个虚假的值,这可能不会让你有很多朋友。
                  • 如果a 恰好是Integer!a 的情况下,使否定运算符变成其他东西可能真的很危险......这样做可能会导致存在错误这很难说。如果a恰好是一个很大的数字,比如357264543,那么处理器就会进入一个大循环,人们可能想知道为什么程序突然变慢了
                  • 这个答案更多的是分享一个很酷的东西,而不是一个实用的例子。
                  【解决方案16】:

                  在数学中,factorial of n 就是 gamma function of n+1
                  (见:http://en.wikipedia.org/wiki/Gamma_function

                  Ruby 有Math.gamma(),所以只需使用Math.gamma(n+1) 并在需要时将其转换回整数。

                  【讨论】:

                    【解决方案17】:

                    还有一种方法:

                    # fact(n) => Computes the Factorial of "n" = n!
                    
                    def fact(n) (1..n).inject(1) {|r,i| r*i }end
                    
                    fact(6) => 720
                    

                    【讨论】:

                      【解决方案18】:

                      为什么标准库需要一个阶乘方法,当有一个用于这个确切目的的内置迭代器时?它被称为upto

                      不,您不需要使用递归,就像所有其他答案所示。

                      def fact(n)
                        n == 0 ? 1 : n * fact(n - 1)
                      end  
                      

                      相反,内置的迭代器 upto 可用于计算阶乘:

                      factorial = 1
                      1.upto(10) {|x| factorial *= x }
                      factorial
                       => 3628800
                      

                      【讨论】:

                        【解决方案19】:

                        谨向所有参与并花时间帮助我们的人致以崇高的敬意,我想分享我对此处列出的解决方案的基准。 参数:

                        迭代次数 = 1000

                        n = 6

                                                             user     system      total        real
                        Math.gamma(n+1)                   0.000383   0.000106   0.000489 (  0.000487)
                        (1..n).inject(:*) || 1            0.003986   0.000000   0.003986 (  0.003987)
                        (1..n).reduce(1, :*)              0.003926   0.000000   0.003926 (  0.004023)
                        1.upto(n) {|x| factorial *= x }   0.003748   0.011734   0.015482 (  0.022795)
                        

                        对于 n = 10

                          user     system      total        real
                        0.000378   0.000102   0.000480 (  0.000477)
                        0.004469   0.000007   0.004476 (  0.004491)
                        0.004532   0.000024   0.004556 (  0.005119)
                        0.027720   0.011211   0.038931 (  0.058309)
                        

                        【讨论】:

                        • 值得注意的是,最快的 Math.gamma(n+1) 也只是 n > 22 的近似值,因此可能并不适合所有用例。
                        【解决方案20】:

                        在 Ruby 中,阶乘的标准库函数 不可用。这样我们就可以在ruby中做一个简单的阶乘函数了。

                        def factorial_number(n)
                         if n <= 1
                            1
                         else
                            n * factorial_number(n-1)
                          end
                        end
                        
                        puts factorial_number(6) #Output is 720   => (6*5*4*3*2*1)
                        puts factorial_number(8) #Output is 40320 => (8*7*6*5*4*3*2*1)
                        

                        【讨论】:

                          猜你喜欢
                          • 2021-01-17
                          • 2020-02-26
                          • 2019-08-06
                          • 1970-01-01
                          • 1970-01-01
                          • 2022-06-24
                          • 2016-06-10
                          • 2011-07-05
                          • 2015-04-16
                          相关资源
                          最近更新 更多