数组中的F#负索引

时间:2015-04-21 10:23:30

标签: arrays dictionary f#

在我的应用中,需要预先计算并保持某些特定角度参数的三角函数值,范围在-90到180度之间变化。 我可以创建数组(每个正弦,cos等一个),它将在第0个索引上存储-90角度的值,而在检索时我可以从索引中减去90.

但是如果我们想要使用[-90 .. 180],还有其他方法在F#中指定索引范围 这样我就可以有更有意义的实施。

考虑到替代解决方案,字典的使用与使用简单的2D数组一样快。

3 个答案:

答案 0 :(得分:2)

如果我理解你的问题,你需要通过键/索引检索预先计算的值,这是一个从-90到180的给定角度。这样的东西?

let value = precomputed.[-90]

您可以使用Map。 F#maps被实现为不可变的AVL树,这是一种形成自平衡二叉树的有效数据结构。如果您有预先计算的数据并且需要经常按键查找,这可能非常有效。在这种情况下,它的不变性确保了静态数据不会被错误地修改,并且对性能几乎没有影响,因为一旦初始化你就不需要改变它。但是,如果您需要经常修改它,我建议您使用常规的.NET Dictionary,因为它们基于散列表,其性能优于AVL树。

您可以将列表转换为键,其中键将是角度,值将是预先计算的值:

let precomputedValus f =
    [for i in -90..180 ->
            i, f(i)]
            |> Map.ofList

f是执行预计算的函数。因此,您可以获得类似的每个角度的预先计算的地图。

let sinValues = precomputedValus (fun e -> sin (float e))

你可以像那样访问procomputed sin值

> sinValues.[-90];;
val it : float = -0.8939966636

答案 1 :(得分:1)

将使用一点索引算法:

let inline idx i = (i + 270) % 270

因为它是inline,所以开销将非常非常小。你可以使用myArray.[idx -90]。 (你可能需要编写不同的模数值,但是你得到了图片)

答案 2 :(得分:0)

最简单的方法是简单地创建一些函数,让某些i返回预先计算的sin i值:

let array_table = 
  let a = Array.init 271 (fun i -> sin <| float (i-90))
  fun i -> a.[i+90]

要查找42的正弦值,您只需执行table 42

anushri和Tomasz都提到使用Maps而不是Arrays,但根据我的经验,这些并不适合存储预先计算的值,因为它们。我们试试吧:

let map_table = 
  let m = Seq.init 271 (fun i -> i-90, sin <| float i) |> Map.ofSeq
  fun i -> Map.find i m 

let no_table = 
  fun i -> sin (float i)

// Benchmarking code omitted (100000 lookups of each value in -90..270) 

运行时,array_table大约比no_table快8倍,比map_table快22倍:

> fsharpi --optimize+ memo.fsx 
map_table
Real: 00:00:02.922, CPU: 00:00:02.924, GC gen0: 4, gen1: 0
no_table
Real: 00:00:01.091, CPU: 00:00:01.091, GC gen0: 3, gen1: 0
array_table
Real: 00:00:00.130, CPU: 00:00:00.130, GC gen0: 3, gen1: 0