Tôi đang phát điên: Hàm Ruby cho giai thừa ở đâu? Không, tôi không cần triển khai hướng dẫn, tôi chỉ muốn hàm từ thư viện. Nó không phải trong Toán học!
Tôi bắt đầu nghi ngờ, nó có phải là một chức năng thư viện chuẩn không?
Tôi đang phát điên: Hàm Ruby cho giai thừa ở đâu? Không, tôi không cần triển khai hướng dẫn, tôi chỉ muốn hàm từ thư viện. Nó không phải trong Toán học!
Tôi bắt đầu nghi ngờ, nó có phải là một chức năng thư viện chuẩn không?
(1..6).inject(:*)
ngắn gọn hơn một chút.
(1..num).inject(:*)
không thành công cho trường hợp nơi num == 0
. (1..(num.zero? ? 1 : num)).inject(:*)
đưa ra câu trả lời đúng cho trường hợp 0 và trả về nil
cho các tham số âm.
Câu trả lời:
Không có hàm giai thừa trong thư viện chuẩn.
Math.gamma
phương thức, ví dụ: stackoverflow.com/a/37352690/407213
Như thế này thì tốt hơn
(1..n).inject(:*) || 1
(1..n).reduce(1, :*)
.
Nó không có trong thư viện chuẩn nhưng bạn có thể mở rộng lớp 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 Giai thừa lặp lại là một lựa chọn tốt hơn vì lý do hiệu suất rõ ràng.
Một cách đáng xấu hổ được đưa nôi từ http://rosettacode.org/wiki/Factorial#Ruby , sở thích cá nhân của tôi là
class Integer
def fact
(1..self).reduce(:*) || 1
end
end
>> 400.fact
=> 64034522846623895262347970319503005850702583026002959458684445942802397169186831436278478647463264676294350575035856810848298162883517435228961988646802997937341654150838162426461942352307046244325015114448670890662773914918117331955996440709549671345290477020322434911210797593280795101545372667251627877890009349763765710326350331533965349868386831339352024373788157786791506311858702618270169819740062983025308591298346162272304558339520759611505302236086810433297255194852674432232438669948422404232599805551610635942376961399231917134063858996537970147827206606320217379472010321356624613809077942304597360699567595836096158715129913822286578579549361617654480453222007825818400848436415591229454275384803558374518022675900061399560145595206127211192918105032491008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Việc triển khai này cũng diễn ra nhanh nhất trong số các biến thể được liệt kê trong Mã Rosetta.
Đã thêm || 1
để xử lý trường hợp số không.
Để cảm ơn và đánh giá cao Mark Thomas , đây là một phiên bản hiệu quả hơn, trang nhã và ít người biết đến hơn một chút:
class Integer
def fact
(2..self).reduce(1,:*)
end
end
reduce
: (1..self).reduce(1,:*)
.
(2..self).reduce(1,:*)
, nếu vi-hiệu quả là điều bạn :)
Trong toán học, factorial of n
chỉ là gamma function of n+1
(xem: http://en.wikipedia.org/wiki/Gamma_ Chức năng )
Ruby Math.gamma()
chỉ cần sử dụng Math.gamma(n+1)
và chuyển nó trở lại một số nguyên nếu muốn.
Bạn cũng có thể sử dụng Math.gamma
hàm tổng hợp thành giai thừa cho các tham số số nguyên.
0..22
: MRI Ruby thực sự thực hiện tra cứu các giá trị đó (xem static const double fact_table[]
trong nguồn ). Ngoài ra, nó là một con số gần đúng. 23 !, chẳng hạn, yêu cầu phần định trị 56-bit không thể biểu diễn chính xác bằng cách sử dụng đôi IEEE 754 có phần định trị 53-bit.
class Integer
def !
(1..self).inject(:*)
end
end
!3 # => 6
!4 # => 24
class Integer ; def ! ; (1..self).inject(:*) ; end ; end
?
a
xảy ra Integer
trong trường hợp !a
... làm như vậy có thể gây ra một lỗi tồn tại rất khó nhận biết. Nếu a
xảy ra là một con số lớn như 357264543
sau đó bộ vi xử lý là đi sâu vào một vòng lặp lớn và mọi người có thể tự hỏi tại sao chương trình tất cả của một đột ngột trở nên chậm chạp
def factorial(n=0)
(1..n).inject(:*)
end
factorial(3)
factorial(11)
Sử dụng Math.gamma.floor
là một cách dễ dàng để tạo ra một giá trị gần đúng và sau đó làm tròn nó trở lại kết quả số nguyên chính xác. Sẽ hoạt động với tất cả các Số nguyên, hãy bao gồm kiểm tra đầu vào nếu cần.
n = 22
nó ngừng đưa ra câu trả lời chính xác và tạo ra giá trị gần đúng.
Với sự tôn trọng cao đối với tất cả những người đã tham gia và dành thời gian của họ để giúp đỡ chúng tôi, tôi muốn chia sẻ điểm chuẩn của tôi về các giải pháp được liệt kê ở đây. Tham số:
số lần lặp = 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)
Đối với 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)
cũng chỉ gần đúng với n> 22, vì vậy có thể không phù hợp với mọi trường hợp sử dụng.
Chỉ là một cách khác để làm điều đó, mặc dù nó thực sự không cần thiết.
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
Bạn có thể sẽ thấy một yêu cầu tính năng Ruby hữu ích. Nó chứa một bản vá quan trọng bao gồm một tập lệnh Bash demo . Sự khác biệt về tốc độ giữa một vòng lặp ngây thơ và giải pháp được trình bày trong lô có thể là 100x (hàng trăm lần) theo đúng nghĩa đen. Được viết bằng Ruby nguyên chất.
Đây là phiên bản của tôi dường như rõ ràng với tôi mặc dù nó không được sạch sẽ.
def factorial(num)
step = 0
(num - 1).times do (step += 1 ;num *= step) end
return num
end
Đây là dòng thử nghiệm irb của tôi hiển thị từng bước.
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
Chỉ cần một cách nữa để làm điều đó:
# fact(n) => Computes the Factorial of "n" = n!
def fact(n) (1..n).inject(1) {|r,i| r*i }end
fact(6) => 720
Tại sao thư viện chuẩn lại yêu cầu phương pháp giai thừa, khi có một trình lặp tích hợp cho mục đích chính xác này? Nó được gọi là upto
.
Không, bạn không cần phải sử dụng đệ quy, giống như tất cả các câu trả lời khác hiển thị.
def fact(n)
n == 0 ? 1 : n * fact(n - 1)
end
Thay vào đó, trình vòng lặp tích hợp tối đa có thể được sử dụng để tính các giai thừa:
factorial = 1
1.upto(10) {|x| factorial *= x }
factorial
=> 3628800
6.downto(1).inject(:*)