Skip to main content

Golang Refresher :: math & os

Guangzhou, China

The Go Standard Library

math|random :: Mathematical operations and random numbers

Basics

package main

import (
"fmt"
"math"
)

func main() {

float := 997.783

// Print Pi
fmt.Println(math.Pi)
fmt.Println(math.E)

// Floor and Ceiling
fmt.Println(math.Floor(float))
fmt.Println(math.Ceil(math.E))

// Truncate to return integer value
fmt.Printf("%.2f\n", math.Trunc(math.Pi))

// Min-Max to determin the biggest/smallest member
fmt.Println(math.Max(math.Pi, math.Ln2))
fmt.Println(math.Min(math.Pi, math.Ln2))

// Modulo - the mod operator is for floats
fmt.Println(17 % 5)
fmt.Println(math.Mod(17.0, 5.0))

// Round and RoundToEven - to closes integer
fmt.Printf("%.1f\n", math.Round(10.5))
fmt.Printf("%.1f\n", math.Round(-10.5))

fmt.Printf("%.1f\n", math.RoundToEven(10.5))
fmt.Printf("%.1f\n", math.RoundToEven(11.5))

}
go run .\main.go

3.141592653589793
2.718281828459045
997
3
3.00
3.141592653589793
0.6931471805599453
2
2
11.0
-11.0
0.0
10.0
12.0

Calculations

package main

import (
"fmt"
"math"
)

func main() {

x := 10.0

// Absolute value
fmt.Println(math.Abs(x), math.Abs(-x))

// Power (x^y) and Exp (e^x)
fmt.Println(math.Pow(x, 2.0))
fmt.Println(math.Exp(x))

// Trigonometry
fmt.Println(math.Cos(math.Pi))
fmt.Println(math.Sin(2 * math.Pi))
fmt.Println(math.Tan(math.Pi / 2))

// Square and cube roots
fmt.Println(math.Sqrt(144))
fmt.Println(math.Cbrt(125))

// Hypothenuse
fmt.Println(math.Hypot(30, 40))
}
go run .\main.go
10 10
100
22026.465794806718
-1
-2.449293598294703e-16
1.6331239353195392e+16
12
5
50

Random

Package rand implements pseudo-random number generators unsuitable for security-sensitive work.

Random numbers are generated by a Source. Top-level functions, such as Float64 and Int, use a default shared Source that produces a deterministic sequence of values each time a program is run. Use the Seed function to initialize the default Source if different behavior is required for each run. The default Source is safe for concurrent use by multiple goroutines, but Sources created by NewSource are not.

This package's outputs might be easily predictable regardless of how it's seeded. For random numbers suitable for security-sensitive work, see the crypto/rand package.

package main

import (
"fmt"
"math/rand"
"time"
)

func main() {

// Random seed as a starting point for the generator
rand.Seed(time.Now().UnixNano())

// Generate random integers
fmt.Println(rand.Int())
fmt.Println(rand.Intn(5))

// Generate random floats
fmt.Println(rand.Float32())
fmt.Println(rand.Float64())

// Generate random ints between a and b
const a, b = 1, 10
for i := 0; i<5; i++ {
n := a + rand.Intn(b-a+1)
fmt.Print(n, " " )
}
fmt.Println()

// Generate random uppercase character
for i := 0; i<5; i++ {
c := string('A' + rune(rand.Intn('Z'-'A'+1)))
fmt.Printf("%s", c)
}
fmt.Println()


// Permutations - randomly select from array
s := []string{"Tomcat", "Fulcrum", "Viper", "Frogfoot", "Apache", "Hind", "Bone"}
// Reorder slice randomly
indexes := rand.Perm(len(s))
fmt.Println(indexes)
// Print index in the order that was generated
for i := 0; i<len(indexes); i++ {
fmt.Println(s[indexes[i]])
}
}
go run .\main.go

7000560910936529311
2
0.5594295
0.03983504194598849
6 5 2 10 9
RVFXJ
[0 3 2 1 5 4 6]
Tomcat
Frogfoot
Viper
Fulcrum
Hind
Apache
Bone

Random Strings

package main

import (
"fmt"
"math/rand"
"strings"
"time"
)

