在JRuby中如何将浮点数保留两位小数?

206

在JRuby(1.6.x)中,如何将浮点数保留两位小数并四舍五入?

number = 1.1164
number.round(2)

# The above shows the following error
# wrong number of arguments (1 for 0)
6个回答

347
(5.65235534).round(2)
#=> 5.65

23
(5.6).round(2) 返回的结果仅为 5.6。 - Bala Karthik
6
看起来很合理,那个额外的零占位符仍然存在,只是不可见。 - boulder_ruby
@BalaKarthik 这正是我使用Theo的解决方案的原因。它可以正确地四舍五入(除非你因某种奇怪的原因要超过3个小数位,参见评论),因此如果你正在寻找字符串输出,那么这是更好的解决方案。 - Dylan Vander Berg
这是正确的。我正在生成随机纬度和经度,所以我使用 number.round(6) 来保留 6 位小数。 - gsumk

239

sprintf('%.2f', number)是一种晦涩但非常强大的数字格式化方式。其结果总是一个字符串,但由于你正在四舍五入,我假设你是为了呈现目的而这样做的。sprintf可以以几乎任何你喜欢的方式格式化任何数字,还有更多。

完整的sprintf文档。


96
根据我的经验,“'%.2f' % number”更常用。这个语句会保留小数点后两位数字并将其格式化为字符串。 - Michael Kohl
6
ruby style guide 建议使用 sprintf(或者format)而不是 % 版本。这个决定的一些理由在这里被讨论了,主要考虑到代码的可读性。并不是每个人都需要遵循这个风格指南,只是提供一些原因 :) - Lucy Bain
4
请注意,sprintf在小数点后第三位时,会在6上进行四舍五入,而不是5。例如,sprintf("%.3f", 1.2225) 的结果将是 "1.222",sprintf("%.3f", 1.2226) 的结果将是 "1.223"。如果这对你很重要,建议使用#round函数来避免问题。 - ecoding5
1
"%.2f" 会将 5 四舍五入到小数点后一位的偶数,有什么解决办法吗? - Mirror318
1
@ricks 浮点数是二进制的,而不是十进制的。没有办法在不改变二进制表示的情况下四舍五入到特定的小数位数。在许多数据库中使用 DECIMAL 类型是一种选择,但最常见的四舍五入原因是为了呈现,因此使用字符串并不是不合理的。如果您因会计规则而进行四舍五入,则应从十进制表示开始,而不是浮点数。 - Theo
显示剩余5条评论

96

在Ruby 1.9中,Float#round可以带有一个参数,而在Ruby 1.8中则不行。JRuby默认为1.8版本,但它能够运行在1.9模式下


1
我知道Sam的意图似乎不是为了呈现类似货币的东西而将数字四舍五入,但请注意,如果您尝试这样做(3.round(2)#= > 3.0,而不是3.00),使用#round(precision)将无法按预期工作。要实现此目的,请查看下面Theo的答案。 - jaredsmith

6

编辑

收到反馈后,原来的解决方案似乎不起作用。因此,我根据建议更新了答案。

def float_of_2_decimal(float_n) 
  float_n.to_d.round(2, :truncate).to_f
end

如果您想要保留两位小数的四舍五入数字,其他答案可能有效。但是,如果您想要保留前两位小数点不进行四舍五入,那么这些答案将无法帮助您。

因此,为了获得一个带有前两位小数点的浮点数,我使用了这个技巧。在某些情况下可能不适用

def float_of_2_decimal(float_n)
  float_n.round(3).to_s[0..3].to_f
end

使用 5.666666666666666666666666,它会返回 5.66 而不是四舍五入后的 5.67。希望对某些人有所帮助。


1
这个不起作用。为了使其起作用,您需要考虑任何大小的数字。使用此处实现的模式,您可以:    'def float_of_2_decimal(float_n)         num = float_n.to_s.split('.')         num[1] = num[1][0..1]         num.join(".").to_f     end'或者更简单的方法是使用float_n.to_d.round(2,:truncate).to_f - rorykoehler
谢谢你的建议。但是,你提出的方法在大数上也失败了! - Anwar
对于输入 11111111111111111.222222222222222,第一个显示 1.11,第二个显示 1.11111111111111e+16 - Anwar
1
是的,你说得对...一旦超过16位,就会出现溢出问题。如果处理大数字,最好使用BigDecimal。类型转换会引入问题。 - rorykoehler
1
@rorykoehler 我尝试了你的方法并得到了这个结果:'111111111111111111111111.222222'.to_d.round(2, :truncate).to_f 返回 1.1111111111111111e+23。但如果你移除最后一个 .to_f,它就可以正常工作。 - lacostenycoder
显示剩余3条评论

-7

试试这个:

module Util
module MyUtil



    def self.redondear_up(suma,cantidad, decimales=0)

        unless suma.present?
            return nil
        end


        if suma>0
            resultado= (suma.to_f/cantidad)
            return resultado.round(decimales)
        end


        return nil


    end

end 
end 

3
谢谢回答。您能否请将它修改为英语,因为问题是用英语提出的。 - Jared

-18

为了截断小数,我使用了以下代码:

<th><%#= sprintf("%0.01f",prom/total) %><!--1dec,aprox-->
    <% if prom == 0 or total == 0 %>
        N.E.
    <% else %>
        <%= Integer((prom/total).to_d*10)*0.1 %><!--1decimal,truncado-->
    <% end %>
        <%#= prom/total %>
</th>

如果您想截取两位小数,应该使用Integr(a*100)*0.01

5
在计算百分比时,绝对不应该这样做。这种截断的方法非常不妥,因为它会使你失去将数字正确四舍五入到小数点后两位的能力。例如,如果你直接截断0.455,得到的结果是0.45,而这个结果不正确,因为如果要四舍五入应该得到0.46。所以千万不要截断小数,一定要四舍五入,否则结果就会在需要向上舍入时出错。 - The Gugaru

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接