Ответ 1
Если код, который вы написали, смущает вас, тогда это должно действительно свести с ума:
def clean_output(amount)
amount.zero? && 0.0 || amount
end
С некоторым доказательством:
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
Мне не нравится использовать nonzero?
, потому что его прецедент немного запутан. Это часть Numeric, но документы показывают, что она используется как часть Comparable с оператором <=>
. Кроме того, я бы предпочел проверить нулевое условие для этой цели, потому что это кажется более простым.
И хотя код OP может показаться многословным, это еще один из тех случаев, когда преждевременная оптимизация не окупается:
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
И результаты:
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)
Я добавил версию без to_s
. Они были запущены на моем ноутбуке, которому несколько лет, поэтому результирующие времена выше предыдущих тестов:
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
И результаты:
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)
Чтобы узнать, что замедлялось 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
С результатами:
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)