func main() {

// Random seed as a starting point for the generator
rand.Seed(time.Now().UnixNano())

// Shuffle
const numstring = "Tomcat Fulcrum Viper Frogfoot Apache Hind Bone"
// split into array of words
words := strings.Fields(numstring)
// generate new order
rand.Shuffle(len(words), func(i,j int) {
// make words swap places
words[i], words[j] = words[j], words[i]
})
fmt.Println(words)


// Random Strings
const uppercase = "QWERTYUIOOPASDFGHJKLZXCVBNM"
const lowercase = "qwertyuiopasdfghjklzxcvbnm"
const digits = "1234567890"
const special = "!@#$%^&*()_+<>?:;/.|,']"
const allchars = uppercase + lowercase + digits + special

// Generate a 10 digit password
var sb strings.Builder
length := 10

for i := 0; i < length; i++ {
sb.WriteRune(rune(allchars[rand.Intn(len(allchars))]))
}
fmt.Println("String result: ", sb.String())

// Generate a 10 digit password that !must contain all types of characters
// Create a buffer that takes 1 random character from all sets
buf := make([]byte, length)
buf[0] = uppercase[rand.Intn(len(uppercase))]
buf[1] = lowercase[rand.Intn(len(lowercase))]
buf[2] = digits[rand.Intn(len(digits))]
buf[3] = special[rand.Intn(len(special))]
// Fill up the rest of the buffer with random `allchars`
for i := 4; i < length; i++ {
buf[i] = allchars[rand.Intn(len(allchars))]
}
// Make sure that the position of the first 4 chars is shuffled
rand.Shuffle(len(buf), func(i, j int) {
// make characters swap places
buf[i], buf[j] = buf[j], buf[i]
})
fmt.Println("String result: ", string(buf))

}
go run .\main2.go

[Viper Frogfoot Bone Hind Tomcat Fulcrum Apache]
String result: 8m8ja#$)ip
String result: ]mVm|5pPL%

os|ioutil :: Files and directories

Package os provides a platform-independent interface to operating system functionality. The design is Unix-like, although the error handling is Go-like; failing calls return values of type error rather than error numbers. Often, more information is available within the error. For example, if a call that takes a file name fails, such as Open or Stat, the error will include the failing file name when printed and will be of type *PathError, which may be unpacked for more information.

The os interface is intended to be uniform across all operating systems. Features not generally available appear in the system-specific package syscall.

Here is a simple example, opening a file and reading some of it.

File info

package main

import (
"fmt"
"os"
)

// Make sure a file is present
func checkFileExists(filePath string) bool {
if _, err := os.Stat(filePath); err !=nil {
if os.IsNotExist(err) {
return false
}
}
return true
}

func main() {

// Check file
exists := checkFileExists("text.txt")
fmt.Println("Is text.txt present:", exists)

// Get file stats
stats, err := os.Stat("text.txt")
if err != nil {
panic(err)
}
// Print modification time
fmt.Println("Modification time:", stats.ModTime())
// Print filesize
fmt.Println("File size:", stats.Size(), "bytes")
// Check file permissions
fmt.Println("File Mode:", stats.Mode())
// Check if it is a directory
fmt.Println("Is it a directory:", stats.IsDir())
// Check if it is a file
fmode := stats.Mode()
if fmode.IsRegular() {
fmt.Println("This is a file not a symlink")
}
}
go run .\main.go
Is text.txt present: true
Modification time: 2021-10-03 20:49:47.2424559 +0800 CST
File size: 5 bytes
File Mode: -rw-rw-rw-
Is it a directory: false
This is a file not a symlink

Write File

package main

import (
"fmt"
"io/ioutil"
"os"
)

// Make sure a file is present
func handleErr(err error) {
if err !=nil {
panic(err)
}
}

// Check if file is already present
func checkFileExists(filePath string) bool {
if _, err := os.Stat(filePath); err !=nil {
if os.IsNotExist(err) {
return false
}
}
return true
}

// Write data to file with `os`
func writeFileData() {
// Create new file
f, err := os.Create("os_create.txt")
handleErr(err)
// Close file afterwards
defer f.Close()
// Print name of generated file
fmt.Println("File generated:", f.Name())
// Write string to file
f.WriteString("This is some text\n")
// Write bytes to file
//data2 := []byte("This some more text\n")
data2 := []byte{'v', 'w', 'x', 'y', 'z', '\n'}
f.Write(data2)
// Sync everything to disk
f.Sync()
}

// Append Data to file
func appendFileData(fname string, data string) {
f, err := os.OpenFile(fname, os.O_APPEND|os.O_WRONLY, 0644)
handleErr(err)
defer f.Close()

_, err = f.WriteString(data)
}

func main() {

// Write data to file with `ioutil`
// But skip if file is already present
if !checkFileExists("datafile.txt") {
data1 := []byte("Hi!\n")
ioutil.WriteFile("datafile.txt", data1, 0644)
}

// Append data to file
appendFileData("datafile.txt", "APPENDIX!")

// Write data to file with `os`
// But if file already exists
if !checkFileExists("os_create.txt") {
writeFileData()
} else {
// Trim file data to 22 bytes
os.Truncate("os_create.txt", 22)
fmt.Println("Log file has been truncated")
}

}
go run .\main.go
File generated: os_create.txt

go run .\main.go
Log file has been truncated

Read File

package main

import (
"fmt"
"io"
"io/ioutil"
"os"
// "path/filepath"
)

// Handle error
func handleErr(err error) {
if err !=nil {
panic(err)
}
}
// Get length of file
func getFileLength(filepath string) int64 {
f, err := os.Stat(filepath)
handleErr(err)
return f.Size()
}

