A causa di the nature of floating-point math, .4 * .4
= 0.16000000000000003
in Julia. Voglio ottenere la risposta matematicamente corretta di 0.16
, in modo efficiente per la CPU. So che round() funziona, ma ciò richiede una conoscenza preliminare del numero di cifre decimali che occupa la risposta, quindi non è una soluzione generale.Aritmetica decimale esatta in Julia
risposta
Alcune opzioni:
Utilizzare la
Rational
tipo integrato. Il modo più preciso e veloce sarebbe16 // 100 * 16 // 100
Se stai usando numeri molto grandi questi potrebbero traboccare, nel qual caso è possibile utilizzare BigInt
s, invece,
big(16)//big(100) * big(16)//big(100)
(che in realtà non c'è bisogno di metterli tutti in big
s, in quanto i numeri razionali promuoveranno automaticamente).
È inoltre possibile utilizzare rationalize(0.16)
, ma questo potrebbe non essere così preciso ed efficiente, come il letterale 0.16
è già stato convertito in una Float64
per il momento Julia vede, così si sta convertendo a un binario in virgola mobile e quindi a Rational
.
avvolge l'attuazione di Intel di IEEE-754 decimale in virgola mobile. Questo dovrebbe essere ragionevolmente veloce (anche se non efficiente come binario), ma ha una precisione fissa, quindi dovrai arrotondare ad un certo punto.
Decimals.jl è una libreria a virgola mobile "grande decimale": poiché utilizza aritmetica di precisione arbitraria, sarà più lenta di DecFP.
Per dire quale è il migliore richiederebbe maggiori informazioni sull'uso previsto.
Nota che DecFP.jl è anche * più veloce * di usare il tipo BigFloat incorporato (a causa dell'immissione di immutabili) –
È possibile utilizzare di decimal.Decimal
con PyCall
Python, ma l'efficienza sarà Python legato
Importa il pacchetto:
julia> using PyCall
julia> @pyimport decimal
julia> const Dec = decimal.Decimal
PyObject <class 'decimal.Decimal'>
operazioni Meta-define (credo che tutti questi tipi di definizioni dovrebbero essere parte di 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
fare qualche calcolo con loro:
0.123.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')
risultato Get:
julia> y[:to_eng_string]() |> float
0.4
Scusa, ma non porterei tutto Python solo per risolvere questo problema, quando il pacchetto DecFP.jl di Steven Johnson funziona molto bene, non aggiunge molto overhead a Julia, ed è ancora più veloce di usare BigFloat! –
calcoli in virgola mobile è stato affrontato. Il fatto che questo caso specifico sia stato causato da questi problemi potrebbe essere la risposta che l'OP stava cercando. La seconda (come ottenere una risposta corretta in Julia) sembra legittima ... Non è affatto legato all'utilizzo di virgola mobile. –
"Qual è il modo meno intensivo per la cpu" - perché ti preoccupi delle prestazioni anche se non avevi ancora la correttezza? –
Un'opzione ragionevole in Julia è l'aritmetica razionale: '4 // 10 * 4 // 10' ->' 4 // 25', e il risultato di 'float (4 // 25)' è in effetti il numero a virgola mobile più vicino a 0,16. –