在我的应用中,需要预先计算并保持某些特定角度参数的三角函数值,范围在-90到180度之间变化。 我可以创建数组(每个正弦,cos等一个),它将在第0个索引上存储-90角度的值,而在检索时我可以从索引中减去90.
但是如果我们想要使用[-90 .. 180],还有其他方法在F#中指定索引范围 这样我就可以有更有意义的实施。
考虑到替代解决方案,字典的使用与使用简单的2D数组一样快。
答案 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
。
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