如何在julia-lang中存储货币值并格式化其输出?

时间:2014-10-21 11:04:24

标签: julia

目前,我将货币金额存储在::Float64类型中,大量金额以数十亿到数百万不同的货币单位。在其他用例中,我还认为货币价值必须保持在数万单位的货币中,例如0.7564

但是,考虑到与双精度浮点数相关的舍入误差,我应该将所有内容转换为定点整数来存储货币单位吗?

其次,如何格式化货币单位的字符串输出,并允许显示相关的货币符号?

其次,他们的任何套餐都提供了"货币"可以安全使用的数据类型?

3 个答案:

答案 0 :(得分:4)

这是存储货币并显示货币的真正基本起点:

immutable Currency
  symbol::Symbol
  amount::Int
end

function Base.show(io::IO, c::Currency)
  print(io, c.symbol, c.amount/100)
end

Currency(:£, 1275) #=> £12.75

这将货币存储为便士的精确值,因此没有舍入错误,但以通常的方式显示。您当然可以轻松地对要存储的小数位数进行参数化。我不能回答你是否应该使用这样的定点数,但它们对加法,减法和乘法肯定更准确。

至于现有技术,快速谷歌“currency.jl”出现了this - 它看起来已过时但可能有用作参考。

答案 1 :(得分:2)

您绝对不应该为货币使用浮点数 - 您应该定义自己的定点数字类型,然后使用它。 Julia手册有一个很好的教程,关于在转换和促销的章节中定义一个新的数字类型。

让我们假设你只需要小数点后的两位数 - 不要介意英镑,先令和便士。您的新类型看起来像

immutable Monetary <: Number
    hundredths :: Int64
end

Monetary(ones :: Int64, hundredths :: Int64) = Monetary(hundredths + 100 * ones)

显然,您希望能够显示货币坐额:

Base.show(io :: IO, x :: Monetary) =
    @printf(io, "%lld.%02lld", fld(x.hundredths, 100), mod(x.hundredths, 100))

您还希望能够添加和减去它们:

+(x :: Monetary, y :: Monetary) = Monetary(x.hundredths + y.hundredths)
-(x :: Monetary, y :: Monetary) = Monetary(x.hundredths - y.hundredths)

另一方面,你永远不会想要乘以它们 - 但将货币总和乘以整数是正常的:

*(x :: Bool, y :: Monetary) = ifelse(x, y, Monetary(0))
*(x :: Monetary, y :: Bool) = ifelse(y, x, Monetary(0))
*(x :: Integer, y :: Monetary) = Monetary(x * y.hundredths)
*(x :: Monetary, y :: Integer) = Monetary(x.hundredths * y)

最后,如果在表达式中将整数与货币总和混合在一起,可以将所有内容转换为货币值:

Base.convert(::Type{Monetary}, x :: Int64) = Monetary(x, 0)
Base.promote_rule(::Type{Monetary}, ::Type{Int64}) = Monetary

这足以执行有用的计算:

julia> Scrooge.Monetary(30,5) * 3 + 12
102.15

但会可靠地捕捉到不正确的操作:

julia> Scrooge.Monetary(30,5) * 3.5
ERROR: no promotion exists for Monetary and Float64
 in * at ./promotion.jl:159

答案 2 :(得分:1)

Currencies.jl提供了使用货币的界面:

using Currencies
@usingcurrencies USD
format(1.23USD + 4.56USD, styles=[:us, :brief])  # $5.79

它支持类型安全算术,货币转换和灵活的漂亮打印。

免责声明:我是Currencies.jl的维护者。