2015-05-15 19 views
6

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

+1

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. –

+2

"Qual è il modo meno intensivo per la cpu" - perché ti preoccupi delle prestazioni anche se non avevi ancora la correttezza? –

+6

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. –

risposta

9

Alcune opzioni:

  1. Utilizzare la Rational tipo integrato. Il modo più preciso e veloce sarebbe

    16 // 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.

  1. 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.

  2. 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.

+0

Nota che DecFP.jl è anche * più veloce * di usare il tipo BigFloat incorporato (a causa dell'immissione di immutabili) –

0

È 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 
+1

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! –