Se il codice che hai scritto ti confonde allora questo dovrebbe piegare davvero la vostra mente:
def clean_output(amount)
amount.zero? && 0.0 || amount
end
Con qualche prova:
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
non mi piace usare nonzero?
perché il suo caso d'uso è un po 'confuso. Fa parte di Numeric ma i documenti lo mostrano come parte di Comparable con l'operatore <=>
. Inoltre, preferisco testare una condizione zero per questo scopo perché sembra più semplice.
E, anche se il codice del PO potrebbe apparire prolisso, questo è un altro di quei casi in cui l'ottimizzazione prematura non paga:
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
E i risultati:
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)
Ho aggiunto una versione senza lo to_s
. Questi sono stati eseguiti sul mio computer portatile, che è di diversi anni, che è il motivo per cui i tempi risultanti sono superiori ai precedenti test:
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
E i risultati:
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)
di risolvere quello che è stato rallentando giù 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
Con i risultati:
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)
Grazie mille per questa risposta. È davvero informativo. I benchmark non sono davvero rilevanti per la mia applicazione, ma è molto interessante vedere che clean_to_s è molto più lento delle altre soluzioni. – Frost
La differenza non sarà così grande se si rimuove la chiamata 'to_s'. Se si stampano i valori, verrà chiamato comunque, ma in questo benchmark viene chiamato esplicitamente in 'clean_to_s'. Anche se 'nonzero?' + 'Abs' è più lento comunque molto probabilmente perché comporta due chiamate al metodo invece di una in altri casi. –
@ KL-7, "La differenza non sarà così grande se si rimuove la chiamata to_s." Ho aggiunto altri test da vedere. –