Exact decimal arithmetic in Julia

Due to the nature of floating point mathematics , .4 * .4 = 0.16000000000000003 in Julia. I want to get a mathematically correct answer of 0.16 in CPU efficient mode. I know round () works, but this requires a preliminary knowledge of the number of decimals the answer answers, so this is not a general solution.

+6
source share
2 answers

Some options:

  • Use the built-in Rational type. The most accurate and fastest way -

    16 // 100 * 16 // 100

If you use very large numbers, this can overflow, in which case you can use BigInt instead

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

(you actually do not need to wrap them all in big s, since rationality will automatically advance).

You can also use rationalize(0.16) , but it may not be as accurate or efficient, since literal 0.16 already converted to Float64 by the time Julia sees it, so you convert to binary floating point and then.

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

  2. Decimals.jl is a large decimal floating-point library: since it uses arbitrary precision arithmetic, it is going to be slower than DecFP.

To say which is best, you will need more information about your intended use.

+9
source

You can use Python decimal.Decimal with PyCall , but efficiency will be related to Python

Import the package:

 julia> using PyCall julia> @pyimport decimal julia> const Dec = decimal.Decimal PyObject <class 'decimal.Decimal'> 

Meta-definition operations (I think all of these 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 the 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 the result:

 julia> y[:to_eng_string]() |> float 0.4 
0
source

Source: https://habr.com/ru/post/987289/


All Articles