@mckeed: Или, (1..6).inject(:*)что более лаконично.
sepp2k
8
почему вы ожидаете, что он будет?
Президент Джеймс К. Полк
4
Интересно, каков статус математических и научных библиотек для Ruby.
Эндрю Гримм
5
Просто обратите внимание на предоставленные примеры с использованием inject. (1..num).inject(:*)не работает в случае, когда num == 0. (1..(num.zero? ? 1 : num)).inject(:*)дает правильный ответ для случая 0 и возвращает nilдля отрицательных параметров.
Йог
Ответы:
136
В стандартной библиотеке нет факториальной функции.
Или задать начальное значение непосредственно: (1..n).reduce(1, :*).
Эндрю Маршалл
77
Его нет в стандартной библиотеке, но вы можете расширить класс Integer.
classIntegerdeffactorial_recursiveself <= 1 ? 1 : self * (self - 1).factorial
enddeffactorial_iterative
f = 1; for i in1..self; f *= i; end; f
endalias:factorial:factorial_iterativeend
NB. Итерационный факториал - лучший выбор по очевидным причинам производительности.
что, черт возьми, это значит ?! да, это быстро, но очень неудобно
niccolo m.
3
это также неверно для 0! - должно быть что-то вроде: if self <= 1; 1; еще; (1.. себя) .reduce (: *); конец
Тармо
8
@allen - Не обвиняйте язык, если вы его не понимаете. Это просто означает: взять диапазон от 1 до себя, а затем удалить из него первый элемент (1) (то есть это то, что означает сокращение в функциональном программировании). Затем удалите первый элемент того, что осталось (2), и умножьте (: *) их вместе. Теперь удалите первый элемент из оставшегося (3) и умножьте его на промежуточную сумму. Продолжайте, пока ничего не останется (т.е. вы обработали весь диапазон). Если сокращение не удалось (потому что в случае 0 массив пуст!), То в любом случае просто верните 1.
SDJMcHattie
Вы также можете обращаться с нулевым случаем, указав начальное значение в reduce: (1..self).reduce(1,:*).
Марк Томас
3
На самом деле вы можете использовать (2..self).reduce(1,:*), если вам
Из документов: «Обратите внимание, что гамма (n) такая же, как факт (n-1) для целого числа n> 0. Однако gamma (n) возвращает float и может быть приближением». Если принять это во внимание, это работает, но решение для сокращения кажется намного более простым.
Майкл Коль
Спасибо за это! Моя интуиция говорит, что лучше использовать стандартную библиотеку вместо написанного на заказ сокращения, когда это возможно. Профилирование может подсказать иное.
Дэвид Дж.
2
Примечание. Это O (1) и точно для 0..22: MRI Ruby фактически выполняет поиск этих значений (см. static const double fact_table[]В источнике ). Кроме того, это приближение. 23 !, например, требуется 56-битная мантисса, которую невозможно точно представить с помощью двойника IEEE 754, который имеет 53-битную мантиссу.
Что не так class Integer ; def ! ; (1..self).inject(:*) ; end ; end?
Алексей Матюшкин
@mudasobwa Мне это нравится, для простоты я сделал рефакторинг.
jasonleonhard
4
Я бы со всем уважением предположил, что переопределение метода экземпляра, включенного во все объекты Ruby, для возврата истинного значения, а не ложного, может не сделать вас много друзей.
MatzFan 03
Может быть действительно опасно превращать оператор отрицания во что-то еще, когда aслучается Integerв случае !a... это может вызвать ошибку, которую очень трудно определить. Если aэто большое число, например, 357264543тогда процессор входит в большой цикл, и люди могут задаться вопросом, почему программа внезапно становится медленной
неполярность
Этот ответ был скорее классным, чем практическим примером для использования.
Использование Math.gamma.floor- это простой способ получить приближение, а затем округлить его до правильного целочисленного результата. Должно работать для всех целых чисел, при необходимости включите проверку ввода.
Исправление: после того, как n = 22он перестает давать точный ответ и производит приближения.
Ayarch
2
С большим уважением ко всем, кто участвовал и потратили свое время, чтобы помочь нам, я хотел бы поделиться своими тестами решений, перечисленных здесь. Параметры:
итераций = 1000
п = 6
user system total real
Math.gamma(n+1) 0.000383 0.0001060.000489 ( 0.000487)
(1..n).inject(:*) ||10.003986 0.0000000.003986 ( 0.003987)
(1..n).reduce(1, :*) 0.003926 0.0000000.003926 ( 0.004023)
1.upto(n) {|x| factorial *= x } 0.003748 0.0117340.015482 ( 0.022795)
Для n = 10
user system total real
0.000378 0.0001020.000480 ( 0.000477)
0.004469 0.0000070.004476 ( 0.004491)
0.0045320.0000240.004556 ( 0.005119)
0.0277200.0112110.038931 ( 0.058309)
Стоит отметить, что самый быстрый Math.gamma(n+1)также является приблизительным только для n> 22, поэтому может не подходить для всех случаев использования.
Нил Слейтер,
1
Просто еще один способ сделать это, хотя в этом нет необходимости.
classFactorialattr_reader:numdefinitialize(num)
@num = num
enddeffind_factorial
(1..num).inject(:*) ||1endend
number = Factorial.new(8).find_factorial
puts number
Возможно, вам будет полезен запрос на добавление функции Ruby . Он содержит нетривиальный патч , включающий демонстрационный скрипт Bash . Разница в скорости между наивным циклом и решением, представленным в пакете, может быть буквально в 100 раз. Написано все на чистом Ruby.
classIntegerdeffactorialreturnself < 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.endend
deffactorial(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)
6.downto(1).inject(:*)
(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
Добавлено
|| 1
для обработки нулевого случая.обновление # 2
С благодарностью и признательностью Марку Томасу , вот версия, которая немного более эффективна, элегантна и неясна:
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
тогда процессор входит в большой цикл, и люди могут задаться вопросом, почему программа внезапно становится медленнойя бы сделал
(1..n).inject(1, :*)
источник
Я просто написал свое:
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
источник
Просто вызовите эту функцию
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, поэтому может не подходить для всех случаев использования.Просто еще один способ сделать это, хотя в этом нет необходимости.
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
источник
Возможно, вам будет полезен запрос на добавление функции 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)
источник
Еще один способ сделать это:
# fact(n) => Computes the Factorial of "n" = n! def fact(n) (1..n).inject(1) {|r,i| r*i }end fact(6) => 720
источник
Зачем стандартной библиотеке нужен факториальный метод, если есть встроенный итератор именно для этой цели? Это называется
upto
.Нет, вам не нужно использовать рекурсию, как показывают все эти другие ответы.
def fact(n) n == 0 ? 1 : n * fact(n - 1) end
Скорее, встроенный итератор upto можно использовать для вычисления факториалов:
factorial = 1 1.upto(10) {|x| factorial *= x } factorial => 3628800
источник