目前,我将货币金额存储在::Float64
类型中,大量金额以数十亿到数百万不同的货币单位。在其他用例中,我还认为货币价值必须保持在数万单位的货币中,例如0.7564
但是,考虑到与双精度浮点数相关的舍入误差,我应该将所有内容转换为定点整数来存储货币单位吗?
其次,如何格式化货币单位的字符串输出,并允许显示相关的货币符号?
其次,他们的任何套餐都提供了"货币"可以安全使用的数据类型?
答案 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的维护者。