Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: I created fast sin() / cos() which could replace slower std::sin()/cos()  (Read 382 times)

0 Members and 1 Guest are viewing this topic.

jp

  • Newbie
  • *
  • Posts: 12
    • View Profile
    • Email
Hi

I was thinking I might be able to provide some code to SFML ... possibly ... :).
It's this: There are sin() and cos() functions at least in 3 modules:

Transformable.hpp
rotate.hpp
view.hpp

And there something like this:

float angle = m_rotation * 3.141592654f / 180.f;
float cosine = static_cast<float>(std::cos(angle));
float sine = static_cast<float>(std::sin(angle));
 

sin() and cos() are significantly slower than multiplication and division so I was thinking if I could find an approximation function which gives the same result/accuracy as sin/cos but is faster. Now I finished working on that and my function fastSin(float angle) is more than 80% faster than std::sin() (and I can do the same for cos()). The good thing is that it is basically as accurate as std::sin(). So calling for example std::sin(0.2866) and fastSin(0.2866) gives the same result, it is just > 80% faster (so about 2 times faster).
(actually in testing it was 82% -340%  faster depending on how many sin() calls in a row).

I know this is not super critical, as those functions with sin/cos (like the getTransform()) are not likely to be called hundreds of thousands of times per second. But if this is any useful I am ready to provide the code for it.

By the way, I studied mathematics in an university and actually my final thesis was just about this: approximating functions (like sin()) by polynomial functions.

Any thoughts?
« Last Edit: March 07, 2021, 02:04:13 pm by jp »

roccio

  • Jr. Member
  • **
  • Posts: 62
    • View Profile
    • Email
It is very interesting. Would be nice to share the code.

jp

  • Newbie
  • *
  • Posts: 12
    • View Profile
    • Email
It is very interesting. Would be nice to share the code.

Ok, just pushed the first version to github:

https://github.com/PekkaCoder/FastSineCos

I have a test bench code and other testing codes also - I am planning to add it there also at some point. So everybody can test it easily and be sure it works (plus see the speed difference).

Also it's a "quick" first version, so quite likely I keep improving it and adding some things later on.

One of the tricks why I get it faster is the fact that when one rotates something, normally the next angle is close to the previous angle, like : 1.52, 1.56, 1.68 etc... So this class uses this as an advantage to calculate the value faster.
« Last Edit: March 07, 2021, 08:00:38 pm by jp »

Elias Daler

  • Hero Member
  • *****
  • Posts: 602
    • View Profile
    • Blog
    • Email
I don't think that it's worth it to maintain custom functions which are implemented in standard library, thoroughly tested and optimized for specific processors... Currently trigonometric function are far from being bottlenecks for SFML.
Tomb Painter, Re:creation dev | eliasdaler.github.io | @EliasDaler | Tomb Painter dev log

jp

  • Newbie
  • *
  • Posts: 12
    • View Profile
    • Email
Currently trigonometric function are far from being bottlenecks for SFML.
Yes true it's not a bottleneck.
I think I am going to use those myself in my own code if I need sin/cos because they are there now, although first needs proper testing.

Just found there is also std::sinf() (C++11) which I was thinking surely is faster because less digits to calculate, but I just tested and was surprised to find out it has the same speed as sin() (unless I made an error in testing).

eXpl0it3r

  • Moderator
  • Hero Member
  • *****
  • Posts: 9795
    • View Profile
    • development blog
    • Email
SFML doesn't see itself as a fast math library, nor are we trying to trade maintainable code for questionable performance gains.
It's fun to play around with these optimization and awesome to hear that you were able to write a thesis around this topic, but it doesn't really fit here. :)
I believe if someone determines that std::sin/std::cos are bottlenecks in their code, they might want to find a more generic way to replace them in all the code used anyways and not just SFML, so they may be better off with a STL drop-in replacement.

Just found there is also std::sinf() (C++11) which I was thinking surely is faster because less digits to calculate, but I just tested and was surprised to find out it has the same speed as sin() (unless I made an error in testing).
As far as I know std::sin and std::sinf do the exact same thing, so comparing them will result in the same performance. The reason why they were added, are founded in the C world and to align with similar function sets. With C++ function overloads, you can write functions with different types but the same function name. ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Nightly Builds: https://www.nightlybuilds.ch/
——————————————————————
Dev Blog: https://dev.my-gate.net/
Thor: http://www.bromeon.ch/libraries/thor/

jp

  • Newbie
  • *
  • Posts: 12
    • View Profile
    • Email
As far as I know std::sin and std::sinf do the exact same thing, so comparing them will result in the same performance. The reason why they were added, are founded in the C world and to align with similar function sets. With C++ function overloads, you can write functions with different types but the same function name. ;)
Aha, that would explain the result.
But just thinking, that float precision (7 digits) has faster approximation than double (15 digits), because the more precision for Sine() the slower the calculation. Getting accurate 7 decimal precision for Sine should be clearly faster than calculating 15 decimal precision. So I guess STL is using double formula for float?
But this is a C++ STL issue, maybe I should ask C++ forum about this :).

Nexus

  • Moderator
  • Hero Member
  • *****
  • Posts: 6254
  • Thor Developer
    • View Profile
    • Bromeon
@jp check the C++ documentation: https://en.cppreference.com/w/cpp/numeric/math/sin
As mentioned by eXpl0it3r, there are overloads for float and double. So the float one doesn't use an unnecessary number of digits.

I agree that it's a nice way to experiment with sin/cos optimizations, but you're also not the first one doing it:
While the standard trigonometric functions may not be the fastest, they're standard, i.e. available everywhere, conforming to the specification and battle-tested for years if not decades (i.e. almost certainly bug-free). For generality they may trade off performance.

Ultimately, the fastest possible implementation is likely a LUT (look-up table), not a Taylor series. Again a trade-off between code size/memory and speed.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development: first SFML book

 

anything