问题
Due to the nature of floating-point math, .4 * .4
= 0.16000000000000003
in Julia. I want to get the mathematically correct answer of 0.16
, in a CPU-efficient way. I know round() works, but that requires prior knowledge of the number of decimal places the answer occupies, so it isn't a general solution.
回答1:
Some options:
Use the inbuilt
Rational
type. The most accurate and fastest way would be16//100 * 16//100
If you're using very big numbers these might overflow, in which case you can use BigInt
s instead,
big(16)//big(100) * big(16)//big(100)
(you don't actually need to wrap them all in big
s, 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
.
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.
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.
回答2:
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
来源:https://stackoverflow.com/questions/30264742/exact-decimal-arithmetic-in-julia