Arrays 数组中的F#负指数
在我的应用程序中,需要预先计算并保留某些特定角度参数的三角函数值,范围从-90度到180度不等。 我可以创建数组(每个正弦、cos等一个),它将在第0个索引上存储-90角度的值,在检索时,我可以从索引中减去90 但是如果我们想使用[-90..180],在F#中有没有其他方法来指定索引的范围 这样我就可以有更有意义的实现Arrays 数组中的F#负指数,arrays,dictionary,f#,Arrays,Dictionary,F#,在我的应用程序中,需要预先计算并保留某些特定角度参数的三角函数值,范围从-90度到180度不等。 我可以创建数组(每个正弦、cos等一个),它将在第0个索引上存储-90角度的值,在检索时,我可以从索引中减去90 但是如果我们想使用[-90..180],在F#中有没有其他方法来指定索引的范围 这样我就可以有更有意义的实现 考虑替代解决方案,字典的使用速度是否与简单2D数组的使用速度一样快。可以使用一些索引算法: let inline idx i = (i + 270) % 270 因为它是内联的
考虑替代解决方案,字典的使用速度是否与简单2D数组的使用速度一样快。可以使用一些索引算法:
let inline idx i = (i + 270) % 270
因为它是内联的,所以开销非常非常小。您只需使用myArray.[idx-90]。(你可能需要写不同的模值,但你明白了)如果我很理解你的问题,你需要通过键/索引检索预先计算的值,键/索引是一个从-90到180的给定角度。像这样的
let value = precomputed.[-90]
您可以使用Map
来实现这一点。F#映射实现为不可变AVL树,这是一种形成自平衡二叉树的高效数据结构。如果您有一个预计算的数据,并且需要频繁地按键查找,那么这将非常有效。在这种情况下,它的不可更改性确保了静态数据不会被误取修改,并且对性能有轻微影响,因为一旦初始化,您就不需要对其进行变异。但是,如果您需要经常修改它,我建议您使用常规的.NET字典,因为它们基于哈希表,比AVL树具有更好的性能
您可以将列表转换为地图,其中关键点为角度,值为预计算值:
let precomputedValus f =
[for i in -90..180 ->
i, f(i)]
|> Map.ofList
其中f
是进行预计算的函数。所以你可以得到每个角度的预计算地图
let sinValues = precomputedValus (fun e -> sin (float e))
您可以像这样访问程序计算的sin值
> sinValues.[-90];;
val it : float = -0.8939966636
最简单的方法是简单地生成一个函数,该函数在给定某个
i
的情况下返回一个预先计算的值sini
:
let array_table =
let a = Array.init 271 (fun i -> sin <| float (i-90))
fun i -> a.[i+90]
当我运行此命令时,array\u table
大约比no\u table
快8倍,比map\u 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
您的问题是定义一个从-90到180的范围,或者按键提取,比如
let value=precomputed.[-90]
yes我想提取给定角度的预计算值。让value=precomputed.[-90]通常(包括项
)可用于创建自定义索引器。但是如果程序的性能受到如此严格的限制,我不确定它们的开销。您确定标准三角函数是性能瓶颈吗?速度真的是问题吗?您是否在硬件上运行这些功能比较慢?我正在处理一个大规模的问题,由于严格的性能要求,我希望避免任何类型的处理延迟,这就是为什么我不想在运行时计算这些值,而是将它们存储在一个数组中,这样检索速度会非常快。我真的怀疑存储sin表是否会比计算快——计算速度非常快,您正在承受相当严重的缓存命中。请注意,在默认情况下,这将在小于-270的输入上失败%
操作员。(对于一个给定的用例来说,这可能是好的,也可能不是好的)值是不可变的,所以我认为不需要字典。我发现你给出的解决方案非常合适,谢谢…现在我想通过这个我可以比较性能并得出一些结论。是的,map将非常适合。问题要求以度为单位输入sin
接受弧度输入。另外,请注意,在典型的x86机器和应用程序上,这比直接计算慢一倍。(我刚刚做了一个粗略的测试运行,预计算导致速度大幅下降,低于原始速度的40%。当然,这可能取决于硬件、缓存、输入顺序的分支预测等)您可以使用任何需要的函数,而不是sin。这只是一个示例。在真实场景中评测应用程序时,应明确检查性能优化。这取决于实际计算函数的成本。所提到的问题与其说是性能问题,不如说是对问题的惯用看法,但这一点不应忽略。
> 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