Я схожу с ума: где функция Ruby для факториала? Нет, мне не нужны учебные реализации, мне просто нужна функция из библиотеки. Это не по математике!
Я начинаю сомневаться, это стандартная библиотечная функция?
Я схожу с ума: где функция Ruby для факториала? Нет, мне не нужны учебные реализации, мне просто нужна функция из библиотеки. Это не по математике!
Я начинаю сомневаться, это стандартная библиотечная функция?
(1..6).inject(:*)
что более лаконично.
(1..num).inject(:*)
не работает в случае, когда num == 0
. (1..(num.zero? ? 1 : num)).inject(:*)
дает правильный ответ для случая 0 и возвращает nil
для отрицательных параметров.
Ответы:
В стандартной библиотеке нет факториальной функции.
Math.gamma
метод, например stackoverflow.com/a/37352690/407213
Как это лучше
(1..n).inject(:*) || 1
(1..n).reduce(1, :*)
.
Его нет в стандартной библиотеке, но вы можете расширить класс 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
NB. Итерационный факториал - лучший выбор по очевидным причинам производительности.
Беззастенчиво скопировано с http://rosettacode.org/wiki/Factorial#Ruby , мой личный фаворит -
class Integer
def fact
(1..self).reduce(:*) || 1
end
end
>> 400.fact
=> 64034522846623895262347970319503005850702583026002959458684445942802397169186831436278478647463264676294350575035856810848298162883517435228961988646802997937341654150838162426461942352307046244325015114448670890662773914918117331955996440709549671345290477020322434911210797593280795101545372667251627877890009349763765710326350331533965349868386831339352024373788157786791506311858702618270169819740062983025308591298346162272304558339520759611505302236086810433297255194852674432232438669948422404232599805551610635942376961399231917134063858996537970147827206606320217379472010321356624613809077942304597360699567595836096158715129913822286578579549361617654480453222007825818400848436415591229454275384803558374518022675900061399560145595206127211192918105032491008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Эта реализация также оказалась самой быстрой среди вариантов, перечисленных в Rosetta Code.
Добавлено || 1
для обработки нулевого случая.
С благодарностью и признательностью Марку Томасу , вот версия, которая немного более эффективна, элегантна и неясна:
class Integer
def fact
(2..self).reduce(1,:*)
end
end
reduce
: (1..self).reduce(1,:*)
.
(2..self).reduce(1,:*)
, если вам
В математике factorial of n
это просто gamma function of n+1
(см. Http://en.wikipedia.org/wiki/Gamma_function )
В Ruby Math.gamma()
так просто используйте Math.gamma(n+1)
и при желании верните его к целому числу.
Вы также можете использовать Math.gamma
функцию, которая сводится к факториалу для целочисленных параметров.
0..22
: MRI Ruby фактически выполняет поиск этих значений (см. static const double fact_table[]
В источнике ). Кроме того, это приближение. 23 !, например, требуется 56-битная мантисса, которую невозможно точно представить с помощью двойника IEEE 754, который имеет 53-битную мантиссу.
class Integer
def !
(1..self).inject(:*)
end
end
!3 # => 6
!4 # => 24
class Integer ; def ! ; (1..self).inject(:*) ; end ; end
?
a
случается Integer
в случае !a
... это может вызвать ошибку, которую очень трудно определить. Если a
это большое число, например, 357264543
тогда процессор входит в большой цикл, и люди могут задаться вопросом, почему программа внезапно становится медленной
def factorial(n=0)
(1..n).inject(:*)
end
factorial(3)
factorial(11)
Использование Math.gamma.floor
- это простой способ получить приближение, а затем округлить его до правильного целочисленного результата. Должно работать для всех целых чисел, при необходимости включите проверку ввода.
n = 22
он перестает давать точный ответ и производит приближения.
С большим уважением ко всем, кто участвовал и потратили свое время, чтобы помочь нам, я хотел бы поделиться своими тестами решений, перечисленных здесь. Параметры:
итераций = 1000
п = 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, поэтому может не подходить для всех случаев использования.
Возможно, вам будет полезен запрос на добавление функции Ruby . Он содержит нетривиальный патч , включающий демонстрационный скрипт Bash . Разница в скорости между наивным циклом и решением, представленным в пакете, может быть буквально в 100 раз. Написано все на чистом Ruby.
Вот моя версия кажется мне понятной, хотя она не такая чистая.
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
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
И еще один способ (=
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)
Зачем стандартной библиотеке нужен факториальный метод, если есть встроенный итератор именно для этой цели? Это называетсяupto
.
Нет, вам не нужно использовать рекурсию, как показывают все эти другие ответы.
def fact(n)
n == 0 ? 1 : n * fact(n - 1)
end
Скорее, встроенный итератор upto можно использовать для вычисления факториалов:
factorial = 1
1.upto(10) {|x| factorial *= x }
factorial
=> 3628800
6.downto(1).inject(:*)