2017-07-19 81 views
2

我寫的點積函數,採用2所列出:點產品功能

let inline dot a b = 
    List.zip a b 
    |> List.map (fun (a, b) -> a * b) 
    |> List.reduce (+) 

是否有更好的方法來計算點積不使用List.zip

回答

6

一個較短的方式是使用List.map2

let inline dot a b = List.map2 (*) a b |> List.sum 

另一種是使用List.fold2

let inline dot a b = List.fold2 (fun state x y -> state + x * y) LanguagePrimitives.GenericZero a b 
+0

第二個函數中的'inline'不會幫助,因爲'0'強制它返回類型爲'int'。 – Soldalma

+0

如果'inline'使該函數具有通用性,那麼使用'LanguagePrimitives.GenericZero'而不是'0'就可以工作。如果它只是告訴編譯器「不要在這裏生成一個函數調用」,那麼它現在很好。 – rmunn

3

在這三個建議的人,我相信用List.fold2一個是最快的:

let inline dot1 a b = 
    List.zip a b 
    |> List.map (fun (a, b) -> a * b) 
    |> List.reduce (+) 

let inline dot2 a b = List.map2 (*) a b |> List.sum 

// Modified with 0.0 instead of 0 and no 'inline' 
let dot3 a b = List.fold2 (fun state x y -> state + x * y) 0.0 a b 

let xs = [0.0..1000000.0] 

> dot1 xs xs;; 
Real: 00:00:00.242, 

> dot2 xs xs;; 
Real: 00:00:00.070 

> dot3 xs xs;; 
Real: 00:00:00.003 

荏苒兩個列表可能是相當昂貴的。 map2-sum解決方案更快,但在列表中迭代兩次。 fold2解決方案只通過列表一次。

+0

爲什麼使用'0.0'而不是'LanguagePrimitives.GenericZero'來使'dot3'成爲一個通用函數?我beilive不強迫泛型可以使功能更快評估,對嗎? – MiP

+0

@MiP - 我不確定。我用'LanguagePrimitives.GenericZero'而不是'0.0'再次嘗試,速度沒有明顯變化。 – Soldalma