在 Ruby 中将美分转换为美元字符串,而不使用 BigDecimal

发布于 2024-12-05 02:38:20 字数 349 浏览 1 评论 0原文

我想在 Ruby 中正确地将美分转换为美元。我永远不需要用零头的钱来工作。

是否可以在不使用 BigDecimal 的情况下正确执行此操作(没有浮点错误)?

例如,美分换算美元

"99" => "0.99"
"324" => "3.24"

以下似乎可行,但它正确吗?

(cents.to_i/100.0).to_s

更新:我注意到如果 cents = "10287349283923497624861294712974892742837833",上面的行不起作用。

I want to convert from cents to dollars correctly in Ruby. I will never have to work with fractions of cents.

Is it possible to do this correctly (without floating point errors) without having to use BigDecimal?

E.g., cents to dollars

"99" => "0.99"
"324" => "3.24"

The following seems to work, but is it correct?

(cents.to_i/100.0).to_s

Update: I noticed the line above doesn't work if cents = "10287349283923497624861294712974892742837833".

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

酷炫老祖宗 2024-12-12 02:38:20

Micheal Kohl 已经回答了:看看金钱宝石。

例子:

require 'money'
Money.use_i18n = false  #https://stackoverflow.com/q/31133229/676874
puts Money.new( 99, 'USD')
puts Money.new(324, 'USD')

以下内容似乎可行,但正确吗?

<前><代码>(cents.to_i/100.0).to_s

乍一看,没问题,但是:

cents = '10'
p (cents.to_i/100.0).to_s # -> '0.1'

你没有 2 位数字。

选择:

p '%.2f' % (cents.to_i/100.0) # -> '0.10'

As Micheal Kohl already answered: Take a look to the money gem.

Example:

require 'money'
Money.use_i18n = false  #https://stackoverflow.com/q/31133229/676874
puts Money.new( 99, 'USD')
puts Money.new(324, 'USD')

The following seems to work, but is it correct?

(cents.to_i/100.0).to_s

On the first look, it is ok, but:

cents = '10'
p (cents.to_i/100.0).to_s # -> '0.1'

You don't have 2 digits.

Alternative:

p '%.2f' % (cents.to_i/100.0) # -> '0.10'
温柔一刀 2024-12-12 02:38:20

您也可以考虑使用有理数。但是,我不确定它们在 sprintf 编辑时是否会转换为浮点数:

"%.2f" % Rational("324".to_i,100)
#=> "3.24"
"%.2f" % Rational("99".to_i,100)
#=> "0.99"
"%.2f" % Rational("80".to_i,100)
#=> "0.80"
"%.2f" % Rational("12380".to_i,100)
#=> "123.80"

You can consider using Rationals as well. However, I am not sure do they get converted to floats when sprintf-ed:

"%.2f" % Rational("324".to_i,100)
#=> "3.24"
"%.2f" % Rational("99".to_i,100)
#=> "0.99"
"%.2f" % Rational("80".to_i,100)
#=> "0.80"
"%.2f" % Rational("12380".to_i,100)
#=> "123.80"
三岁铭 2024-12-12 02:38:20

如果它们已经是刺痛,你可以使用字符串操作并完全绕过数字问题:

# There are, of course, all sorts of ways to do this.
def add_decimal(s)
  pfx = [ '0.00', '0.0', '0.' ]
  if(pfx[s.length])
    s = pfx[s.length] + s
  else
    s = s.dup
    s[-2, 0] = '.'
  end
  s
end

add_decimal('')      #   "0.00" 
add_decimal('1')     #   "0.01" 
add_decimal('12')    #   "0.12" 
add_decimal('123')   #   "1.23" 
add_decimal('1234')  #  "12.34" 
add_decimal('12345') # "123.45"

没有精度问题,没有浮点,没有bignums,没有Rational,没有什么棘手的,没有什么聪明的。需要进行一些简单的修改来处理负值,但这将与已有的一样简单。

If they're stings already you could use string manipulation and bypass the numeric problems completely:

# There are, of course, all sorts of ways to do this.
def add_decimal(s)
  pfx = [ '0.00', '0.0', '0.' ]
  if(pfx[s.length])
    s = pfx[s.length] + s
  else
    s = s.dup
    s[-2, 0] = '.'
  end
  s
end

add_decimal('')      #   "0.00" 
add_decimal('1')     #   "0.01" 
add_decimal('12')    #   "0.12" 
add_decimal('123')   #   "1.23" 
add_decimal('1234')  #  "12.34" 
add_decimal('12345') # "123.45"

No precision issues, no floating point, no bignums, no Rational, nothing tricky, nothing clever. Some simple modifications would be needed to deal with negative values but that will be as simple as what's already there.

多彩岁月 2024-12-12 02:38:20

就我个人而言,我不会尝试重新发明这个特定的轮子并使用 金钱宝石。来自文档(添加了重点):

特点

提供一个 Money 类,它封装了有关某个货币的所有信息
一定数量的货币,例如其价值和货币。

提供 Money::Currency 类,其中封装了有关货币的所有信息
货币单位。

将货币值表示为整数(以美分为单位)。这
避免浮点舍入错误。

将货币表示为
Money::Currency 实例提供高度的灵活性。

提供用于将货币从一种货币兑换成另一种货币的 API。


将货币和货币字符串解析为
相应的货币/货币对象。

Personally I wouldn't try to re-invent this specific wheel and go with the money gem. From the docs (emphasis added):

Features

Provides a Money class which encapsulates all information about an
certain amount of money, such as its value and its currency.

Provides a Money::Currency class which encapsulates all information about a
monetary unit.

Represents monetary values as integers, in cents. This
avoids floating point rounding errors.

Represents currency as
Money::Currency instances providing an high level of flexibility.

Provides APIs for exchanging money from one currency to another.

Has
the ability to parse a money and currency strings into the
corresponding Money/Currency object.

嘴硬脾气大 2024-12-12 02:38:20

这是一种单行方法,也简单地使用字符串操作,从而完全绕过数字问题:

cents.rjust(3, "0").insert(-3, ".")

Here's a one-line method that also simply uses string manipulation thereby completely bypassing the numeric issues:

cents.rjust(3, "0").insert(-3, ".")
凹づ凸ル 2024-12-12 02:38:20

这些答案相当古老,所以我希望下一个人知道有一种更简单的方法(如果您使用的是 Rails)。

ActiveSupport::NumberHelper.number_to_currency(111048.fdiv(100))

有货币和精度选项。请参阅 Rails 文档

These answers are fairly old, so I wanted the next person to know there's an easier way (if you're using Rails).

ActiveSupport::NumberHelper.number_to_currency(111048.fdiv(100))

There's currency and precision options. See Rails documentation

怼怹恏 2024-12-12 02:38:20

您可以使用 fdiv 来实现此目的。它返回两个数字相除后的浮点结果

-> price.to_i.fdiv(100)

例如:'123'.to_i.fdiv(100) -> 1.23

You can use fdiv for this purpose. It returns the floating point result after division of two numbers

-> price.to_i.fdiv(100)

For example: '123'.to_i.fdiv(100) -> 1.23

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文