# Speeding up trig-heavy code

**URL:** <https://discourse.julialang.org/t/speeding-up-trig-heavy-code/134656>\
**Category:** Performance\
**Tags:** performance, trigonometry, nerdsnipe\
**Created:** [December 20, 2025, 11:13pm UTC](https://discourse.julialang.org/t/speeding-up-trig-heavy-code/134656 "2025-12-20T23:13:30Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![langestefan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/langestefan/32/207923_2.png) [@langestefan](https://discourse.julialang.org/u/langestefan)\
**Post date:** [December 20, 2025, 11:13pm UTC](https://discourse.julialang.org/t/speeding-up-trig-heavy-code/134656/1 "2025-12-20T23:13:30Z")

</div>

Hello!

I recently released v0.3.2 of SolarPosition.jl. I feel like it is now in a position where I am very happy with the performance, at least I think I covered all the basics like type stability covered in [Performance Tips · The Julia Language](https://docs.julialang.org/en/v1/manual/performance-tips/index.html#Consider-using-views-for-slices-1).

I benchmarked SolarPosition.jl against its python equivalent solposx, and found that we are usually between 10x-200x faster (singlethreaded) depending on input size and algorithm choice. PSA, which provides a great tradeoff between accuracy and computation time, is 200x faster than the python version. On top of that we can do multithreading, while the python version can’t (at least not trivially).

Here is a profiling view I created for [PSA](https://github.com/JuliaAstro/SolarPosition.jl/blob/main/src/Positioning/psa.jl):

 ![Screenshot_20251220_183756](https://global.discourse-cdn.com/julialang/original/3X/1/e/1e7917074f8806244182b8b8108fa0273ad4afd4.jpeg)

As you can see most time is lost computing trigonometry functions like `sin`, `cos`, `atan`.

This is mostly for my own curiosity, but is there even more to gain here? I experimented with `@fastmath`, but found that it breaks correctness in exchange for maybe 5-10% percent performance gain. I also experimented with static arrays, but found that it yielded no improvements.

If you want to try something, feel free to make a PR. The github bot will benchmark your changes against the main branch using AirspeedVelocity.jl so you immediately get feedback.

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [December 20, 2025, 11:21pm UTC](https://discourse.julialang.org/t/speeding-up-trig-heavy-code/134656/2 "2025-12-20T23:21:05Z")

</div>

Is it common to have just a single solar position you want to compute? At this point, it is possible that the single-threaded speedups are close to exhausted (although I wouldn’t underestimate the cleverness of people here) but setting up parallelized computations on GPUs would probably yield massive instant speedups

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [December 20, 2025, 11:22pm UTC](https://discourse.julialang.org/t/speeding-up-trig-heavy-code/134656/3 "2025-12-20T23:22:54Z")

</div>

> [@langestefan](#):
>
> This is mostly for my own curiosity, but is there even more to gain here?

You could try trigonometric functions in packages like SLEEF.jl

---

<div class="post-metadata">

**Author:** ![raman\_kumar](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raman_kumar/32/26782_2.png) [@raman\_kumar](https://discourse.julialang.org/u/raman_kumar)\
**Post date:** [December 20, 2025, 11:24pm UTC](https://discourse.julialang.org/t/speeding-up-trig-heavy-code/134656/4 "2025-12-20T23:24:42Z")

</div>

If your code is calculating trigonometric values of same angle then combinations like `sincos`and `sincosd` etc. can help improve performance.  
I think we should have better documentation of KernelAbstractions.jl. I am also looking for fast solution to my code but using GPU is tough as its documentation are not detailed.

---

<div class="post-metadata">

**Author:** ![langestefan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/langestefan/32/207923_2.png) [@langestefan](https://discourse.julialang.org/u/langestefan)\
**Post date:** [December 20, 2025, 11:43pm UTC](https://discourse.julialang.org/t/speeding-up-trig-heavy-code/134656/5 "2025-12-20T23:43:49Z")

</div>

> [@gdalle](#):
>
> Is it common to have just a single solar position you want to compute?

I use it for the MTK component wrapper, but other than that probably not.

> [@raman\_kumar](#):
>
> If your code is calculating trigonometric values of same angle then combinations like `sincos`and `sincosd` etc. can help improve performance.

True, already using that.

---

<div class="post-metadata">

**Author:** ![raman\_kumar](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raman_kumar/32/26782_2.png) [@raman\_kumar](https://discourse.julialang.org/u/raman_kumar)\
**Post date:** [December 21, 2025, 12:07am UTC](https://discourse.julialang.org/t/speeding-up-trig-heavy-code/134656/6 "2025-12-21T00:07:26Z")

</div>

> [@langestefan](#):
>
> True, already using that.

But now i think that i am wrong 😂.

```julia-auto
julia> using BenchmarkTools

julia> x= rand(1000);

julia> f(x) = (sin(x), cos(x))
f (generic function with 1 method)

julia> m(x) = sincos(x)
m (generic function with 1 method)

julia> @btime f.($x);

  5.805 μs (3 allocations: 15.70 KiB)

julia> @btime m.($x);

  6.161 μs (3 allocations: 15.70 KiB)

```

Results varies with size of `x`.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [December 21, 2025, 7:21pm UTC](https://discourse.julialang.org/t/speeding-up-trig-heavy-code/134656/7 "2025-12-21T19:21:35Z")

</div>

When you benchmark on an array, the results get confused with memory effects, and there is probably a lot more noise.

Here is a benchmark on a single number. The improvement is even greater if you use a larger angle, because then it only needs to do the reduction modulo 2π once.

```julia-auto
julia> @btime f($(Ref(0.1))[]);
  4.625 ns (0 allocations: 0 bytes)

julia> @btime sincos($(Ref(0.1))[]);
  3.958 ns (0 allocations: 0 bytes)

julia> @btime f($(Ref(10.1))[]);
  6.875 ns (0 allocations: 0 bytes)

julia> @btime sincos($(Ref(10.1))[]);
  5.541 ns (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

**Author:** ![wsmoses](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wsmoses/32/26497_2.png) [@wsmoses](https://discourse.julialang.org/u/wsmoses)\
**Post date:** [December 21, 2025, 8:40pm UTC](https://discourse.julialang.org/t/speeding-up-trig-heavy-code/134656/8 "2025-12-21T20:40:50Z")

</div>

since from the perf log it appears you have a bunch of individual kernel calls, using Reactant.@compile may be able to help identify fusion opportunities

---

<div class="post-metadata">

**Author:** ![langestefan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/langestefan/32/207923_2.png) [@langestefan](https://discourse.julialang.org/u/langestefan)\
**Post date:** [December 21, 2025, 9:07pm UTC](https://discourse.julialang.org/t/speeding-up-trig-heavy-code/134656/9 "2025-12-21T21:07:20Z")

</div>

Ran a small test with Reactant.jl, it immediately found/compiled for my RTX3090 (magic?) and that yielded a 200x speedup. That’s pretty insane!

---

<div class="post-metadata">

**Author:** ![roflmaostc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/roflmaostc/32/30123_2.png) [@roflmaostc](https://discourse.julialang.org/u/roflmaostc)\
**Post date:** [December 22, 2025, 2:34pm UTC](https://discourse.julialang.org/t/speeding-up-trig-heavy-code/134656/10 "2025-12-22T14:34:42Z")

</div>

Are you sure you did synchronize your CUDA kernel?

`@btime CUDA.@sync ...`

---

<div class="post-metadata">

**Author:** ![langestefan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/langestefan/32/207923_2.png) [@langestefan](https://discourse.julialang.org/u/langestefan)\
**Post date:** [December 22, 2025, 6:49pm UTC](https://discourse.julialang.org/t/speeding-up-trig-heavy-code/134656/11 "2025-12-22T18:49:59Z")

</div>

I’m not sure what you mean, so I guess no? 😅

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [December 22, 2025, 9:54pm UTC](https://discourse.julialang.org/t/speeding-up-trig-heavy-code/134656/12 "2025-12-22T21:54:20Z")

</div>

If you don’t call `CUDA.@sync` you’re only measuring the time it takes for the CPU to tell the GPU “do this”. You’re missing the actual computation time + the time it takes for the results to travel back to the CPU, which is what `@sync` does.

---

<div class="post-metadata">

**Author:** ![wsmoses](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wsmoses/32/26497_2.png) [@wsmoses](https://discourse.julialang.org/u/wsmoses)\
**Post date:** [December 22, 2025, 11:45pm UTC](https://discourse.julialang.org/t/speeding-up-trig-heavy-code/134656/13 "2025-12-22T23:45:13Z")

</div>

Reactant does not call CUDA.jl (julia specific bindings of the cuda runtime), it calls CUDA directly, so that does not apply. However you can use @compile sync=true to be assured of the same

---

<div class="post-metadata">

**Author:** ![wsmoses](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wsmoses/32/26497_2.png) [@wsmoses](https://discourse.julialang.org/u/wsmoses)\
**Post date:** [December 23, 2025, 4:24am UTC](https://discourse.julialang.org/t/speeding-up-trig-heavy-code/134656/14 "2025-12-23T04:24:45Z")

</div>

@langestefan if you have a PR open with your use of reactant, I can offer comments on if the setup for benchmarking is proper. Relatedly, if this is an interesting code, we’d be happy to take it as an integration test in Reactant!

---

<div class="post-metadata">

**Author:** ![langestefan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/langestefan/32/207923_2.png) [@langestefan](https://discourse.julialang.org/u/langestefan)\
**Post date:** [December 24, 2025, 1:48pm UTC](https://discourse.julialang.org/t/speeding-up-trig-heavy-code/134656/15 "2025-12-24T13:48:42Z")

</div>

I’m working on it, but I have some beginner questions 😅. Should I ask those on slack? (I see no reactant channel, but I think it deserves one!)

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [December 24, 2025, 1:58pm UTC](https://discourse.julialang.org/t/speeding-up-trig-heavy-code/134656/16 "2025-12-24T13:58:31Z")

</div>

> [@langestefan](#):
>
> Should I ask those on slack

Sounds like they may be helpful to other people as well, so asking on discourse for persistence would be better.

---

<div class="post-metadata">

**Author:** ![langestefan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/langestefan/32/207923_2.png) [@langestefan](https://discourse.julialang.org/u/langestefan)\
**Post date:** [December 24, 2025, 3:01pm UTC](https://discourse.julialang.org/t/speeding-up-trig-heavy-code/134656/17 "2025-12-24T15:01:23Z")

</div>

So there is a warning for 1.12 that it is not supported, but I haven’t run into any issues with it so far. I guess 1.12 support is mostly there now and it is ‘okay’ to use?

In the examples data is converted to `ConcreteRArray` using `Reactant.to_rarray`. But this function has no docs or docstring and ‘may be internal’ ?

```julia-auto
help?> Reactant.to_rarray
  │ Warning
  │
  │ The following bindings may be internal; they may change or be removed in future versions:
  │
  │ • Reactant.to_rarray

```

The input to my function is a vector of `DateTime`, which just returns itself:

```julia
julia> dts = collect(DateTime(2020):Hour(1):DateTime(2021))
8785-element Vector{DateTime}:

julia> Reactant.to_rarray(dts)
8785-element Vector{DateTime}:

```

Still, `@compile` seems to work correctly.

---

<div class="post-metadata">

**Author:** ![Elrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elrod/32/22461_2.png) [@Elrod](https://discourse.julialang.org/u/Elrod)\
**Post date:** [December 25, 2025, 7:03am UTC](https://discourse.julialang.org/t/speeding-up-trig-heavy-code/134656/18 "2025-12-25T07:03:32Z")

</div>

If you do trig in a loop, `LoopVectorization.@turbo` should speed it up.  
But not by nearly as much as running it on a GPU.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [December 25, 2025, 4:57pm UTC](https://discourse.julialang.org/t/speeding-up-trig-heavy-code/134656/19 "2025-12-25T16:57:40Z")

</div>

I’ve opened two issues:

- [[Bug] polynomial evaluation accomplished in a suboptimal manner, sure cause of suboptimal accuracy and suboptimal performance · Issue #49 · JuliaAstro/SolarPosition.jl · GitHub](https://github.com/JuliaAstro/SolarPosition.jl/issues/49)

- [[Bug] most likely you want to replace each used Taylor polynomial with a Minimax polynomial · Issue #51 · JuliaAstro/SolarPosition.jl · GitHub](https://github.com/JuliaAstro/SolarPosition.jl/issues/51)

A PR attempts to fix issue `#49`:

- [rely on `evalpoly` instead of hardcoding polynomial evaluation by nsajko · Pull Request #50 · JuliaAstro/SolarPosition.jl · GitHub](https://github.com/JuliaAstro/SolarPosition.jl/pull/50)

Some more notes:

- ~~More improvements, for performance and/or accuracy, could perhaps be achieved by creating specialized kernel functions.~~ Been playing with these ideas in Sollya, but was not able to achieve an improvement.

- Some of the above would be easier to tackle if the constant coefficients that appear all over the code base were commented more effectively. As is, when I notice a polynomial in the code, I basically have to reverse engineer, or look for matching numbers in all relevant literature. It would be nice if each polynomial in the source code was near to a comment that made it clear what are the exact values of the coefficients (before rounding to `Float64`), and what is the expression for the Taylor series.

- Another thing that might make further improvements easier would be an arbitrary precision implementation.

---

<div class="post-metadata">

**Author:** ![langestefan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/langestefan/32/207923_2.png) [@langestefan](https://discourse.julialang.org/u/langestefan)\
**Post date:** [December 25, 2025, 9:16pm UTC](https://discourse.julialang.org/t/speeding-up-trig-heavy-code/134656/20 "2025-12-25T21:16:34Z")

</div>

Thank you for looking at the code, providing feedback and preparing the PR!

[Next page](https://discourse.julialang.org/t/speeding-up-trig-heavy-code/134656.md?page=2)
