quitacementos - ¿Cómo puedo limpiar de manera eficiente el flotador de cero negativo de Ruby?
rubi rc 10 quitacementos mexico (5)
En realidad, hay una solución que no requiere una condición.
def clean_output(value)
value + 0
end
salida:
> clean_output(3.0)
=> 3.0
> clean_output(-3.0)
=> -3.0
> clean_output(-0.0)
=> 0.0
En realidad, no me gusta esta solución mejor que la que acepté, debido a la falta de claridad. Si lo viera en un fragmento de código que no escribí, me preguntaría por qué querría agregar cero a todo.
Aunque resuelve el problema, así que pensé que lo compartiría aquí de todos modos.
En Ruby, 0.0 * -1 == -0.0
.
Tengo una aplicación donde multiplico un montón de objetos Float
con -1
, pero no me gusta el -0.0
en la salida, ya que es confuso.
¿Hay una forma inteligente de hacer que la salida de Float#to_s
0.0
lugar de -0.0
?
Estoy completamente bien con la ejecución de cada objeto Float
través de algún tipo de método scrubber / helper, pero lo siguiente tiende a confundirme aún más:
def clean_output(amount)
if amount.zero?
0.0
else
amount
end
end
ACTUALIZAR:
Para ser más precisos en lo que estoy buscando, quiero una solución que pueda ejecutar en un montón de flotadores, algunos de los cuales serán negativos, otros positivos. Los negativos deben permanecer negativos a menos que sean ceros negativos, es decir, -0.0
.
Ejemplos:
clean_output(-0.0) #=> 0.0
clean_output(-3.0) #=> -3.0
clean_output(3.0) #=> 3.0
No puedo pensar en nada mejor que eso:
def clean_output(value)
value.nonzero? || value.abs
end
pero eso es sólo una variación de su solución. Sin embargo, a diferencia del suyo, este no cambia el tipo de value
(si, por ejemplo, pasa -0
, devolverá 0
). Pero parece que no es importante en tu caso.
Si está seguro de que su código estará más limpio, puede agregar un método como ese a la clase Numeric
(que hará que ese método esté disponible para Float
, Fixnum
y otras clases numéricas):
class Numeric
def clean_to_s
(nonzero? || abs).to_s
end
end
y luego usarlo:
-0.0.clean_to_s # => ''0.0''
-3.0.clean_to_s # => ''-3.0''
# same method for Fixnum''s as a bonus
-0.clean_to_s # => ''0''
Eso hará que sea más fácil procesar una serie de flotadores:
[-0.0, -3.0, 0.0, -0].map &:clean_to_s
# => ["0.0", "-3.0", "0.0", "0"]
Para mí, la intención de este código es un poco más clara y, al menos en Ruby 1.9.3, es un poco más rápida que @la Tin Man''s
def clean_output4(amount)
amount.zero? ? 0.0 : amount
end
user system total real
clean_output: 0.860000 0.000000 0.860000 ( 0.859446)
clean_output4: 0.830000 0.000000 0.830000 ( 0.837595)
Si el código que escribiste te confunde, entonces esto debería realmente cambiar tu 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 el nonzero?
Porque su caso de uso es un poco confuso. Es parte de Numeric pero los documentos muestran que se usó como parte de Comparable con el operador <=>
. Además, prefiero probar una condición cero para este propósito porque parece más sencillo.
Y, aunque el código del OP puede aparecer detallado, este es otro de esos casos en los que la optimización prematura no da resultado:
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)
to_s
una versión sin los to_s
. Estos se ejecutaron en mi computadora portátil, que tiene varios años, por lo que los tiempos resultantes son más altos que los de 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)
Para resolver lo que se estaba desacelerando 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 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)
simplemente verifique si la respuesta es cero y luego aplique abs al valor. Se convertirá -0.0 en 0.0
fl_num = -0.0
fl_num = fl_num.abs
fl_num = 0.0