2015-05-15 15 views
6

Z powodu the nature of floating-point math, .4 * .4 = 0.16000000000000003 w Julia. Chcę uzyskać matematycznie poprawną odpowiedź 0.16, w sposób efektywny CPU. Wiem, że funkcja round() działa, ale wymaga to wcześniejszej znajomości liczby miejsc dziesiętnych odpowiedzi, więc nie jest to rozwiązanie ogólne.Dokładna arytmetyka dziesiętna w Julia

+1

matematyki zmiennoprzecinkowej został rozwiązany. Fakt, że ten konkretny przypadek został spowodowany przez te problemy, może być odpowiedzią, której szukał OP. Druga (jak uzyskać poprawną odpowiedź w Julii) wydaje się prawidłowa ... Nie jest jednak związany z używaniem zmiennoprzecinkowych. –

+2

"Jaki jest najgorszy sposób działania procesora" - dlaczego nawet nie zależy Ci na wydajności, skoro jeszcze nie masz jeszcze poprawności? –

+6

Rozsądną opcją w Julii jest racjonalna arytmetyka: '4 // 10 * 4 // 10' ->' 4 // 25', a wynik 'float (4 // 25)' jest rzeczywiście najbliższą liczbą zmiennoprzecinkową do 0,16. –

Odpowiedz

9

Niektóre opcje:

  1. pomocą wbudowanego Rational typu. Najdokładniejszym i najszybszym sposobem byłoby

    16 // 100 * 16 // 100

Jeśli używasz bardzo duże cyfry te mogą przelewem, w którym to przypadku można użyć zamiast BigInt s,

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

(w rzeczywistości nie trzeba owinąć je wszystkie w big s, jak rationals promować będzie automatycznie).

Można również użyć rationalize(0.16), ale to może nie być tak dokładne i skuteczne, jak dosłowne 0.16 został już przekształcony w Float64 przez czas Julia widzi, więc jesteś konwersja do binarnego zmiennoprzecinkowe następnie do Rational.

  1. owija realizację Intel z IEEE-754 dziesiętny zmiennoprzecinkowych. Powinno to być dość szybkie (choć nie tak wydajne jak binarne), ale ma stałą precyzję, więc będziesz musiał zaokrąglić w pewnym momencie.

  2. Decimals.jl jest biblioteką zmiennoprzecinkową "duża liczba dziesiętna": ponieważ wykorzystuje arytmetykę arytmetyki precyzyjnej, będzie wolniejsza niż DecFP.

Aby powiedzieć, który jest najlepszy, należy uzyskać więcej informacji o jego zamierzonym zastosowaniu.

+0

Zauważ, że DecFP.jl jest również * szybszy * niż przy użyciu wbudowanego typu BigFloat (z powodu używania niezmiennych) –

0

Można używać Pythona decimal.Decimal z PyCall, ale wydajność będzie Python związany

importu pakietu:

julia> using PyCall 

julia> @pyimport decimal 

julia> const Dec = decimal.Decimal 
PyObject <class 'decimal.Decimal'> 

Meta-zdefiniowania operacji (myślę, że wszystkie tego rodzaju definicji powinien być część 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 

Czy jakieś matematyki z nich:

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') 

uzyskać wynik:

julia> y[:to_eng_string]() |> float 
0.4 
+1

Przepraszam, ale nie przyniósłbym całego Pythona tylko po to, by rozwiązać ten problem, gdy pakiet DecFP.jl Steven Johnson'a działa bardzo dobrze, nie dodaje wiele do Julii i jest jeszcze szybszy niż w BigFloat! –