SORU
5 HAZİRAN 2010, CUMARTESİ


Nasıl Haskell bu sayısal hesaplama performansını artırmak için?

Ben oldukça meşgulüm taşıma David Blei orijinal C implementation Gizli Öyle Tahsisi için Haskell, ve yapmaya karar verdim olsun bırakın bazı düşük seviyeli şeyler C. aşağıdaki işlevi bir örnek—bir yaklaşım, ikinci türevin lgamma:

double trigamma(double x)
{
    double p;
    int i;

    x=x 6;
    p=1/(x*x);
    p=(((((0.075757575757576*p-0.033333333333333)*p 0.0238095238095238)
         *p-0.033333333333333)*p 0.166666666666667)*p 1)/x 0.5*p;
    for (i=0; i<6 ;i  )
    {
        x=x-1;
        p=1/(x*x) p;
    }
    return(p);
}

Daha fazla veya daha az deyimsel aşağıdaki gibidir: Haskell içine bu tercüme ettim

trigamma :: Double -> Double
trigamma x = snd $ last $ take 7 $ iterate next (x' - 1, p')
  where
    x' = x   6
    p  = 1 / x' ^ 2
    p' = p / 2   c / x'
    c  = foldr1 (\a b -> (a   b * p)) [1, 1/6, -1/30, 1/42, -1/30, 5/66]
    next (x, p) = (x - 1, 1 / x ^ 2   p)

Sorun çalıştırdığımda her iki Criterion Haskell benim sürüm üzerinden altı veya yedi kat daha yavaş (DZD 6.12.1 -O2 hazırlıyorum). Bazı benzer işlevleri daha da kötü.

Haskell performansı hakkında neredeyse hiçbir şey bilmiyorum, ve her zaman sadece FFI ile matematik yoğun bir avuç C fonksiyonları arayabilirim beri çok digging through Core ya da böyle bir şey ile ilgilenen, ben değilim.

Ama ben merak edip orada kolay lokma olduğumu kayıp bir tür uzantısı ya da Kütüphane ya da açıklama bu olabilir hızlandırın bu sayısal şeyler olmadan yapmak çok çirkin.


GÜNCELLEME:Burada iki daha iyi çözümler, Don Stewart sayesinde Yitz. Biraz Yitz cevap Data.Vector kullanmak için modifiye ettim.

invSq x = 1 / (x * x)
computeP x = (((((5/66*p-1/30)*p 1/42)*p-1/30)*p 1/6)*p 1)/x 0.5*p
  where p = invSq x

trigamma_d :: Double -> Double
trigamma_d x = go 0 (x   5) $ computeP $ x   6
  where
    go :: Int -> Double -> Double -> Double
    go !i !x !p
        | i >= 6    = p
        | otherwise = go (i 1) (x-1) (1 / (x*x)   p)

trigamma_y :: Double -> Double
trigamma_y x = V.foldl' ( ) (computeP $ x   6) $ V.map invSq $ V.enumFromN x 6

İkisinin performansı aynı neredeyse, bir veya diğer puan veya iki derleyici bayrakları bağlı olarak kazanmış gibi görünüyor.

camccann over at Reddit bu hikayenin ana fikri "en iyi sonuç İçin, DZD arka uç kod jeneratör." olarak Don Stewart kullanmak olduğunu söyledi Bu çözüm engelleme, güvenli bahis loop fusion daha deyimsel bir tarzda benzer performans verebilir ancak C kontrol yapılarını doğrudan Haskell çevirmek için sadece görünüyor.

Muhtemelen benim kod Data.Vector yaklaşım kullanarak sonuna kadar veririm.

CEVAP
5 HAZİRAN 2010, CUMARTESİ


Aynı kontrol ve veri yapıları kullanmak, verimli:

{-# LANGUAGE BangPatterns #-}
{-# OPTIONS_GHC -fvia-C -optc-O3 -fexcess-precision -optc-march=native #-}

{-# INLINE trigamma #-}
trigamma :: Double -> Double
trigamma x = go 0 (x' - 1) p'
    where
        x' = x   6
        p  = 1 / (x' * x')

        p' =(((((0.075757575757576*p-0.033333333333333)*p 0.0238095238095238)
                  *p-0.033333333333333)*p 0.166666666666667)*p 1)/x' 0.5*p

        go :: Int -> Double -> Double -> Double
        go !i !x !p
            | i >= 6    = p
            | otherwise = go (i 1) (x-1) (1 / (x*x)   p)

Senin testsuite yok, ama bu aşağıdaki kanamayla verir:

A_zdwgo_info:
        cmpq    $5, %r14
        jg      .L3
        movsd   .LC0(%rip), %xmm7
        movapd  %xmm5, %xmm8
        movapd  %xmm7, %xmm9
        mulsd   %xmm5, %xmm8
        leaq    1(%r14), %r14
        divsd   %xmm8, %xmm9
        subsd   %xmm7, %xmm5
        addsd   %xmm9, %xmm6
        jmp     A_zdwgo_info

Tamam görünüyor. Bu -fllvm arka uç iyi bir iş yok kod türüdür.

GCC ya da Şablon Haskell veya manuel çözümü ile de döngü unrolls ve yapmanın tek yolu. Eğer bu bir sürü yapıyor eğer o (TH makro) düşünebilirsiniz.

Aslında, DZD LLVM arka uç döngü göz önüne sermek yapar :-)

Eğer gerçekten orijinal Haskell versiyonu gibi son olarak, eğer, stream fusion combinators, kullanarak yazma ve DZD geri döngü haline dönüştürür. (Okuyucu için bir egzersiz).

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Mega64

    Mega64

    24 ŞUBAT 2006
  • Paste Magazine

    Paste Magazi

    28 AĞUSTOS 2008
  • Rayone GB

    Rayone GB

    14 Temmuz 2007