Reputation: 67
In my application there is a need to precompute and keep trigonometric function values for some particular angle parameters, the range varies from -90 to 180 degree. I can create arrays(one for each sine, cos etc) which will store value for -90 angle on 0th index and while retrieving I can subtract 90 from the index.
but is there any other way in F# to specify range of index, if we want to use [-90 .. 180] so that I can have more meaningful implementation.
considering alternate solution, will usage of dictionary be as fast as usage of simple 2D arrays.
Upvotes: 2
Views: 319
Reputation: 5688
The easiest way is to simply make some function which given some i
returns a pre-computed value of sin i
:
let array_table =
let a = Array.init 271 (fun i -> sin <| float (i-90))
fun i -> a.[i+90]
To lookup the sine of, say, 42, you simply do table 42
.
anushri and Tomasz both mention using Maps instead of Arrays, but in my experience, these are not good candidates for storing precomputed values, as they are much slower than Arrays. Let's try:
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)
When I run this, array_table
is roughly 8 times faster than no_table
and 22 times faster than map_table
:
> 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
Upvotes: 0
Reputation: 16033
If I understand well your problem you would need to retrieve precomputed values by the key/index which is a given angle going from -90 to 180. Something like this ?
let value = precomputed.[-90]
You could use Map
for that. F# maps are implemented as immutable AVL trees, an efficient data structure which forms a self-balancing binary tree. This can be very efficient if you have a precomputed data and you need to look up by key frequently. Its immutability in this case ensures that the static data cannot be modified by mistake and has little impact to performance as you never need to mutate it once initialized. However if you need to modify it frequently I would advice you to use a regular .NET Dictionary because they are based on hashtable which has a better performance than AVL trees.
You could turn the list into the map where the key would be the angle and the value would be the precomputed one :
let precomputedValus f =
[for i in -90..180 ->
i, f(i)]
|> Map.ofList
Where f
is the function doing the precomputation. So you obtain your precomputed map for every angle something like that.
let sinValues = precomputedValus (fun e -> sin (float e))
And you can access the procomputed sin value like that
> sinValues.[-90];;
val it : float = -0.8939966636
Upvotes: 2
Reputation: 3838
A little index arithmetic will be of use:
let inline idx i = (i + 270) % 270
since it's inline
the overhead is going to be very, very small. And you can just use myArray.[idx -90]
. (you might have to write different modulo values, but you get the picture)
Upvotes: 1