2010-11-09 5 views
4

J'ai une valeur numérique comme 30.6355 qui représente l'argent, comment arrondir à 2 décimales?J'ai une valeur numérique comme 30.6355 qui représente l'argent, comment arrondir à 2 décimales?

+2

Êtes-vous vendant de l'essence? Pourquoi auriez-vous de l'argent à la 5ème virgule? –

+1

duplicata possible de [Arrondir un nombre entier de rubis à 0,05 près] (http://stackoverflow.com/questions/1346257/round-a-ruby-integer-up-to-the-nearest-0-05) - question dit 0.05 mais la même technique s'applique à n'importe quelle unité, comme 0.01 –

+2

Oh, l'argent dans le flotteur ... encore ... Est-ce que '.0055' est une erreur flottante accumulée?))) – Nakilon

Répondre

13

Ruby 1.8:

class Numeric 
    def round_to(places) 
     power = 10.0**places 
     (self * power).round/power 
    end 
end 

(30.6355).round_to(2) 

Ruby 1.9:

(30.6355).round(2) 

En 1.9, round peut arrondir à un nombre spécifié de chiffres.

20

Vous ne devriez pas utiliser double ou float types lorsqu'ils traitent avec la devise: ils ont à la fois trop de décimales et des erreurs d'arrondi occasionnelles. L'argent peut tomber à travers ces trous et il sera difficile de repérer les erreurs après que cela se produise.

Lorsque vous gérez de l'argent, utilisez un type décimal fixe. En Ruby (et Java), utilisez BigDecimal.

+8

En fait, le plus gros problème est qu'elles n'ont pas de décimales * du tout *, elles ont * des positions * binaires *. –

+0

@ Jörg, a raison. Voir http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems pour une explication. – lucasrizoli

+0

'gem install money'. http://money.rubyforge.org/ –

0

Ceci arrondira pour quelques cas utiles - pas bien écrit mais cela fonctionne! N'hésitez pas à modifier.

def round(numberString) 
numberString = numberString.to_s 
decimalLocation = numberString.index(".") 
numbersAfterDecimal = numberString.slice(decimalLocation+1,numberString.length-1) 
numbersBeforeAndIncludingDeciaml = numberString.slice(0,decimalLocation+1) 

if numbersAfterDecimal.length <= 2 
    return numberString.to_f 
end 

thingArray = numberString.split("") 
thingArray.pop 

prior = numbersAfterDecimal[-1].to_i 
idx = numbersAfterDecimal.length-2 

thingArray.reverse_each do |numStr| 
    if prior >= 5 
     numbersAfterDecimal[idx] = (numStr.to_i + 1).to_s unless (idx == 1 && numStr.to_i == 9) 
     prior = (numStr.to_i + 1) 
    else 
     prior = numStr.to_i 
    end 
    break if (idx == 1) 
    idx -= 1 
end 

resp = numbersBeforeAndIncludingDeciaml + numbersAfterDecimal[0..1] 
resp.to_f 
end 

round(18.00) == 18.0

round(18.99) == 18.99

round(17.9555555555) == 17.96

round(17.944444444445) == 17.95

round(15.545) == 15.55

round(15.55) == 15.55

round(15.555) == 15.56

round(1.18) == 1.18

round(1.189) == 1.19

Questions connexes