Exact decimal arithmetic in Julia

五迷三道 提交于 2019-12-01 04:03:14
Simon Byrne

Some options:

  1. Use the inbuilt Rational type. The most accurate and fastest way would be

    16//100 * 16//100

If you're using very big numbers these might overflow, in which case you can use BigInts instead,

big(16)//big(100) * big(16)//big(100)

(you don't actually need to wrap them all in bigs, as the rationals will promote automatically).

You can also use rationalize(0.16), but this may not be quite as accurate or efficient, as the literal 0.16 has already been converted to a Float64 by the time Julia sees it, so you're converting to a binary floating point and then to a Rational.

  1. DecFP.jl wraps the Intel implementation of IEEE-754 Decimal floating point. This should be reasonably fast (though not as efficient as binary), but has fixed precision, so you will have to round at some point.

  2. Decimals.jl is a "big decimal" floating point library: as it uses arbitrary precision arithmetic, it is going to be slower than DecFP.

To say which is the best would require more information about your intended use.

You can use Python's decimal.Decimal with PyCall, but efficiency is going to be Python bound

Import the package:

julia> using PyCall

julia> @pyimport decimal

julia> const Dec = decimal.Decimal
PyObject <class 'decimal.Decimal'>

Meta-define operations (I think all of these kind of definitions should be part of PyCall!):

julia> py_methods = Dict(
           :+ => :__add__,
           :* => :__mul__,
           :- => :__sub__,
           (:/) => :__truediv__
       )
Dict{Symbol,Symbol} with 4 entries:
  :/ => :__truediv__
  :+ => :__add__
  :* => :__mul__
  :- => :__sub__

julia> for (op, meth) in py_methods
           op = Expr(:quote, op)
           meth = Expr(:quote, meth)
           @eval Base.($op){T<:PyObject}(x::T, y::T) = x[$meth](y)
       end

Do some math with them:

julia> x = Dec("0.4")
PyObject Decimal('0.4')

julia> x * x
PyObject Decimal('0.16')

julia> x + x
PyObject Decimal('0.8')

julia> x - x
PyObject Decimal('0.0')

julia> x / x
PyObject Decimal('1')

julia> y = x + x * x / x - x
PyObject Decimal('0.4')

Get result:

julia> y[:to_eng_string]() |> float
0.4
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!