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