Golang Complex Numbers
The Go programming language includes native support for complex numbers. Complex numbers have a real and an imaginary component (see the Wikipedia article for more information on this).
There are two complex number types: complex64 and complex128. These are shown in the table below:
Float Type | Description | Range |
complex64 | 64-bit complex number | -3.4e+38 to +3.4e+38 for both real and imaginary |
complex128 | 128-bit complex number | -1.7e+308 to +1.7e+308 for both real and imaginary |
Go makes working with complex numbers very easy using unique syntax.
The Two Parts of an Imaginary Number
As mentioned, a complex number has two parts: one real, and one imaginary.
The real part is like any other (non-complex) number, but the imaginary part is formed by multiplying a number with the square root of -1, abbreviated i or sometimes j.
Take the following example:
3 + 5i
3 + 5j
These complex numbers are equal; j is often used in engineering applications where an i might be confusing (such as when working with electric current).
The number ‘3’ is the real part and the number ‘5i‘ or ‘5j‘ is the imaginary part. These are equal to the number 5 times the square root of negative one:
5i = 5j = 5\sqrt{-1}
Initializing Complex Numbers in Go
Initializing complex numbers is slightly different when compared with other types because they have two parts that need to be specified. There are two ways to intialize complex numbers in Go: using a parentheses-based syntax, and using a more classic syntax in which we specify the imaginary side using the character ‘i‘.
The parentheses syntax seems to be more popular, but we will cover both below.
Parentheses Syntax
In Golang, when working with a complex number, we have to declare both parts. We can do this using parentheses:
var <name> = complex(<real>,<imaginary>)
This can be seen in the example below:
package main
import (
"fmt"
)
func main() {
var c1 = complex(4, 2)
fmt.Println(c1)
}
Output:
(4+2i)
As with other variable types, we would have gotten the same result using ‘:=’ instead of the var keyword:
c1 := complex(4, 2)
Classic Syntax
I am using the term ‘classic syntax’ to describe this form because it is the same syntax for complex numbers used in the field of mathematics. ‘Classic syntax’ is my own description for this, as a way of distinguishing it from the ‘parentheses syntax’ described above.
To initialize a complex number using classic syntax, we can simply assign a complex value to a variable by denoting the imaginary part of the number with the character i:
var <name> = <real> + <imaginary>i
Let’s look at an example:
package main
import (
"fmt"
)
func main() {
var c1 = 4 + 3i
c2 := 2 + 5i
fmt.Println(c1)
fmt.Println(c2)
}
Output:
(4+3i) (2+5i)
Note that we initialized c1 using the var keyword and c2 using ‘:=’. They both gave us the same result (excepting the actual values, of course).
Getting the Real and Imaginary Parts of a Complex Number in Go
Go makes it easy to retrieve the real or the imaginary part of a complex number.
To get the real part of a complex number, we can use the keyword real:
real(num)
To get the real part of a complex number, we can use the keyword imag.
imag(num)
The following example shows how this looks in code:
package main
import (
"fmt"
)
func main() {
var c1 = 4 + 3i
fmt.Println(real(c1))
fmt.Println(imag(c1))
}
Output:
4 3
Complex Number Math in Go
Go makes it easy to perform mathematical operations on complex numbers.
We can use the standard mathematical operators (+, -, *, /) to easily perform basic operations:
package main
import (
"fmt"
)
func main() {
c1 := 4 + 3i
c2 := 2 + 5i
fmt.Println(c1 + c2)
fmt.Println(c1 - c2)
fmt.Println(c1 * c2)
fmt.Println(c1 / c2)
}
Output:
(6+8i) (2-2i) (-7+26i) (0.793103448275862-0.48275862068965514i)
The math/cmplx Package
We have seen that we can perform basic operations on complex numbers using the native support included with Go. However, there are many operations that can’t be performed (or are more difficult to perform) without importing additional functionality.
In Golang, one of the most useful libraries for performing mathematical operations is the math package. Within the math package is the math/cmplx package, which specializes in extending Go’s functionality for complex numbers.
The math/cmplx package contains many helpful functions for working with complex numbers. These include:
- Absolute value of a complex number using the function Abs().
- Trigonometric operations with complex numbers.
- Logarithmic operations on complex numbers.
- Additional mathematical operations such as the square root of a complex number.
- Complex conjugate of a complex number.
See the complete list of available functions in the (easy to read!) official documentation.
In the next section, we will cover how to calculate the complex conjugate of a complex number in Go using the math/cmplx package. This will provide a template for working with this package so that you can extend this example when performing other tasks with complex numbers in Go.
Calculating a Complex Conjugate in Go
We can use the math/cmplx package to calculate the complex conjugate of a complex number in Go.
The complex conjugate is a number that has the same real value but negative imaginary value as the original number. For example, if we take the complex number ‘4 + 5i‘ then the complex conjugate of this number will be ‘4 – 5i‘.
The complex conjugate is useful in a variety of circumstances. For example, it can be multiplied with the original number to calculate its’ absolute value.
In order to use the math/cmplx package, first we need to import it.
Importing the math/cmplx Package
We need to import the math/cmplx package by including it in the import statement:
import (
"fmt"
"math/cmplx"
)
Note that we also keep the fmt package to allow us to print to the console.
Using the math/cmplx Package
Now we can use functions inside the cmplx package using the syntax:
cmplx.<Function Name>()
We can use this syntax to find the complex conjugate using the Conj() function:
package main
import (
"fmt"
"math/cmplx"
)
func main() {
c1 := 4 + 3i
c2 := 2 - 5i
c3 := -6 - 19i
cc1 := cmplx.Conj(c1)
cc2 := cmplx.Conj(c2)
cc3 := cmplx.Conj(c3)
fmt.Printf("Complex Conjugate of c1: %f\n", cc1)
fmt.Printf("Complex Conjugate of c2: %.1f\n", cc2)
fmt.Printf("Complex Conjugate of c3: %.2f", cc3)
}
Output:
Complex Conjugate of c1: (4.000000-3.000000i) Complex Conjugate of c2: (2.0+5.0i) Complex Conjugate of c3: (-6.00+19.00i)
Inside the Printf argument, we had to use a bit of magic for this to print cleanly.
%f designates that we want to print a value without an exponent.
\n tells the compiler to print a new line.
For the sake of completeness and clarity, we printed the complex conjugate with 3 different decimal place configurations:
%f to use the default number of decimal places.
%.1f to use a single decimal place.
%.2f to use two decimal places.