Julia 中的精确十进制算术
Exact decimal arithmetic in Julia
由于 the nature of floating-point math,.4 * .4
= 0.16000000000000003
在 Julia 中。我想以 CPU 高效的方式获得 0.16
的数学正确答案。我知道 round() 有效,但这需要事先知道答案占用的小数位数,因此它不是通用解决方案。
部分选项:
使用内置的 Rational
类型。最准确和最快的方法是
16//100 * 16//100
如果您使用的数字非常大,这些数字可能会溢出,在这种情况下,您可以改用 BigInt
s,
big(16)//big(100) * big(16)//big(100)
(您实际上不需要将它们全部包装在 big
中,因为有理数会自动提升)。
您也可以使用 rationalize(0.16)
,但这可能不那么准确或高效,因为当 Julia 看到时文字 0.16
已经转换为 Float64
它,所以你要转换为二进制浮点数,然后转换为 Rational
.
DecFP.jl wraps the Intel implementation of IEEE-754 十进制浮点数。这应该相当快(虽然不如二进制有效),但具有固定精度,因此您将不得不在某些时候舍入。
Decimals.jl 是一个 "big decimal" 浮点库:因为它使用任意精度算法,它会比 DecFP 慢。
要说哪个最好,需要更多关于您的预期用途的信息。
您可以将 Python 的 decimal.Decimal
与 PyCall
一起使用,但效率将受到 Python 的限制
导入包:
julia> using PyCall
julia> @pyimport decimal
julia> const Dec = decimal.Decimal
PyObject <class 'decimal.Decimal'>
元定义操作(我认为所有这些类型的定义都应该是 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
和他们一起做一些数学运算:
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')
得到结果:
julia> y[:to_eng_string]() |> float
0.4
由于 the nature of floating-point math,.4 * .4
= 0.16000000000000003
在 Julia 中。我想以 CPU 高效的方式获得 0.16
的数学正确答案。我知道 round() 有效,但这需要事先知道答案占用的小数位数,因此它不是通用解决方案。
部分选项:
使用内置的
Rational
类型。最准确和最快的方法是16//100 * 16//100
如果您使用的数字非常大,这些数字可能会溢出,在这种情况下,您可以改用 BigInt
s,
big(16)//big(100) * big(16)//big(100)
(您实际上不需要将它们全部包装在 big
中,因为有理数会自动提升)。
您也可以使用 rationalize(0.16)
,但这可能不那么准确或高效,因为当 Julia 看到时文字 0.16
已经转换为 Float64
它,所以你要转换为二进制浮点数,然后转换为 Rational
.
DecFP.jl wraps the Intel implementation of IEEE-754 十进制浮点数。这应该相当快(虽然不如二进制有效),但具有固定精度,因此您将不得不在某些时候舍入。
Decimals.jl 是一个 "big decimal" 浮点库:因为它使用任意精度算法,它会比 DecFP 慢。
要说哪个最好,需要更多关于您的预期用途的信息。
您可以将 Python 的 decimal.Decimal
与 PyCall
一起使用,但效率将受到 Python 的限制
导入包:
julia> using PyCall
julia> @pyimport decimal
julia> const Dec = decimal.Decimal
PyObject <class 'decimal.Decimal'>
元定义操作(我认为所有这些类型的定义都应该是 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
和他们一起做一些数学运算:
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')
得到结果:
julia> y[:to_eng_string]() |> float
0.4