2009-07-03 42 views
24

En ruby, quiero convertir un float en un int si se trata de un número entero. Por ejemploRuby round float to_int si el número entero es

a = 1.0 
b = 2.5 

a.to_int_if_whole # => 1 
b.to_int_if_whole # => 2.5 

Básicamente estoy tratando de evitar mostrar" 0.0" en cualquier número que no tiene un número decimal. Estoy buscando una manera elegante (o incorporada) de hacer

def to_int_if_whole(float) 
    (float % 1 == 0) ? float.to_i : float 
end 

Respuesta

5

Esta es la solución que terminó trabajando de la manera que yo quiero que:

class Float 
    alias_method(:original_to_s, :to_s) unless method_defined?(:original_to_s) 

    def is_whole? 
    self % 1 == 0 
    end 

    def to_s 
    self.is_whole? ? self.to_i.to_s : self.original_to_s 
    end 
end 

De esta manera puedo actualizar la lógica is_whole? (I parece que Tadman de es el más sofisticado) si es necesario, y asegura que en cualquier lugar donde un Float salga a una cadena (por ejemplo, en una forma) aparece de la manera que yo quiero (es decir, sin ceros en el extremo).

Gracias a todos por sus ideas, realmente han ayudado.

3

No sé mucho sobre Ruby.

Pero esta es una pantalla problema. Me sorprendería enormemente si las bibliotecas que está utilizando no tienen forma de formatear un número cuando lo convierte en una cadena.

Puede que no exista una opción de formato catch-all que haga exactamente lo que usted desea pero puede configurar un método que devuelva true si el float es la representación flotante de un número entero y de lo contrario es falso. Dentro de una rutina de formateo que usted crea (por lo que solo tiene que hacer esto en un solo lugar) simplemente cambie el formato en función de si esto es verdadero o falso.

This explica cómo controlar el número de dígitos que aparecen después del decimal al mostrar un número.

Tenga cuidado con las complejidades de las representaciones de coma flotante. Las matemáticas podrían decir que la respuesta es 3 pero puede obtener 3.000000000000000000001. Sugeriría usar un delta para ver si el número es casi un número entero.

+0

Esto es cierto, pero quiero que se muestre de esta manera * en todas partes * una salida de flotación como una cadena. Básicamente, quiero anular el método Float.to_s, o colgar esta lógica al final del mismo. –

2

Aunque me tiendo a estar de acuerdo con el comentario anterior, si usted debe hacer esto:

(float == float.floor) ? float.to_i : float 
0

No sé mucho sobre Ruby tampoco.

Pero en C++, lo haría esto:

bool IsWholeNumber(float f) 
{ 
    const float delta = 0.0001; 
    int i = (int) f; 
    return (f - (float)i) < delta; 
} 

Y entonces yo formato a la precisión de salida en base a eso.

48

Una forma sencilla de que sería:

class Float 
    def prettify 
    to_i == self ? to_i : self 
    end 
end 

Esto se debe a:

irb> 1.0 == 1 
=> true 
irb> 1 == 1.0 
=> true 

Posteriormente, se podría hacer:

irb> 1.0.prettify 
=> 1 

irb> 1.5.prettify 
=> 1.5 
1

Aquí está mi aplicación terriblemente hacktastic proporcionan para los propósitos educativos :

class Float 
    def to_int_if_whole(precision = 2) 
    ("%.#{precision}f" % self).split(/\./).last == '0' * precision and self.to_i or self 
    end 
end 

puts 1.0.to_int_if_whole # => 1 
puts 2.5.to_int_if_whole # => 2.5 
puts 1.9999999999999999999923.to_int_if_whole # => 2 

El motivo por el que se utiliza la llamada al estilo sprintf es que maneja las aproximaciones de coma flotante de forma mucho más fiable que lo que suele hacer el método Float # round.

41

Un sprintf un trazador de líneas ...

sprintf("%g", 5.0) 
=> "5" 

sprintf("%g", 5.5) 
=> "5.5" 
+0

¿Cómo harías algo como '" # {% g, percentage}% off "'? ¿Es posible como un trazador de líneas? – Dennis

+0

muchas gracias, justo lo que estaba buscando. – Toontje

+0

No exactamente, porque no solo cae '.0', sino también todo si el exponente es menor que -4, y lo redondea, por ejemplo:' "% g"% 1.123456789 # => "1.12346" ' –

2

Si está utilizando rieles se puede usar con la opción de ayuda number_to_roundedstrip_insignificant_zeros, por ejemplo:

ActiveSupport::NumberHelper.number_to_rounded(42.0, strip_insignificant_zeros: true) 

o como esto:

42.0.to_s(:rounded, strip_insignificant_zeros: true) 
Cuestiones relacionadas