Skip to content
Snippets Groups Projects
Select Git revision
  • 08791deabc9f1c51baf4ad7c5e5f9d85eddf6b6b
  • master default protected
  • termui_test
3 results

pi.go

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    pi.go 2.89 KiB
    // 29 april 2021
    // If I get time, it would be fun to do the second uebung in go.
    // For the sake of speed, we can do all the numbers at once, put
    // them in arrays, rather than doing i/o on every step.
    
    package main
    
    import (
    	"errors"
    	"flag"
    	"fmt"
    	"math/rand"
    	"os"
    	"strconv"
    
    	"gonum.org/v1/plot"
    	"gonum.org/v1/plot/vg"
    )
    
    const (
    	exitSuccess = iota
    	exitFailure
    )
    
    // usage prints out anything the caller gives us then bails.
    func usage(e string) {
    	u := "usage: pi seed nsteps nstep_nprint"
    	fmt.Fprintln(os.Stderr, e+"\n"+u)
    	os.Exit(exitFailure)
    }
    
    // getnums does the work of filling out the arrays of results
    func getnums(cmdArgs cmdArgs) {
    	rand.Seed(cmdArgs.seed)
    	inCnt := make([]uint32, cmdArgs.nstep)
    	{ // The braces limit the lifetime of inPoint, to save a bit of memory
    		inPoint := make([]bool, cmdArgs.nstep)
    		for i := 0; i < cmdArgs.nstep; i++ { // Fill out the array with true/false
    			x := rand.Float32()
    			y := rand.Float32()
    			if (x*x + y*y) <= 1 {
    				inPoint[i] = true
    			}
    		}
    		if inPoint[0] {
    			inCnt[0] = 1
    		}
    		for i := 1; i < cmdArgs.nstep; i++ {
    			inCnt[i] = inCnt[i-1]
    			if inPoint[i] {
    				inCnt[i]++
    			}
    		}
    	}
    	for i := 0; i < cmdArgs.nstep; i = i + cmdArgs.nstepPrint {
    		pi := 4 * float32(inCnt[i]) / float32(i+1)
    		fmt.Println(i, inCnt[i], pi)
    	}
    }
    
    // doplot makes a primitive plot without any interesting options
    func doplot(plotName string) error {
    	p := plot.New()
    	p.Title.Text = "ugly plot"
    	if err := p.Save(15*vg.Centimeter, 10*vg.Centimeter, plotName); err != nil {
    		return err
    	}
    	return nil
    }
    
    type cmdArgs struct {
    	seed              int64
    	nstep, nstepPrint int
    	plotName          string
    	doStdout          bool // don't print boring table
    }
    
    // cmdline gets our command line arguments and maybe a flag or two.
    func cmdline(cmdArgs *cmdArgs) error {
    	var err error
    	var suppress bool
    	flag.StringVar(&cmdArgs.plotName, "p", "", "Plot filename")
    	flag.BoolVar(&suppress, "s", false, "Suppress stdout")
    	flag.Parse()
    	if flag.NArg() != 3 {
    		return errors.New("Wrong number of command line args")
    	}
    	a := flag.Args() // not necessary, but makes error messages cleaner
    	if cmdArgs.seed, err = strconv.ParseInt(a[0], 10, 64); err != nil {
    		return errors.New("Could not convert first arg " + a[1] + " to int")
    	}
    	if cmdArgs.nstep, err = strconv.Atoi(a[1]); err != nil {
    		return errors.New("Could not convert second arg " + a[2] + " to int")
    	}
    	if cmdArgs.nstepPrint, err = strconv.Atoi(a[2]); err != nil {
    		return errors.New("Could not convert third arg " + a[3] + " to int")
    	}
    	cmdArgs.doStdout = true
    	if suppress {
    		cmdArgs.doStdout = false
    	}
    	return nil
    }
    
    // main. The rules say ./pi seed nsteps nstep_print
    func main() {
    	var cmdArgs cmdArgs
    	if err := cmdline(&cmdArgs); err != nil {
    		usage(err.Error())
    	}
    	fmt.Println("doStdout is", cmdArgs.doStdout)
    	getnums(cmdArgs)
    	if err := doplot(cmdArgs.plotName); err != nil {
    		fmt.Fprintln(os.Stderr, err)
    		os.Exit(exitFailure)
    	}
    }