What does `fastabs(z::Complex)` do?

There is a fastabs(z::Complex) defined in both SpecialFunctions.jl and Base.Math.

From its name, I would guess it computes the same thing as abs(z::Complex) but faster. However

julia> z = 3 + 4im
3 + 4im

julia> abs(z)
5.0

julia> Base.Math.fastabs(z)
7

Looking at the code, the definition is

"""
    fastabs(x::Number)
Faster `abs`-like function for rough magnitude comparisons.
`fastabs` is equivalent to `abs(x)` for most `x`,
but for complex `x` it computes `abs(real(x))+abs(imag(x))` rather
than requiring `hypot`.
"""
fastabs(x::Number) = abs(x)
fastabs(z::Complex) = abs(real(z)) + abs(imag(z))

What is this function used for?

I thought this was a bug and opened an issue and was told that there is some “intended behaviour”… what is the used case? It’s confusing when it says

Faster abs-like function for rough magnitude comparisons.

while 5 and 7 seems to be a pretty big difference…

The use case here is for special functions where you want to do something different for big and small inputs. Specifically, fastabs will be off by a maximum factor of sqrt(2), so it’s very useful when a function needs to do something different for small inputs.

2 Likes

Thanks for the explanation. I’m not familiar with the special functions – I will read more on it.

The reason that got me interested was that I noticed the Base.abs was indeed much slower than a hand-coded one, although there’s some small errors.

julia> using BenchmarkTools

julia> zz = rand(ComplexF64, 10000, 10000);

julia> complex_abs(z::Complex) = √(abs2(real(z)) + abs2(imag(z)))
complex_abs (generic function with 1 method)

julia> @btime abs.(zz);
  1.657 s (5 allocations: 762.94 MiB)

julia> @btime complex_abs.(zz);
  414.170 ms (5 allocations: 762.94 MiB)

julia> @btime hypot.(zz);
  1.533 s (5 allocations: 762.94 MiB)

julia> abs.(zz) == hypot.(zz)
true

julia> abs.(zz) == complex_abs.(zz)
false

julia> abs.(zz) ≈ complex_abs.(zz)
true

So at first I thought the reason for fastabs was just faster abs with some numerical error – not expecting a factor of sqrt(2). But now it seems that’s just me not taking enough math classes :slight_smile:

If you want a faster version, you could try @fastmath abs.(zz) which should do something close to complex_abs.

3 Likes