Nếu mã bạn đã viết lẫn lộn bạn thì đây phải thực sự uốn cong tâm trí của bạn:
def clean_output(amount)
amount.zero? && 0.0 || amount
end
Với một số bằng chứng:
irb(main):005:0> f = 0.0
=> 0.0
irb(main):006:0> f.zero? && 0.0 || f
=> 0.0
irb(main):007:0> f = -0.0
=> -0.0
irb(main):008:0> f.zero? && 0.0 || f
=> 0.0
irb(main):009:0> f=1.0
=> 1.0
irb(main):010:0> f.zero? && 0.0 || f
=> 1.0
tôi không thích sử dụng nonzero?
vì use-case của nó là một chút bối rối. Nó là một phần của Numeric nhưng các tài liệu cho thấy nó được sử dụng như một phần của Comparable với toán tử <=>
. Thêm vào đó, tôi muốn thử nghiệm cho một điều kiện không cho mục đích này bởi vì nó có vẻ đơn giản hơn.
Và, mặc dù mã của OP có thể xuất hiện tiết, đây là một trong những trường hợp tối ưu hóa quá sớm không trả hết:
require 'benchmark'
def clean_output(amount)
if amount.zero?
0.0
else
amount
end
end
def clean_output2(amount)
amount.zero? && 0.0 || amount
end
def clean_output3(value)
value + 0
end
class Numeric
def clean_to_s
(nonzero? || abs).to_s
end
end
n = 5_000_000
Benchmark.bm(14) do |x|
x.report("clean_output:" ) { n.times { a = clean_output(-0.0) } }
x.report("clean_output2:") { n.times { a = clean_output2(-0.0) } }
x.report("clean_output3:") { n.times { a = clean_output3(-0.0) } }
x.report("clean_to_s:" ) { n.times { a = 0.0.clean_to_s } }
end
Và kết quả:
ruby test.rb
user system total real
clean_output: 2.120000 0.000000 2.120000 ( 2.127556)
clean_output2: 2.230000 0.000000 2.230000 ( 2.222796)
clean_output3: 2.530000 0.000000 2.530000 ( 2.534189)
clean_to_s: 7.200000 0.010000 7.210000 ( 7.200648)
ruby test.rb
user system total real
clean_output: 2.120000 0.000000 2.120000 ( 2.122890)
clean_output2: 2.200000 0.000000 2.200000 ( 2.203456)
clean_output3: 2.540000 0.000000 2.540000 ( 2.533085)
clean_to_s: 7.200000 0.010000 7.210000 ( 7.204332)
Tôi đã thêm phiên bản không có to_s
. Chúng được chạy trên máy tính xách tay của tôi, đó là một vài tuổi, đó là lý do những lần kết quả cao hơn so với các bài kiểm tra theo thời gian:
require 'benchmark'
def clean_output(amount)
if amount.zero?
0.0
else
amount
end
end
def clean_output2(amount)
amount.zero? && 0.0 || amount
end
def clean_output3(value)
value + 0
end
class Numeric
def clean_to_s
(nonzero? || abs).to_s
end
def clean_no_to_s
nonzero? || abs
end
end
n = 5_000_000
Benchmark.bm(14) do |x|
x.report("clean_output:" ) { n.times { a = clean_output(-0.0) } }
x.report("clean_output2:") { n.times { a = clean_output2(-0.0) } }
x.report("clean_output3:") { n.times { a = clean_output3(-0.0) } }
x.report("clean_to_s:" ) { n.times { a = -0.0.clean_to_s } }
x.report("clean_no_to_s:") { n.times { a = -0.0.clean_no_to_s } }
end
Và kết quả:
ruby test.rb
user system total real
clean_output: 3.030000 0.000000 3.030000 ( 3.028541)
clean_output2: 2.990000 0.010000 3.000000 ( 2.992095)
clean_output3: 3.610000 0.000000 3.610000 ( 3.610988)
clean_to_s: 8.710000 0.010000 8.720000 ( 8.718266)
clean_no_to_s: 5.170000 0.000000 5.170000 ( 5.170987)
ruby test.rb
user system total real
clean_output: 3.050000 0.000000 3.050000 ( 3.050175)
clean_output2: 3.010000 0.010000 3.020000 ( 3.004055)
clean_output3: 3.520000 0.000000 3.520000 ( 3.525969)
clean_to_s: 8.710000 0.000000 8.710000 ( 8.710635)
clean_no_to_s: 5.140000 0.010000 5.150000 ( 5.142462)
Để sắp xếp ra những gì đã làm chậm xuống non_zero?
:
require 'benchmark'
n = 5_000_000
Benchmark.bm(9) do |x|
x.report("nonzero?:") { n.times { -0.0.nonzero? } }
x.report("abs:" ) { n.times { -0.0.abs } }
x.report("to_s:" ) { n.times { -0.0.to_s } }
end
với kết quả:
ruby test.rb
user system total real
nonzero?: 2.750000 0.000000 2.750000 ( 2.754931)
abs: 2.570000 0.010000 2.580000 ( 2.569420)
to_s: 4.690000 0.000000 4.690000 ( 4.687808)
ruby test.rb
user system total real
nonzero?: 2.770000 0.000000 2.770000 ( 2.767523)
abs: 2.570000 0.010000 2.580000 ( 2.569757)
to_s: 4.670000 0.000000 4.670000 ( 4.678333)
Cảm ơn bạn rất nhiều vì câu trả lời này. Nó thực sự mang tính thông tin. Các tiêu chuẩn không thực sự có liên quan đến ứng dụng của tôi, nhưng nó rất thú vị khi thấy rằng clean_to_s chậm hơn rất nhiều so với các giải pháp khác. – Frost
Sự khác biệt sẽ không lớn nếu bạn xóa cuộc gọi 'to_s'. Nếu bạn đang đi để in các giá trị đó, nó sẽ được gọi là anyway, nhưng trong tiêu chuẩn này nó được gọi là rõ ràng trong 'clean_to_s'. Mặc dù, 'nonzero?' + 'Abs' là chậm hơn nhiều khả năng vì nó liên quan đến hai cuộc gọi phương thức thay vì một trong các trường hợp khác. –
@ KL-7, "Sự khác biệt sẽ không quá lớn nếu bạn xóa cuộc gọi to_s". Tôi đã thêm một số bài kiểm tra nữa để xem. –