Если код, который вы написали, сбивает вас с толку, то это должно действительно сойти с ума:
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 с оператором <=>
.Кроме того, я бы предпочел проверить нулевое условие для этой цели, потому что оно кажется более простым.
И, хотя код ОП может показаться многословным, это еще один из тех случаев, когда преждевременная оптимизация не окупается:
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)