func main() {

// Get length of file
length := getFileLength("text.txt")
fmt.Println("File length:", length)

// Read entire file and print
content, err := ioutil.ReadFile("text.txt")
handleErr(err)
fmt.Println("Entire Content:\n", string(content))
fmt.Println()

// Read file in chunks of 20 bytes
// open the file
const BuffSize = 20
f, _ := os.Open("text.txt")
defer f.Close()
// Create buffer with size BuffSize
b1 := make([]byte, BuffSize)
fmt.Println("Content read in 20bytes chunks")
for {
n, err := f.Read(b1)
// Continue looping
if err != nil {
// Until you reach the end of file
if err != io.EOF {
// If error other than EOF, panic
handleErr(err)
}
// Break
break
}

fmt.Println("Bytes read:", n)
fmt.Println("Content:", string(b1[:n]))
}

// Read from a specific position
// Create buffer to read 10 bytes
b2 := make([]byte, 10)
// Read the last 10 bytes from open file
_, err = f.ReadAt(b2,length-int64(len(b2)))
handleErr(err)
fmt.Println("Last 10bytes of file:", string(b2))

}
go run .\main.go
File length: 243
Entire Content:
If you like piña coladas
And gettin′ caught in the rain
If you're not into yoga
If you have half a brain
If you like makin' love at midnight
In the dunes on the cape
Then I′m the love that you′ve looked for
Write to me and escape

Content read in 20bytes chunks
Bytes read: 20
Content: If you like piña co
Bytes read: 20
Content: ladas
And gettin′
Bytes read: 20
Content: caught in the rain
Bytes read: 20
Content:
If you're not into
Bytes read: 20
Content: yoga
If you have ha
Bytes read: 20
Content: lf a brain
If you l
Bytes read: 20
Content: ike makin' love at m
Bytes read: 20
Content: idnight
In the dune
Bytes read: 20
Content: s on the cape
Then
Bytes read: 20
Content: I′m the love that
Bytes read: 20
Content: you′ve looked for
Bytes read: 20
Content:
Write to me and esc
Bytes read: 3
Content: ape

Last 10bytes of file: and escape

Directories

package main

import (
"fmt"
"io/ioutil"
"os"
)

// Handle error
func handleErr(err error) {
if err !=nil {
panic(err)
}
}

func main() {

// Create a directory
os.Mkdir("newdir", os.ModePerm)

// Create nested dir
os.MkdirAll("newdir2/surprise", os.ModePerm)

// Remove a directory
defer os.Remove("newdir")

// Remove directory and children
defer os.RemoveAll("newdir2")

// Read what the working directory is
dir, _ := os.Getwd()
fmt.Println("Current working dir:", dir)

// Read the directory of the current process
exedir, _ := os.Executable()
fmt.Println("Process dir:", exedir)

// Read and list content of current directory
content, _ := ioutil.ReadDir(".")
fmt.Println("Dir content:", content)
for _, fi := range content {
fmt.Println(fi.Name(), fi.IsDir())
}
}
go run .\main.go
Current working dir: E:\golang-refresher\files\Directories
Process dir: C:\Users\INSTAR\AppData\Local\Temp\go-build1247541399\b001\exe\main.exe
Dir content: [0xc0000e0000 0xc0000e0070 0xc0000e00e0 0xc0000e0150]
main.go false
newdir true
newdir2 true
text.txt false

Temporary Data

package main

import (
"fmt"
"io/ioutil"
"os"
)

// Handle error
func handleErr(err error) {
if err !=nil {
panic(err)
}
}

func main() {

// Get default temp dir
tempPath := os.TempDir()
fmt.Println("Default temp dir:", tempPath)

// Create a temporary file

// Create temp data
tempData := []byte("Some temp data")

// Generate file with random filename
tmpFile, err := ioutil.TempFile(tempPath, "temp_*.txt")
if err != nil {
panic(err)
}

// Write temp data to file
if _, err := tmpFile.Write(tempData); err !=nil {
panic(err)
}

// Read and print tempFile content
data, _ := ioutil.ReadFile(tmpFile.Name())
fmt.Printf("%s\n", data)

// Remove temp file

// Check if it is there
fmt.Println("Remove tempfile:", tmpFile.Name())
defer os.Remove(tmpFile.Name())


// Create a randomly named temp dir inside the default tmp directory
tmpDir, err := ioutil.TempDir("", "temp_*")
if err != nil {
panic(err)
}
// Remove temp dir
fmt.Println("Remove temp dir:", tmpDir)
defer os.RemoveAll(tmpDir)

}
go run .\main.go
Default temp dir: C:\Users\INSTAR\AppData\Local\Temp
Some temp data
Remove tempfile: C:\Users\INSTAR\AppData\Local\Temp\temp_2823599238.txt
Remove temp dir: C:\Users\INSTAR\AppData\Local\Temp\temp_596935459