Introduction
Moving on in the 100 days of golang series, we can take a look into the math package in golang's standard library. In programming, math is quite critical aspect, we need to perform certain mathematical operations quite regularly so golang's standard library has a package for serving some quite commonly used math functions and procedures. We'll take a look at some of the basic and common functions which are available in the math package.
Mathematical Constants
We have some constants like pi
, e
, Phi
already defined as constants in the math package of the standard library in golang. They have a precision till 15 digits stored in float64 values.
package main import ( "fmt" "math" ) func main() { fmt.Println("Pi = ", math.Pi) fmt.Println("E = ", math.E) fmt.Println("Phi = ", math.Phi) fmt.Println("Sqrt of 2 = ", math.Sqrt2) fmt.Println("Naturla Log 2 = ", math.Ln2) fmt.Println("Naturla Log 10 = ", math.Ln10) }
$ go run basic-functions/constants.go Pi = 3.141592653589793 E = 2.718281828459045 Phi = 1.618033988749895 Sqrt of 2 = 1.4142135623730951 Naturla Log 2 = 0.6931471805599453 Naturla Log 10 = 2.302585092994046
We can use these constants in trigonometric calculations and also in scientific computing. Further, you can get a list of all constants defined in the math package of the go standard library from the documentation.
Basic Math functions
We have some quite basic and fundamental functions in the math package that can be used commonly in many programs. Let's take a look at a few of them.
- Abs :parameters (float64) , returns float64
As the name suggest, the Abs it returns the absolute result of a numbers. It takes a parameter as a float64 value and returns the absolute value of the provided number as a float64
number.
package main import ( "fmt" "math" ) func main() { a := 45 b := 100 diff := a - b fmt.Println(diff) absolute_diff := math.Abs(float64(a) - float64(b)) fmt.Println(absolute_diff) }
$ go run basic-functions/main.go -55 55
As, we can see the Abs
function takes in a float64 value and returns a absolute value of the given number that too a float64
value. We need to cast the numbers a
and b
into float64
as we have not provided the initial values and so the compiler has assigned the type to them as int
.
Type Casting
We can caste a type into other by using the variable around the type name as type_name(variable)
. In the above example we have converted the int
value 45
into a float64
as float64(45)
which again yields 45
but as a float64 type.
foo := 77 fmt.Printf("Type of foo = %T \n", foo) fmt.Println("foo = ", int(foo)) fmt.Println("String Cast: ", string(foo)) fmt.Println("Float Cast: ", float64(foo))
Though not every type cannot be casted into due to quite oblivious reasons, for instance 77
or any other integer value (except for 0 or 1) cannot be converted into boolean value.
Hello Gopher! Just a small note, the math package almost deals with float64 types rather than int to avoid backwards compatibility to perform operations on floating point values which can be casted into integers rather than defining separate functions for decimal values and integers.
- Min/Max: parameters(float64) , returns float64
We can get the minimum and maximum value of the two numbers provided to the function.
var float64 a = 120 var float64 b = 54 minimum := math.Min(float64(a), float64(b)) maximum := math.Max(float64(a), float64(b)) fmt.Printf("Min of %v and %v is %v \n", a, b, minimum) fmt.Printf("Max of %v and %v is %v \n", a, b, maximum)
$ go run basic-functions/main.go Min of 120 and 54 is 54 Max of 120 and 54 is 120
- Pow : parameters(float64, float64) , returns float64
- Pow10: parameters(int) , returns float64
The Pow function is used to get the exponential result of the base number. So, if we provide the values x and y, we would get the result as the number x raised to y.
var x float64 = 3 var y float64 = 4 z := math.Pow(x, y) z10 := math.Pow10(int(x)) fmt.Println("X ^ Y = ", z) fmt.Println("10 ^ X = ", z10)
$ go run basic-functions/main.go X ^ Y = 81 10 ^ X = 1000
We also have the Pow10 function which works just like the pow function except the x value is 10 and we don't have to provide it, there is just one parameter as a integer which returns a float64 value.
- Sqrt: parameters(float64) , returns float64
The Sqrt function as the name suggest, it is used to get the square root value of a floating point value which returns a float64 value.
var k float64 = 125 sqrt_of_k := math.Sqrt(k) cbrt_of_k := math.Cbrt(k) fmt.Printf("Square root of %v = %v \n", k, sqrt_of_k) fmt.Printf("Cube root of %v = %v \n", k, cbrt_of_k)
$ go run basic-functions/main.go Square root of 125 = 11.180339887498949 Cube root of 125 = 5
- Trunc: parameters(float64) , returns float64
The Truncate function provides the way to round off a decimal value(float64) to an integer but it returns a value in float64
.
var p float64 = 445.235 trunc_p := math.Trunc(p) fmt.Printf("Truncated value of %v = %v \n", p, trunc_p) p = 123.678 trunc_p = math.Trunc(p) fmt.Printf("Truncated value of %v = %v \n", p, trunc_p)
$ go run basic-functions/main.go Truncated value of 445.235 = 445 Truncated value of 123.678 = 123
- Ceil : parameters(float64) , returns float64
We also can use the Ceil function to roud up the value to the next integer value but the value is returned as float64
.
var c float64 = 33.25 ceil_c := math.Ceil(c) fmt.Printf("Ceiled value of %v = %v \n", c, ceil_c) c = 134.78 ceil_c = math.Ceil(c) fmt.Printf("Ceiled value of %v = %v \n", c, ceil_c)
$ go run basic-functions/main.go Ceiled value of 33.25 = 34 Ceiled value of 134.78 = 135
- Trigonometric Functions
Trigonometric functions are quite helpful that can help in intense mathematical computations in backend projects or precision dependent projects. We have functions Sin, Cos, SinCos, Tan, hyperbolic functions in Trigonometric functions like Sinh, Cosh, Tanh, and Inverse Trigonometric functions like Asin, Asinh, etc.
- Sin: parameters(float64) , returns float64
package main import ( "fmt" "math" ) func main() { // basic trigonometric functions var x float64 = math.Pi / 2 sinx := math.Sin(x) cosx := math.Cos(x) tanx := math.Tan(x) fmt.Printf("Sin(%v) = %v \n", x, sinx) fmt.Printf("Cos(%v) = %v \n", x, cosx) fmt.Printf("Tan(%v) = %v \n", x, tanx) // hyperbolic trigonometric functions var h float64 = math.Pi / 2 sinh := math.Sinh(h) cosh := math.Cosh(h) tanh := math.Tanh(h) fmt.Printf("Sinh(%v) = %v \n", h, sinh) fmt.Printf("Cosh(%v) = %v \n", h, cosh) fmt.Printf("Tanh(%v) = %v \n", h, tanh) // Inverse Trigonometric functions var y float64 = -1 arc_sin := math.Asin(y) // -pi/2 radians or 90 degrees arc_cos := math.Acos(y) // pi randians or 180 degrees arc_tan := math.Atan(y) fmt.Printf("Sin^-1(%v) = %v \n", y, arc_sin) fmt.Printf("Cos^-1(%v) = %v \n", y, arc_cos) fmt.Printf("Tan^-1(%v) = %v \n", y, arc_tan)
$ go run basic-functions/trignometric.go Sin(1.5707963267948966) = 1 Cos(1.5707963267948966) = 6.123233995736757e-17 Tan(1.5707963267948966) = 1.6331239353195392e+16 Sinh(1.5707963267948966) = 2.3012989023072947 Cosh(1.5707963267948966) = 2.5091784786580567 Tanh(1.5707963267948966) = 0.9171523356672744 Sin^-1(-1) = -1.5707963267948966 Cos^-1(-1) = 3.141592653589793 Tan^-1(-1) = -0.7853981633974483
Here we can see that the functions are working fine and giving a decently precise value. This might be enough for simple and smaller projects, though for higher precision and accuracy areas, other computations and programming is required to compute the values.
- Exponential and Logarithmic Functions
We also have the exponential and logarithmic functions defined in the math package to leverage computations realted to formulae that deal with logarithmic or exponential calculations.
- Exp : parameters(flaot64) , returns float64
- Exp2 : parameters(flaot64) , returns float64
package main import ( "fmt" "math" ) func main() { // exponential function var x float64 = 2 y := math.Exp(x) fmt.Println("e^x = ", y) var n float64 = 3.5 y = math.Exp2(n) fmt.Println("2^n = ", y) // Logarithmic function y = math.Log(x) fmt.Println("natural log x = ", y) n = 128 y = math.Log2(n) fmt.Println("Log2 of 100 = ", y) }
$ go run basic-functions/expo_log.go e^x = 7.38905609893065 2^n = 11.31370849898476 natural log x = 0.6931471805599453 Log2 of 100 = 7
Here, we have exponential functions such as e^x
and 2^n
which might be useful in some common programming calculations. Also the logarithmic functions like log x
which is natural log of x(base e), and log2 n
which is logn to the base 2.
The Random package
The random
sub-package in golang provides some great tools for working with random numbers and generating them. It provides exhaustive list of functions and types that help in generating pseudo random numbers.
- Int : parameters() , returns int
- Intn : parameters( int ) , returns int
package main import ( "fmt" "math/rand" ) func main() { // random integer generation x := rand.Int() fmt.Println(x) // random number generation till range for i := 0; i < 5; i++ { y := rand.Intn(10) fmt.Println(y) } }
$ go run basic-functions/rand.go 5577006791947779410 7 7 9 1 8
In the above example, we have used the Int function in the random sub-package of the math package which generates a pseudo random integer of the range dependent on the system architecture generally int32
or int64
. We get a huge number which is pseudo random i.e. not truly random. If you try to execute the program a couple of time, you would notice the number remains the same and we are calling it random? Well we need to dive into random numbers and seeding for a different part of the series for sure.
The Intn function also generates a pseudo random number but this time, we define the range of the upper boundary to generate them. It is not inclusive of the number provided i.e. we have provide the value 10
so the number 10
is not included in the range. It's called half open interval. It starts from 0 so the range becomes mathematically [0, n)
if n is the number provided to the Intn function.
The Bits package
We also have a bit sub-package in the math package of the go standard library. This sub package is used for working around with bit manipulation and operations at the binary level. This is quite helpful in competitive programming , also in understanding the basics of data structures and fundamentals in computer science.
- Add : parameters(uint, uint, uint) , returns uint, uint
- Len : parameters(uint) , returns int
- OnesCount : parameters(uint) , returns int
package main import ( "fmt" "math/bits" ) func main() { s, c := bits.Add(0, 9, 1) fmt.Printf("Sum = %d \nCarry = %d \n", s, c) // (45) in decimal = (1 0 1 1 0 1) in binary var n uint = 45 length := bits.Len(n) ones_in_45 := bits.OnesCount(n) fmt.Printf("Minimum bits required to represent 45 = %d \n", length) fmt.Printf("Set Bits in 45 = %d \n", ones_in_45) }
$ go run basic-functions/bit.go Sum = 10 Carry = 0 Minimum bits required to represent 45 = 6 Set Bits in 45 = 4
Here, in the above example, we have used the bits sub pacakge in the math package, the Add function allows us to provide the two numbers and a carry bit on which it returns two values the sum and the carry. The sum is defined as the summation of x + y + carry
the two numbers and the carry bit. The carry bit needs to be either 0 or 1.
Also the value provided the function i.e. x and y
need to be unsigned uint
iorder to work with bits.
We also have the Len function which returns the maximum number of bits required to represent the provided unsigned integer. We have used 45 which is equivalent to 10110
and hence the function returns 6
as teh number of bits. The OnesCount Function is also similar but it returns the number of set bits(the 1
bit) in the number provided to it.
We'll see this sub package in a separate section of its own. Bits is really a great pacakge to work with bits and low level manipulation of numbers in Golang.
The Complex package
The complex subpackage is really specific to the operation to the complex numbers and its operations. Using complex numbers with basic operations and trigonometric functions are provided in the package.
package main import ( "fmt" "math/cmplx" ) func main() { x := complex(5, 8) y := complex(3, 4) mod_x := cmplx.Abs(x) mod_y := cmplx.Abs(y) conj_x := cmplx.Conj(x) phase_x := cmplx.Phase(x) mod, phase := cmplx.Polar(x) fmt.Println("x = ", x) fmt.Println("Modulus of x = ", mod_x) fmt.Println("Modulus of y = ", mod_y) fmt.Println("Conjugate of x = ", conj_x) fmt.Println("Phase of x = ", phase_x) fmt.Printf("Polar Form : %v, %v\n", mod, phase) }
$ go run basic-functions/complex.go x = (5+8i) Modulus of x = 9.433981132056603 Modulus of y = 5 Conjugate of x = (5-8i) Phase of x = 1.0121970114513341 Polar Form : 9.433981132056603, 1.0121970114513341
We have used the complex function to create complex numbers. The cmplx
subpackage in the math package provides many functions to play with trignometric and simple operations with complex numbers. The Abs function is used to get the modulus of the provided complex number. The modulus is calculated with sqrt(x^2 + y^2)
, this gives the magnitude of the complex number. Here, we get the modulus as 9.43
as sqrt(25 + 64)
for the complex number 5+8i
. Also, for 3+4i
the modulus becomes sqrt(9+16)
which turns out to be 5
. The Conjugate function is used to get the conjugate of the provided complex number.
Also the phase or the Argument of the complex number can be obtained with the Phase function. The phase is caluculated by the formula tan^-1 (y/x)
but the angle is returned in randians. So for x = 5+8i
the argument/Phase becomes tan^-1( 8/5)
which is 57.995 degrees
or 1.012 radians
.
We have the Polar function which gives the polar form of the complex number i.e. (modulus r, phase theta)
So this function returns two values the modulus and the argument/phase of the complex number. We have already calcualted both the values but this functions gets both of them in a single function. Quite neat, we can even ignore one value after the return of the function by using the ignore operator _, phase := cmplx.Polar(5+7i)
to only care and get the phase/argument of the complex number or modulus, _ := cmplx.Polar(5+7i)
to get the modulus from the complex number.
So that's some basic operations on complex numbers, this might have very few use cases but it's still quite useful when needed.
That's it from this part. Reference for all the code examples and commands can be found in the 100 days of Golang GitHub repository.
Conclusion
So from this section we were able to get a bit deeper introduction to the math
package in golang's standard library. We covered some few important functions and constants in the main math package along with the glimpse of other subpackages like rand
, cmplx
and bits
. We didn't get too much in detail with those sub packages as they can be explored on a separate section of their own. Hopefully, you have got a godd overview of the math package in golang which again is really important aspect in programming.
Thank you for reading. If you have any questions or feedback, please let me know in the comments or on social handles. Happy Coding :)