Skip to content
Snippets Groups Projects
Select Git revision
  • 470e32ce732fe604a9cd55fb79fb5deb7ed8971e
  • master default protected
  • devel
  • adaptive_step_size
4 results

ackwork_test.go

  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    pi.go 3.67 KiB
    // 29 april 2021
    // An example for the second Uebung in Struktur und Simulation.
    // 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. This is actually
    // necessary if we want to make plots. We have to store all the points.
    // The plotting library I used does not draw to the screen. Bummer. One could
    // use the canvas in vggio, although that pulls in all of the fyne library.
    // There is an egregious bug in the clipping of lines in plotter, so do
    // not use it. Use a scatter plot.
    
    package main
    
    import (
    	"errors"
    	"flag"
    	"fmt"
    	"math"
    	"math/rand"
    	"os"
    	"strconv"
    )
    
    const (
    	exitSuccess = iota
    	exitFailure
    )
    
    // usage prints out anything the caller gives us then bails.
    func usage(e string) {
    	u := "usage: pi [flags] seed nsteps nstep_nprint"
    	if e != "" {
    		fmt.Fprintln(os.Stderr, e+"\n"+u)
    	}
    	flag.Usage()
    	os.Exit(exitFailure)
    }
    
    // getnums does the work of filling out the arrays of results
    func getnums(cmdArgs cmdArgs) ([]float32, []float32) {
    	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 // avoid divide by zero errors in loop
    		}
    		for i := 1; i < cmdArgs.nstep; i++ {
    			inCnt[i] = inCnt[i-1]
    			if inPoint[i] {
    				inCnt[i]++
    			}
    		}
    	} // We have the counts. Now calculate the errors and standard error
    	pi := make([]float32, cmdArgs.nstep)     // estimated pi
    	stdErr := make([]float32, cmdArgs.nstep) // standard error
    
    	for i := range inCnt {
    		ptmp := float64(inCnt[i]) / float64(i+1)
    		pi[i] = float32(4 * ptmp)
    		stdErr[i] = float32(4 * math.Sqrt((ptmp*(1-ptmp))/(float64(i+1))))
    	}
    	return pi, stdErr
    }
    
    // wrtTable prints out the table, as per the Uebung instructions
    func wrtTable(cmdArgs cmdArgs, pi, stdErr []float32) {
    	fmt.Printf("%8s %7s %7s %7s\n", "step", "pi", "err", "stderr")
    	for i := 0; i < cmdArgs.nstep; i = i + cmdArgs.nstepPrint {
    		e := math.Pi - pi[i]
    		fmt.Printf("%8d %.5f %.5f %.5f\n", i+1, pi[i], e, stdErr[i])
    	}
    }
    
    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", "", "filename to Plot to. No name means no plofile")
    	flag.BoolVar(&suppress, "s", false, "Suppress stdout - the long table of numbers")
    	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
    }
    
    func main() {
    	var cmdArgs cmdArgs
    	if err := cmdline(&cmdArgs); err != nil {
    		usage(err.Error())
    	}
    	pi, stdErr := getnums(cmdArgs)
    	if cmdArgs.doStdout {
    		wrtTable(cmdArgs, pi, stdErr)
    	}
    	if err := doplot(pi, stdErr, cmdArgs.plotName); err != nil {
    		fmt.Fprintln(os.Stderr, err)
    		os.Exit(exitFailure)
    	}
    	os.Exit(exitSuccess)
    }