Si el código que escribió se confunde entonces esto debe doblar realmente su mente:
def clean_output(amount)
amount.zero? && 0.0 || amount
end
Con alguna prueba:
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
no me gusta usar nonzero?
debido a que su caso de uso está un poco confundido Es parte de Numeric pero los documentos muestran que se usó como parte de Comparable con el operador <=>
. Además, preferiría probar una condición cero para este propósito porque parece más directo.
Y, aunque el código de la OP podría parecer prolijo, este es otro de esos casos en los que la optimización prematura no vale la pena:
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
y los resultados:
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)
Agregué una versión sin el to_s
. Estos se llevaron a cabo en mi portátil, que tiene varios años, por lo que los tiempos resultantes son más altas que las pruebas anteriores:
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
y los resultados:
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)
de resolver lo que estaba desacelerando non_zero?
abajo:
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 los resultados:
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)
Muchas gracias por esta respuesta. Es realmente informativo. Los puntos de referencia no son tan relevantes para mi aplicación, pero es muy interesante ver que clean_to_s es mucho más lento que las otras soluciones. – Frost
La diferencia no será tan grande si elimina la llamada 'to_s'. Si va a imprimir esos valores, se llamará de todos modos, pero en este punto de referencia se llama explícitamente en 'clean_to_s'. Sin embargo, 'nonzero?' + 'Abs' es más lento de todos modos, ya que implica dos llamadas al método en lugar de una en otros casos. –
@ KL-7, "La diferencia no será tan grande si elimina la llamada de to_s". Agregué algunas pruebas más para ver. –