2011-11-18 31 views
3

我在寫一個非常性能強勁的程序,並且一直在使用C,但有人告訴我函數式編程有多酷,所以我決定用F#重寫它。如何在F#中寫Duff的設備?

無論如何,我在F#中難以複製算法的特定函數是Duff's device。它不是典型的迭代,而是展開循環,以便每次迭代可以複製8個字節,而不是一個。

void copy_memory(char* to, char* from, size_t count) { 
    size_t n = (count+7)/8; 
    switch(count%8) { 
    case 0: do{ *to++ = *from++; 
    case 7:  *to++ = *from++; 
    case 6:  *to++ = *from++; 
    case 5:  *to++ = *from++; 
    case 4:  *to++ = *from++; 
    case 3:  *to++ = *from++; 
    case 2:  *to++ = *from++; 
    case 1:  *to++ = *from++; 
      }while(--n>0); 
    } 
} 

這種利用情況下通,並跳轉至C,其中,據我所知,是不幸的特點是F#似乎缺少一個循環的中間的能力。

我讀了一些MSDN上的東西,並認爲F#的match功能將是我可以最接近C的switch。所以,我開始寫這段代碼

open System.Reflection 
let copyMemory (pTo : Pointer) (pFrom : Pointer) length = 
    let n = (length + 7)/8 
    match n % 8 with 
    | 0 -> 

然後我無法弄清楚該怎麼做。它不會讓我在這裏開始一個循環,並在另一個案例中結束它。

F#中有什麼東西可以用來做案例轉場並跳到循環的中間嗎?如果你能爲我做到這一點,我想我可以自己找出其他的。

+0

祝你好運...我想你必須直接發出IL代碼;) – fmr

+3

Duff的設備在功能語言或任何現代編譯器中都沒有意義,因爲它們會優化像這樣給你,如果它是有道理的。 –

+0

我意識到我的第二個努力是越野車,所以我用更忠實的達夫的翻譯來代替它。 – Daniel

回答

7

這裏的撥弄在F#內存:-)

#nowarn "9" //stop telling me I'm going to break something 
open Microsoft.FSharp.NativeInterop 

let inline (~+) ptr = NativePtr.add ptr 1 

let rec copyMemory src dest = function 
    | 0 ->() 
    | n -> 
    NativePtr.read src |> NativePtr.write dest 
    copyMemory +src +dest (n - 1) 

的慣用方法,但是這可能是更多的精神達夫

let inline (+>) s d = 
    NativePtr.read !s |> NativePtr.write !d 
    s:= NativePtr.add !s 1 
    d:= NativePtr.add !d 1 

let copyMemory src dst count = 
    let n = ref ((count + 7)/8) 
    let s, d = ref src, ref dst 
    let 
    rec case_0() = s +> d; case_7() 
    and case_7() = s +> d; case_6() 
    and case_6() = s +> d; case_5() 
    and case_5() = s +> d; case_4() 
    and case_4() = s +> d; case_3() 
    and case_3() = s +> d; case_2() 
    and case_2() = s +> d; case_1() 
    and case_1() = s +> d; decr n; if !n > 0 then case_0() 
    match count % 8 with 
    | 7 -> case_7() | 6 -> case_6() 
    | 5 -> case_5() | 4 -> case_4() 
    | 3 -> case_3() | 2 -> case_2() 
    | 1 -> case_1() | _ -> case_0() 

但嚴重

System.Buffer.BlockCopy(src, 0, dest, 0, count) 
2

有在F#中沒有標籤。然而,您可以另一種方式展開循環。

let copy (dst : nativeptr<byte>) (src : nativeptr<byte>) count = 
    let mutable s = src 
    let mutable d = dst 

    for n in 1 .. count/8 do 
     NativePtr.read s |> NativePtr.write d 
     s <- NativePtr.ofNativeInt(NativePtr.toNativeInt s + nativeint 1) 
     d <- NativePtr.ofNativeInt(NativePtr.toNativeInt d + nativeint 1) 
     NativePtr.read s |> NativePtr.write d 
     s <- NativePtr.ofNativeInt(NativePtr.toNativeInt s + nativeint 1) 
     d <- NativePtr.ofNativeInt(NativePtr.toNativeInt d + nativeint 1) 
     NativePtr.read s |> NativePtr.write d 
     s <- NativePtr.ofNativeInt(NativePtr.toNativeInt s + nativeint 1) 
     d <- NativePtr.ofNativeInt(NativePtr.toNativeInt d + nativeint 1) 
     NativePtr.read s |> NativePtr.write d 
     s <- NativePtr.ofNativeInt(NativePtr.toNativeInt s + nativeint 1) 
     d <- NativePtr.ofNativeInt(NativePtr.toNativeInt d + nativeint 1) 
     NativePtr.read s |> NativePtr.write d 
     s <- NativePtr.ofNativeInt(NativePtr.toNativeInt s + nativeint 1) 
     d <- NativePtr.ofNativeInt(NativePtr.toNativeInt d + nativeint 1) 
     NativePtr.read s |> NativePtr.write d 
     s <- NativePtr.ofNativeInt(NativePtr.toNativeInt s + nativeint 1) 
     d <- NativePtr.ofNativeInt(NativePtr.toNativeInt d + nativeint 1) 
     NativePtr.read s |> NativePtr.write d 
     s <- NativePtr.ofNativeInt(NativePtr.toNativeInt s + nativeint 1) 
     d <- NativePtr.ofNativeInt(NativePtr.toNativeInt d + nativeint 1) 
     NativePtr.read s |> NativePtr.write d 
     s <- NativePtr.ofNativeInt(NativePtr.toNativeInt s + nativeint 1) 
     d <- NativePtr.ofNativeInt(NativePtr.toNativeInt d + nativeint 1) 

    for n in 1 .. count % 8 do 
     NativePtr.read s |> NativePtr.write d 
     s <- NativePtr.ofNativeInt(NativePtr.toNativeInt s + nativeint 1) 
     d <- NativePtr.ofNativeInt(NativePtr.toNativeInt d + nativeint 1) 

相關提示,NativePtr.add將拜會nativeptr的sizeof所以我鑄造以上nativeint。