2009-07-03 12 views
24

In Ruby möchte ich einen Float zu einem int konvertieren, wenn es eine ganze Zahl ist. Zum BeispielRuby runden float to_int wenn ganze Zahl

a = 1.0 
b = 2.5 

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

Grundsätzlich versuche ich die Anzeige“0,0" auf einer beliebigen Anzahl zu vermeiden, die nicht eine Dezimalzahl hat. Ich suche nach einem eleganten (oder eingebauten) Weg zu tun

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

Antwort

5

Dies ist die Lösung, die die Art und Weise arbeiten landete ich möchte es:

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 

diese Weise kann ich die is_whole? Logik aktualisieren kann (I scheint wie Tadman ist, ist die anspruchsvollste), wenn nötig, und es wird sichergestellt, dass irgendwo, wo ein Float zu einer Zeichenkette (zB in einer Form) ausgibt, es so erscheint, wie ich es möchte (dh keine Nullen am Ende).

Danke an alle für Ihre Ideen - sie haben wirklich geholfen.

3

Ich weiß nicht viel über Ruby.

Aber das ist ein Display Problem. Ich wäre sehr überrascht, wenn die Bibliotheken, die Sie verwenden, keine Möglichkeit haben, eine Zahl zu formatieren, wenn Sie sie in eine Zeichenkette konvertieren.

Es gibt möglicherweise keine Catch-all-Formatierungsoption, die genau das tut, was Sie wollen, aber Sie könnten eine Methode einrichten, die true zurückgibt, wenn float die Float-Repräsentation einer ganzen Zahl ist und andernfalls false. Innerhalb einer Formatierungsroutine, die Sie erstellen (Sie müssen dies also nur einmal tun), ändern Sie einfach die Formatierung basierend darauf, ob dies wahr oder falsch ist.

This erläutert, wie die Anzahl der Ziffern gesteuert wird, die beim Anzeigen einer Zahl nach dem Dezimalzeichen angezeigt werden.

Achten Sie auf die Feinheiten von Gleitkommadarstellungen. Math könnte sagen, die Antwort ist 3, aber Sie können 3.000000000000000000001 erhalten. Ich würde vorschlagen, ein Delta zu verwenden, um zu sehen, ob die Zahl fast eine ganze Zahl ist.

+0

Das ist richtig, aber ich möchte, dass es auf diese Weise * überall * einen Float-Ausgang als String anzeigt. Grundsätzlich möchte ich die Float.to_s-Methode überschreiben oder diese Logik am Ende hängen. –

2

Obwohl ich dazu neigen würde mit der oben genannten Post zustimmen, wenn Sie dies tun müssen:

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

Ich weiß nicht viel über Ruby-entweder.

Aber in C++, würde ich dies tun:

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

Und dann würde ich die Ausgabe Präzision auf dieser Grundlage zu formatieren.

48

Ein einfacher Weg, um es sei:

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

Das ist, weil:

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

Dann Sie tun können:

irb> 1.0.prettify 
=> 1 

irb> 1.5.prettify 
=> 1.5 
1

Hier ist für pädagogische Zwecke meiner schrecklich hacktastic Umsetzung zur Verfügung gestellt :

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 

Der Grund für die Verwendung des sprintf-style-Aufrufs ist, dass Gleitkomma-Näherungswerte viel zuverlässiger gehandhabt werden, als dies bei der Methode Float # round der Fall ist.

41

Ein Motto sprintf ...

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

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

Wie würden Sie etwas wie "# {% g, prozentual}% off" '? Ist es als One-Liner möglich? – Dennis

+0

vielen Dank, genau das, was ich gesucht habe. – Toontje

+0

Nicht genau, denn es fällt nicht nur '.0', sondern auch alles, wenn der Exponent kleiner als -4 ist, und runde es, zum Beispiel:' "% g"% 1.123456789 # => "1.12346" ' –

2

Wenn Sie Schienen verwenden Sie Helfer number_to_rounded mit Option verwenden können strip_insignificant_zeros, zum Beispiel:

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

oder so:

42.0.to_s(:rounded, strip_insignificant_zeros: true)