 # 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 If you want a faster version, you could try `@fastmath abs.(zz)` which should do something close to `complex_abs`.

3 Likes