// 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) } }