Follow

technical, a simple fast cosine

hi i just made a simple thing for when you need something that looks like a cosine but doesn't have to be super accurate. it's still kind of expensive (four multiplies), but otoh it's actually pretty close to a real cosine.

this is a by-product of when i optimized a magnetic field implementation for uni, which included a cosine. i learnt how to make this fast from naoki shibata's sleef library, though the rounding trick is mine c:

you can find my (hopefully well-explained) code here: https://github.com/antoniusf/CRPropa3/blob/fix-planewave-comments/src/magneticField/turbulentField/PlaneWaveTurbulence.cpp#L283

you could get a slightly more accurate result by tweaking the numbers a bit, but i like that they're so nice, so i'm keeping them.

also, this computes cos(2πx), instead of cos(x), meaning that it goes through a whole cycle in 1 unit instead of 2π units. this simplifies things.

round is a normal rounding function, i.e. rounds down for fractional parts < 0.5, and up for > 0.5.

cos(2πx):

reduced = x - round(x)

sq = reduced * reduced

((-64 * sq + 64) * sq - 20) * sq + 1

technical, a simple fast cosine

i then ran an optimization routine using this set of constraints. all of this was done in julia (the language), because it has a good package for global optimization, BlackBoxOptim.jl. i handed it my target function and let it do it's job, and then i just rounded the resulting values. look how nice they came out!

technical, a simple fast cosine

okay, so what about the round? i'm not sure how easy this is to explain without drawing it out on paper, but basically, we want to take the input value, and then map it to another value in [-0.5, 0.5]. this works because the cosine repeats, and all of the ranges [0.5, 1.5], [1.5, 2.5], etc., look exactly the same as the first one. round(x) always returns the center of the range that a certain value is in, so 1 for [0.5, 1.5], etc. so, doing x - round(x) gives the corresponding value in [-0.5, 0.5]. (you could think of this as shifting the range where our value is to the range around zero, where our polynomial approximation works.)

antonius@antoniusf@cybre.spacetechnical, a simple fast cosine

how does this work?

if you try plotting just the last line, you can see that between -0.5 and 0.5 it looks a lot like a cosine! (beyond that it gets very big very fast, but that's okay.)

this is by design. if you unravel that line a bit, you will get to a formula like this:

–64x⁶ + 64x⁴ – 20x² + 1

-> it's a polynomial approximation to the cosine! if you're not in physics (or math), you should know that formulas like this can be made to look like arbitrary functions, just by tweaking the numbers, at least if you don't zoom out to far.

to come up with these particular numbers, i set these constraints for my computer:

– cos(2π·0) should be 1.

– x = ±0.5 is where these approximations are joined together, and i want that to be smooth. mathematically, i enforce this by saying that the slope should be zero.

– i want things to look nice, so the parts above the y axis should be as similar as possible to the parts below.

that was all!