1

I am in the process of optimizing the most demanding function in a Unity 3d game. The most costly subroutine is the unity Mathf.Abs method which is being called on floating point values(NEVER DOUBLES). In cases, calls to this function are adding multiple milliseconds to the frame render delay. The code base is confidential so you will have to take my word that the Abs calls are central to the algorithm.

While deep profiling I discovered that mathf. Abs is just a wrapper that calls the much faster system.math.abs that is used for doubles. It seems that if I could avoid the wrapper entirely and simply call an equivalent of system.Math.Abs designed for float32, I would get significant speedup for free.

Can someone explain to me why it's so difficult to find one? The float libs I tested on NuGet are also converting the results from a double version.

I looked into the GNU implementation that used a a float_long union struct and a masking operation. Could someone steer me in the right direction of implementing this in my own namespace or finding one that will help me out?

  • 3
    What about `float abs = x < 0 ? -x : x;`? Its probably the fastest you can get – SinOfficial Jun 29 '19 at 21:05
  • I got roughly 2x speedup with your solution. I feel pretty foolish for not trying this, I thought I'd have to do more bit wrangling, but it turns out compiler saves the day again. If you want some bonus points, please explain what the union struct in the GNU implementation is for. – Loot Fox Official - Parker Jun 30 '19 at 06:30
  • btw you **can** simply use [`System.Math.Abs`](https://learn.microsoft.com/dotnet/api/system.math.abs#System_Math_Abs_System_Single_) on `float` (= `Single`) values – derHugo Jul 01 '19 at 05:21
  • The fastest way would probably involve manually changing the sign bit of the floating point value. I'm not going to benchmark this for you since it is 3am for me right now, but it would probably involve creating a function marked as unsafe, reinterpreting it as an int with something like `int bits = *(int*)(&val);`, changing the sign bit with something like `bits &= ~(1 << 31);` and then reinterpreting that as a float again. – adisib Jul 01 '19 at 06:37
  • A relavent question/answer [here](https://stackoverflow.com/questions/44630015/how-would-fabsdouble-be-implemented-on-x86-is-it-an-expensive-operation). Notice that with SSE instruction set you can perform multiple fabs at once. – jodag Jul 11 '19 at 17:02
  • I found your question googling for a similar matter. I just closed (but copied the link just in case) an article which touches the ground (also shows decompiled snippets), I found the answer satisfying (even if its in direct contradiction with a solution that worked for you, spooky) https://jacksondunstan.com/articles/5361 – zambari Feb 27 '20 at 21:49

0 Answers0