# Complex arithmetic significantly slower? - not really

**URL:** <https://fortran-lang.discourse.group/t/complex-arithmetic-significantly-slower-not-really/4569>\
**Category:** Help\
**Created:** [October 19, 2022, 4:33pm UTC](https://fortran-lang.discourse.group/t/complex-arithmetic-significantly-slower-not-really/4569 "2022-10-19T16:33:03Z")\
**Posts on this page:** 8\
**Page:** 2

<div class="post-metadata">

**Author:** ![Pap](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/pap/32/1305_2.png) [@Pap](https://fortran-lang.discourse.group/u/Pap)\
**Post date:** [October 19, 2022, 10:09pm UTC](https://fortran-lang.discourse.group/t/complex-arithmetic-significantly-slower-not-really/4569/25 "2022-10-19T22:09:16Z")

</div>

> [@vmagnin](#):
>
> So it does not simply compute `sqrt(X*X+Y*Y)` but takes care of overflow/underflow problems that could occur.

> [@RonShepard](#):
>
> The library routine to compute complex abs is complicated, with tests to protect against unnecessary overflow and underflow. Also, it is a 2-norm that requires a square root, which adds additional overhead to the test.

This probably explains the results I posted above.

> [@kargl](#):
>
> When I see a statement that attacks those that have given you (a generic you) a free compiler, I will speak up. Your statement below is yet another example of why I have stopped contributing (and others as well).

Well, I never said GFortran is bad - if it was I wouldn’t use it. I was just wondering why I got poor performance in the complex plane, and I got the answer. When I see such a difference in performance I could suspect something is wrong with complex numbers arithmetic, and I clearly said this was just a GUESS - which turned out to be a wrong one. Does this justify a flat-out blatantly offensive first reaction? You should “speak up” if you so wish, but you could/should also be more civilized as well. Nobody came here to bash GFortran - definitely not me, since I am using it almost exclusively the last few years. I can’t thank enough the people behind the whole GCC project for their work, but that doesn’t mean I should never suspect something is wrong, or even questioning the way the whole project takes lately (but that’s another topic, and very controversial.)

> [@ivanpribec](#):
>
> The factor 2× difference between abs and the squared norm is observable in other compilers too:

Thank you for those results, I was wondering what’s going on with other compilers as well.

> [@PierU](#):
>
> Multiplications are almost for free (at least they are as soon as the result is added to something), and I expect any decent compiler to replace the power 2 (\*\*2) by a simple multiplication. Writing a multiplication instead of \*\*2 is a C habit 😉

This is a lesson I learned years ago and that’s why I treat `**2` like a taboo. But things are changing for the better, it seems.

> [@vmagnin](#):
>
> For Mandelbrot, I tried also other metrics like the [Manhattan distance](https://en.wikipedia.org/wiki/Taxicab_geometry) and the [Chebyshev distance](https://en.wikipedia.org/wiki/Chebyshev_distance).

This is just an example for my upcoming FGL, in fact it is just a “sub-example” showing the capabilities of the imaging “sub-library” I added recently. It was never intended to be a thorough fractals study, although it is certainly an interesting topic.

In fact when I saw the poor performance the first thing I thought is something is wrong with the imaging code (which maybe needed optimizations or was buggy - I hunted the “usual suspect”, the “big fish” first.) So I wrote the equivalent code in C for comparisons, focusing on how the imaging is done. But C doesn’t have built-in complex arithmetic (yes, I am aware of \<complex.h\>, but come on now). So my C implementation never had `abs` or `sqrt` since all I care for is if we escaped the small circle Mandelbrot is all about. When I saw the C code performing better I got angry. 😆 Fun fact: when I was typing that `abs` in the Fortran complex-plane version of the code, I stopped for a moment thinking “maybe not `abs`?”. Then I thought “nevermind, it makes the code clearer”. Little did I know this would cost several hours of work to hunt down a bug in the imaging code - which was not there.

Thank you all for participating. This was productive. 🙂  
The discussion you people did about Mandelbrot set and how to further optimize the offending line in the code made me thinking of starting a whole fractal project. But I guess 0.1-0.5 seconds for a detailed fractal image in a “sub-example” of my library, using a 10-years-old laptop (which was never a good one to begin with) is… good enough for now. Otherwise that library would never be completed.

---

<div class="post-metadata">

**Author:** ![RonShepard](https://avatars.discourse-cdn.com/v4/letter/r/a3d4f5/32.png) [@RonShepard](https://fortran-lang.discourse.group/u/RonShepard)\
**Post date:** [October 19, 2022, 10:27pm UTC](https://fortran-lang.discourse.group/t/complex-arithmetic-significantly-slower-not-really/4569/26 "2022-10-19T22:27:56Z")

</div>

> [@Pap](#):
>
> This is a lesson I learned years ago and that’s why I treat `**2` like a taboo. But things are changing for the better, it seems.

I would say that this has not been an issue in any fortran compiler since the 1960s. The more general way to compute integer powers involves extracting the bits from the exponent and recursively multiplying to get the final result. Even that is relatively cheap, especially for constant integer exponents where the compiler can see what is the highest nonzero bit.

The thing that is expensive is `x**y` where `x` and `y` are floating point. This is typically computed using log() and exp(). This is what the C language does with its `pow()` function, and it is why C programmers avoid it when possible and replace it with explicit multiplies. As I said, for integer exponents, this has not been a problem in fortran since the 1960s.

---

<div class="post-metadata">

**Author:** ![Pap](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/pap/32/1305_2.png) [@Pap](https://fortran-lang.discourse.group/u/Pap)\
**Post date:** [October 19, 2022, 11:18pm UTC](https://fortran-lang.discourse.group/t/complex-arithmetic-significantly-slower-not-really/4569/28 "2022-10-19T23:18:28Z")

</div>

> [@RonShepard](#):
>
> I would say that this has not been an issue in any fortran compiler since the 1960s. The more general way to compute integer powers involves extracting the bits from the exponent and recursively multiplying to get the final result.

You are probably right, I am only using compilers, never got involved in making one. But with an ancient Assembly and Pascal background (which didn’t even have a `pow` function back then) you get used to “powers means `log`”, so it’s a “terrifying” thing you should avoid - even if it’s just foo squared. Nothing worse than an old habit…

> [@kargl](#):
>
> You made a sweeping generalization about the quality of gfortran.

I beg to strongly disagree. You just quoted me, but you conveniently skipped the last part. I will make it bold in the full quote:

> [@Pap](#):
>
> My best bet is that complex numbers are poorly implemented - in GFortran, at least. **But I might be wrong here.**

I am really sorry I have to say this but this convenient half-quote doesn’t give me an option:  
Where is the “sweeping generalization” and the “attack to gfortran” is beyond me. But the flat-out uncivilized, bad manners are right in front of me when I read your first post. And the next ones don’t get much better…

---

<div class="post-metadata">

**Author:** ![Pap](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/pap/32/1305_2.png) [@Pap](https://fortran-lang.discourse.group/u/Pap)\
**Post date:** [October 19, 2022, 11:59pm UTC](https://fortran-lang.discourse.group/t/complex-arithmetic-significantly-slower-not-really/4569/30 "2022-10-19T23:59:03Z")

</div>

> [@kargl](#):
>
> I am well aware of the second sentence. Nothing like a escape clause. The sweeping generalization is the first sentence. I won’t quoted again. The first sentence was unnecessary in your initial post and provoked a response you did not expect.

Well, your… abrasive response (to put it lightly, it was far more offensive than that) provoked a response you obviously did not expect - but you should, unless you think you can do such things, and others will just accept such a behavior without answering.  
The fact is I _never_ said GFortran is bad, and I am thankful to the people behind it. That doesn’t mean I will accept every decision they take (especially lately) blindly nor it means I will accept bad manners.  
At any rate, think what you wish, it doesn’t really matter. My question here was answered, plus it triggered an interesting discussion about further optimizations, which I very much enjoyed. I prefer to stay at that.

---

<div class="post-metadata">

**Author:** ![PierU](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/pieru/32/1848_2.png) [@PierU](https://fortran-lang.discourse.group/u/PierU)\
**Post date:** [October 20, 2022, 6:23am UTC](https://fortran-lang.discourse.group/t/complex-arithmetic-significantly-slower-not-really/4569/32 "2022-10-20T06:23:19Z")

</div>

> [@vmagnin](#):
>
> I tried that in May. And discovered that 2.0 must be replaced by ~2.3: the topological ball is a square with sides oriented at a 45° angle. And if you want the Mandelbrot set to be fully inside, 2.0 is not enough.
> 
> Note also that the contour lines are different from the Euclidean contour lines outside the set, so the esthetic is different.

Sure… I did the test only for timing purposes with random data, not even the Mandelbrot algorithm. But in general yes, replacing the L2 norm by the L1 norm (or any other norm) has implications beyond the timing.

---

<div class="post-metadata">

**Author:** ![PierU](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/pieru/32/1848_2.png) [@PierU](https://fortran-lang.discourse.group/u/PierU)\
**Post date:** [October 20, 2022, 6:30am UTC](https://fortran-lang.discourse.group/t/complex-arithmetic-significantly-slower-not-really/4569/33 "2022-10-20T06:30:49Z")

</div>

> [@RonShepard](#):
>
> Is the test for the size of the circle or rectangle that is plotted? If so, and if it is a square plot, then it seems like two separate tests
> 
> ```auto
> if ( abs(znew%re) > 1.0_wp) exit
> if ( abs(znew%im) > 1.0_wp) exit
> 
> ```
> 
> would be appropriate. There are no multiplications, additions, divisions, or square roots in those tests.

This is the ~~L0 norm~~ L∞ norm… But it’s not faster: you are trading an addition for a second test. It can be a faster if the first test is triggered often enough.

---

<div class="post-metadata">

**Author:** ![vmagnin](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/vmagnin/32/28_2.png) [@vmagnin](https://fortran-lang.discourse.group/u/vmagnin)\
**Post date:** [October 20, 2022, 7:42am UTC](https://fortran-lang.discourse.group/t/complex-arithmetic-significantly-slower-not-really/4569/34 "2022-10-20T07:42:01Z")

</div>

> [@RonShepard](#):
>
> then it seems like two separate tests
> 
> ```auto
> if ( abs(znew%re) > 1.0_wp) exit
> if ( abs(znew%im) > 1.0_wp) exit
> 
> ```

I think those tests seem equivalent to Chebyshev distance (L\_{\infty} metric):  
for Mandelbrot we can use `if (max(abs(z%re), abs(z%im)) > 2.0_wp)`  
and yes, there is no arithmetic =\> fast & no rounding.

Here 2.0 is sufficient, as the topological ball is a square parallel to the axes.

The graphical difference comes from the fact that the color outside the Mandelbrot set is generally computed from the number of iterations of the most inner loop. So it depends on the metric used in that test.

---

<div class="post-metadata">

**Author:** ![vmagnin](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/vmagnin/32/28_2.png) [@vmagnin](https://fortran-lang.discourse.group/u/vmagnin)\
**Post date:** [October 20, 2022, 7:50am UTC](https://fortran-lang.discourse.group/t/complex-arithmetic-significantly-slower-not-really/4569/35 "2022-10-20T07:50:14Z")

</div>

Concerning `abs(z)`, I would finally say avoid it:

- if it has a significant impact on performances (here it weights ~half of the most inner loop),
- and you don’t need the Euclidean distance in another computation (here the square of the distance is sufficient),
- and you are sure you will have no overflow (here we are just around a small circle) and no problems with underflow (here the origin is in the big heart of the set).

So in the general case use `abs(z)` unless you have a good reason to avoid it.

[Previous page](https://fortran-lang.discourse.group/t/complex-arithmetic-significantly-slower-not-really/4569.md?page=1)
