From 110d6b6dc66d0b2127f3a4d59e585369d1804aff Mon Sep 17 00:00:00 2001 From: NunoSempere Date: Sun, 9 Jun 2024 15:15:53 +0200 Subject: [PATCH] f2 to f, f to f0 --- f.go | 309 +++++++++++++++++++++++++++++----------------------------- f0.go | 230 +++++++++++++++++++++++++++++++++++++++++++ f2.go | 225 ------------------------------------------ 3 files changed, 382 insertions(+), 382 deletions(-) create mode 100644 f0.go delete mode 100644 f2.go diff --git a/f.go b/f.go index 6287fdf..cc590a9 100644 --- a/f.go +++ b/f.go @@ -2,6 +2,7 @@ package main import ( "bufio" + "errors" "fmt" "math" "os" @@ -10,37 +11,110 @@ import ( ) const NORMAL90CONFIDENCE = 1.6448536269514727 +const general_err_msg = "Valid inputs: 2 || * 2 || / 2 || 2 20 || * 2 20 || / 2 20 || clean || =: var || op var || clean || help || debug || exit" -func boundsToLogParams(low float64, high float64) (float64, float64) { - loglow := math.Log(low) - loghigh := math.Log(high) - logmean := (loghigh + loglow) / 2.0 - logstd := (loghigh - loglow) / (2.0 * NORMAL90CONFIDENCE) - return logmean, logstd +// Actually, I should look up how do do a) enums in go, b) union types +type Lognormal struct { + low float64 + high float64 +} + +type Dist struct { + Type string + Lognormal Lognormal + Samples []float64 +} + +// Parse line into Distribution +func parseLineErr(err_msg string) (string, Dist, error) { + fmt.Println(general_err_msg) + fmt.Println(err_msg) + return "", Dist{}, errors.New(err_msg) +} +func parseLine(line string, vars map[string]Dist) (string, Dist, error) { + + words := strings.Split(strings.TrimSpace(line), " ") + op := "" + var dist Dist + + switch words[0] { + case "*": + op = "*" + words = words[1:] + case "/": + op = "/" + words = words[1:] + case "+": + return parseLineErr("+ operation not implemented yet") + case "-": + return parseLineErr("- operation not implemented yet") + default: + op = "*" // later, change the below to + } + + switch len(words) { + case 0: + return parseLineErr("Operator must have operand; can't operate on nothing") + case 1: + var_word, var_word_exists := vars[words[0]] + single_float, err1 := strconv.ParseFloat(words[0], 64) + switch { + case var_word_exists: + dist = var_word + case err1 == nil: + dist = Dist{Type: "Lognormal", Lognormal: Lognormal{low: single_float, high: single_float}, Samples: nil} + case err1 != nil && !var_word_exists: + return parseLineErr("Trying to operate on a scalar, but scalar is neither a float nor an assigned variable") + } + case 2: + new_low, err1 := strconv.ParseFloat(words[0], 64) + new_high, err2 := strconv.ParseFloat(words[1], 64) + if err1 != nil || err2 != nil { + return parseLineErr("Trying to operate by a distribution, but distribution is not specified as two floats") + } + dist = Dist{Type: "Lognormal", Lognormal: Lognormal{low: new_low, high: new_high}, Samples: nil} + default: + return parseLineErr("Other input methods not implemented yet") + } + return op, dist, nil } -func multiplyLognormals(logmean1 float64, logstd1 float64, logmean2 float64, logstd2 float64) (float64, float64) { - return logmean1 + logmean2, math.Sqrt(logstd1*logstd1 + logstd2*logstd2) +// Join distributions +// Multiply lognormals + +func multiplyLogDists(l1 Lognormal, l2 Lognormal) Lognormal { + logmean1 := (math.Log(l1.high) + math.Log(l1.low)) / 2.0 + logstd1 := (math.Log(l1.high) - math.Log(l1.low)) / (2.0 * NORMAL90CONFIDENCE) + + logmean2 := (math.Log(l2.high) + math.Log(l2.low)) / 2.0 + logstd2 := (math.Log(l2.high) - math.Log(l2.low)) / (2.0 * NORMAL90CONFIDENCE) + + logmean_product := logmean1 + logmean2 + logstd_product := math.Sqrt(logstd1*logstd1 + logstd2*logstd2) + + h := logstd_product * NORMAL90CONFIDENCE + loglow := logmean_product - h + loghigh := logmean_product + h + return Lognormal{low: math.Exp(loglow), high: math.Exp(loghigh)} + } -func logParamsToBounds(logmean float64, logstd float64) (float64, float64) { - h := logstd * NORMAL90CONFIDENCE - loglow := logmean - h - loghigh := logmean + h - return math.Exp(loglow), math.Exp(loghigh) +func joinDists(old_dist Dist, new_dist Dist, op string) (Dist, error) { + switch { + case old_dist.Type == "Lognormal" && new_dist.Type == "Lognormal" && op == "*": + return Dist{Type: "Lognormal", Lognormal: multiplyLogDists(old_dist.Lognormal, new_dist.Lognormal), Samples: nil}, nil + case old_dist.Type == "Lognormal" && new_dist.Type == "Lognormal" && op == "/": + tmp_dist := Lognormal{low: 1.0 / new_dist.Lognormal.high, high: 1.0 / new_dist.Lognormal.low} + return Dist{Type: "Lognormal", Lognormal: multiplyLogDists(old_dist.Lognormal, tmp_dist), Samples: nil}, nil + default: + fmt.Printf("For now, can't do anything besides multiplying lognormals\n") + } + return old_dist, errors.New("Can't combine distributions in this way") } -func combineBounds(old_low, old_high, new_low, new_high float64) (float64, float64) { - logmean_old, logstd_old := boundsToLogParams(old_low, old_high) - logmean_new, logstd_new := boundsToLogParams(new_low, new_high) - - logmean_product, logstd_product := multiplyLognormals(logmean_old, logstd_old, logmean_new, logstd_new) - - return logParamsToBounds(logmean_product, logstd_product) -} - -func prettyPrintDist(low float64, high float64) { +/* Pretty print distributions */ +func prettyPrintLognormal(low float64, high float64) { // fmt.Printf("=> %.1f %.1f\n", low, high) fmt.Printf("=> ") switch { @@ -76,155 +150,76 @@ func prettyPrintDist(low float64, high float64) { // fmt.Printf("=> %.1f %.1f\n", low, high) } +func prettyPrintDist(dist Dist) { + if dist.Type == "Lognormal" { + prettyPrintLognormal(dist.Lognormal.low, dist.Lognormal.high) + } else { + fmt.Printf("%v", dist) + } +} + +/* Main event loop */ func main() { reader := bufio.NewReader(os.Stdin) - - var old_low, old_high float64 - var input string - var err1, err2 error - -InitialForLoop: - for { - input, _ = reader.ReadString('\n') - input = strings.TrimSpace(input) - words := strings.Split(input, " ") - - switch len(words) { - case 1: - single_float, err1 := strconv.ParseFloat(words[0], 64) - if err1 != nil { - fmt.Println("Trying to initialize with a scalar, but scalar is not a float") - continue InitialForLoop - } - old_low = single_float - old_high = single_float - case 2: - old_low, err1 = strconv.ParseFloat(words[0], 64) - old_high, err2 = strconv.ParseFloat(words[1], 64) - if err1 != nil || err2 != nil { - fmt.Println("Trying to initialize with a distribution, but distribution is not specified as two floats") - continue InitialForLoop - } - default: - fmt.Println("Please enter two floats separated by a space, like: 1 10") - continue InitialForLoop - } - if err1 != nil || err2 != nil { - fmt.Println("Please enter two floats separated by a space, like: 1 10") - continue - } - break - } - prettyPrintDist(old_low, old_high) - - error_msg_cont := "Valid inputs: 2 || * 2 || / 2 || 2 20 || * 2 20 || / 2 20 || i || e" + init_dist := Dist{Type: "Lognormal", Lognormal: Lognormal{low: 1, high: 1}, Samples: nil} // Could also just be a scalar + old_dist := init_dist + vars := make(map[string]Dist) + // Could eventually be a more complex struct with: + // { Dist, VariableMaps, ConfigParams } or smth EventForLoop: for { - input, _ = reader.ReadString('\n') + input, _ := reader.ReadString('\n') if strings.TrimSpace(input) == "" { continue EventForLoop } - words := strings.Split(strings.TrimSpace(input), " ") - var new_low, new_high float64 - - switch words[0] { - case "*": - switch len(words) { - case 1: - fmt.Println("Can't multiply by nothing") - fmt.Println(error_msg_cont) + { + words := strings.Split(strings.TrimSpace(input), " ") + switch { + case words[0] == "exit" || words[0] == "e": + break EventForLoop + case words[0] == "help" || words[0] == "h": + fmt.Println(general_err_msg) continue EventForLoop - case 2: - single_float, err1 := strconv.ParseFloat(words[1], 64) - if err1 != nil { - fmt.Println("Trying to multiply by a scalar, but scalar is not a float") - fmt.Println(error_msg_cont) - continue EventForLoop - } - new_low = single_float - new_high = single_float - case 3: - new_low, err1 = strconv.ParseFloat(words[1], 64) - new_high, err2 = strconv.ParseFloat(words[2], 64) - if err1 != nil || err2 != nil { - fmt.Println(error_msg_cont) - fmt.Println("Trying to multiply by a distribution, but distribution is not specified as two floats") - continue EventForLoop - } - default: - fmt.Println("Trying to multiply by something, but this something is neither a scalar nor a distribution") - fmt.Println(error_msg_cont) + case words[0] == "debug" || words[0] == "d": + fmt.Printf("Old dist: %v\n", old_dist) + fmt.Printf("Vars: %v\n", vars) continue EventForLoop - } - case "/": - switch len(words) { - case 1: - fmt.Println("Can't divide by nothing") - fmt.Println(error_msg_cont) + case words[0] == "=:" && len(words) == 2: + vars[words[1]] = old_dist + fmt.Printf("%s ", words[1]) + prettyPrintDist(old_dist) continue EventForLoop - case 2: - single_float, err1 := strconv.ParseFloat(words[1], 64) - if err1 != nil { - fmt.Println("Trying to divide by a scalar, but scalar is not a float") - fmt.Println(error_msg_cont) - continue EventForLoop - } - new_low = 1.0 / single_float - new_high = 1.0 / single_float - case 3: - new_low, err1 = strconv.ParseFloat(words[1], 64) - new_high, err2 = strconv.ParseFloat(words[2], 64) - if err1 != nil || err2 != nil { - fmt.Println("Trying to divide by a distribution, but distribution is not specified as two floats") - fmt.Println(error_msg_cont) - continue EventForLoop - } - tmp := new_low - new_low = 1.0 / new_high - new_high = 1.0 / tmp - default: - fmt.Println("Trying to divide by something, but this something is neither a scalar nor a distribution") - } - default: - switch len(words) { - case 0: + case words[0] == "." || words[0] == "clean" || words[0] == "c": + old_dist = init_dist + fmt.Println() continue EventForLoop - case 1: - switch words[0] { - case "i": - fmt.Printf("=> %.1f %.1f\n", old_low, old_high) - logmean_old, logstd_old := boundsToLogParams(old_low, old_high) - fmt.Printf("=> Lognormal, with logmean: %.1f, logstd: %.1f\n", logmean_old, logstd_old) - continue EventForLoop - case "e": - break EventForLoop - default: - single_float, err1 := strconv.ParseFloat(words[0], 64) - if err1 != nil { - fmt.Println("Unrecognized command") - fmt.Println(error_msg_cont) - continue EventForLoop - } - new_low = single_float - new_high = single_float - } - case 2: - new_low, err1 = strconv.ParseFloat(words[0], 64) - new_high, err2 = strconv.ParseFloat(words[1], 64) - if err1 != nil || err2 != nil { - fmt.Println("Trying to multiply by a distribution, but distribution is not specified as two floats") - fmt.Println(error_msg_cont) - continue EventForLoop - } - default: - fmt.Println("No operation takes more than 3 words") - fmt.Println(error_msg_cont) + case words[0] == "=." && len(words) == 2: + vars[words[1]] = old_dist + fmt.Printf("%s ", words[1]) + prettyPrintDist(old_dist) + old_dist = init_dist + fmt.Println() continue EventForLoop + // Other possible cases: + // Save to file + // Sample n samples + // Save stack to a variable? + // clean stack + // Define a function? No, too much of a nerdsnipea } } - old_low, old_high = combineBounds(old_low, old_high, new_low, new_high) - prettyPrintDist(old_low, old_high) + op, new_dist, err := parseLine(input, vars) + if err != nil { + continue EventForLoop + } + + joint_dist, err := joinDists(old_dist, new_dist, op) + if err != nil { + continue EventForLoop + } + old_dist = joint_dist + prettyPrintDist(old_dist) } } diff --git a/f0.go b/f0.go new file mode 100644 index 0000000..6287fdf --- /dev/null +++ b/f0.go @@ -0,0 +1,230 @@ +package main + +import ( + "bufio" + "fmt" + "math" + "os" + "strconv" + "strings" +) + +const NORMAL90CONFIDENCE = 1.6448536269514727 + +func boundsToLogParams(low float64, high float64) (float64, float64) { + loglow := math.Log(low) + loghigh := math.Log(high) + logmean := (loghigh + loglow) / 2.0 + logstd := (loghigh - loglow) / (2.0 * NORMAL90CONFIDENCE) + return logmean, logstd + +} + +func multiplyLognormals(logmean1 float64, logstd1 float64, logmean2 float64, logstd2 float64) (float64, float64) { + return logmean1 + logmean2, math.Sqrt(logstd1*logstd1 + logstd2*logstd2) +} + +func logParamsToBounds(logmean float64, logstd float64) (float64, float64) { + h := logstd * NORMAL90CONFIDENCE + loglow := logmean - h + loghigh := logmean + h + return math.Exp(loglow), math.Exp(loghigh) +} + +func combineBounds(old_low, old_high, new_low, new_high float64) (float64, float64) { + logmean_old, logstd_old := boundsToLogParams(old_low, old_high) + logmean_new, logstd_new := boundsToLogParams(new_low, new_high) + + logmean_product, logstd_product := multiplyLognormals(logmean_old, logstd_old, logmean_new, logstd_new) + + return logParamsToBounds(logmean_product, logstd_product) +} + +func prettyPrintDist(low float64, high float64) { + // fmt.Printf("=> %.1f %.1f\n", low, high) + fmt.Printf("=> ") + switch { + case math.Abs(low) >= 1_000_000_000_000: + fmt.Printf("%.1fT", low/1_000_000_000_000) + case math.Abs(low) >= 1_000_000_000: + fmt.Printf("%.1fB", low/1_000_000_000) + case math.Abs(low) >= 1_000_000: + fmt.Printf("%.1fM", low/1_000_000) + case math.Abs(low) >= 1_000: + fmt.Printf("%.1fK", low/1_000) + case math.Abs(low) >= 1_000: + fmt.Printf("%.1fK", low/1_000) + default: + fmt.Printf("%.1f", low) + } + fmt.Printf(" ") + switch { + case math.Abs(high) >= 1_000_000_000_000: + fmt.Printf("%.1fT", high/1_000_000_000_000) + case math.Abs(high) >= 1_000_000_000: + fmt.Printf("%.1fB", high/1_000_000_000) + case math.Abs(high) >= 1_000_000: + fmt.Printf("%.1fM", high/1_000_000) + case math.Abs(high) >= 1_000: + fmt.Printf("%.1fK", high/1_000) + case math.Abs(high) >= 1_000: + fmt.Printf("%.1fK", high/1_000) + default: + fmt.Printf("%.1f", high) + } + fmt.Printf("\n") + // fmt.Printf("=> %.1f %.1f\n", low, high) +} + +func main() { + reader := bufio.NewReader(os.Stdin) + + var old_low, old_high float64 + var input string + var err1, err2 error + +InitialForLoop: + for { + input, _ = reader.ReadString('\n') + input = strings.TrimSpace(input) + words := strings.Split(input, " ") + + switch len(words) { + case 1: + single_float, err1 := strconv.ParseFloat(words[0], 64) + if err1 != nil { + fmt.Println("Trying to initialize with a scalar, but scalar is not a float") + continue InitialForLoop + } + old_low = single_float + old_high = single_float + case 2: + old_low, err1 = strconv.ParseFloat(words[0], 64) + old_high, err2 = strconv.ParseFloat(words[1], 64) + if err1 != nil || err2 != nil { + fmt.Println("Trying to initialize with a distribution, but distribution is not specified as two floats") + continue InitialForLoop + } + default: + fmt.Println("Please enter two floats separated by a space, like: 1 10") + continue InitialForLoop + } + if err1 != nil || err2 != nil { + fmt.Println("Please enter two floats separated by a space, like: 1 10") + continue + } + break + } + prettyPrintDist(old_low, old_high) + + error_msg_cont := "Valid inputs: 2 || * 2 || / 2 || 2 20 || * 2 20 || / 2 20 || i || e" +EventForLoop: + for { + input, _ = reader.ReadString('\n') + if strings.TrimSpace(input) == "" { + continue EventForLoop + } + words := strings.Split(strings.TrimSpace(input), " ") + + var new_low, new_high float64 + + switch words[0] { + case "*": + switch len(words) { + case 1: + fmt.Println("Can't multiply by nothing") + fmt.Println(error_msg_cont) + continue EventForLoop + case 2: + single_float, err1 := strconv.ParseFloat(words[1], 64) + if err1 != nil { + fmt.Println("Trying to multiply by a scalar, but scalar is not a float") + fmt.Println(error_msg_cont) + continue EventForLoop + } + new_low = single_float + new_high = single_float + case 3: + new_low, err1 = strconv.ParseFloat(words[1], 64) + new_high, err2 = strconv.ParseFloat(words[2], 64) + if err1 != nil || err2 != nil { + fmt.Println(error_msg_cont) + fmt.Println("Trying to multiply by a distribution, but distribution is not specified as two floats") + continue EventForLoop + } + default: + fmt.Println("Trying to multiply by something, but this something is neither a scalar nor a distribution") + fmt.Println(error_msg_cont) + continue EventForLoop + } + case "/": + switch len(words) { + case 1: + fmt.Println("Can't divide by nothing") + fmt.Println(error_msg_cont) + continue EventForLoop + case 2: + single_float, err1 := strconv.ParseFloat(words[1], 64) + if err1 != nil { + fmt.Println("Trying to divide by a scalar, but scalar is not a float") + fmt.Println(error_msg_cont) + continue EventForLoop + } + new_low = 1.0 / single_float + new_high = 1.0 / single_float + case 3: + new_low, err1 = strconv.ParseFloat(words[1], 64) + new_high, err2 = strconv.ParseFloat(words[2], 64) + if err1 != nil || err2 != nil { + fmt.Println("Trying to divide by a distribution, but distribution is not specified as two floats") + fmt.Println(error_msg_cont) + continue EventForLoop + } + tmp := new_low + new_low = 1.0 / new_high + new_high = 1.0 / tmp + default: + fmt.Println("Trying to divide by something, but this something is neither a scalar nor a distribution") + } + default: + switch len(words) { + case 0: + continue EventForLoop + case 1: + switch words[0] { + case "i": + fmt.Printf("=> %.1f %.1f\n", old_low, old_high) + logmean_old, logstd_old := boundsToLogParams(old_low, old_high) + fmt.Printf("=> Lognormal, with logmean: %.1f, logstd: %.1f\n", logmean_old, logstd_old) + continue EventForLoop + case "e": + break EventForLoop + default: + single_float, err1 := strconv.ParseFloat(words[0], 64) + if err1 != nil { + fmt.Println("Unrecognized command") + fmt.Println(error_msg_cont) + continue EventForLoop + } + new_low = single_float + new_high = single_float + } + case 2: + new_low, err1 = strconv.ParseFloat(words[0], 64) + new_high, err2 = strconv.ParseFloat(words[1], 64) + if err1 != nil || err2 != nil { + fmt.Println("Trying to multiply by a distribution, but distribution is not specified as two floats") + fmt.Println(error_msg_cont) + continue EventForLoop + } + default: + fmt.Println("No operation takes more than 3 words") + fmt.Println(error_msg_cont) + continue EventForLoop + } + } + + old_low, old_high = combineBounds(old_low, old_high, new_low, new_high) + prettyPrintDist(old_low, old_high) + } +} diff --git a/f2.go b/f2.go deleted file mode 100644 index cc590a9..0000000 --- a/f2.go +++ /dev/null @@ -1,225 +0,0 @@ -package main - -import ( - "bufio" - "errors" - "fmt" - "math" - "os" - "strconv" - "strings" -) - -const NORMAL90CONFIDENCE = 1.6448536269514727 -const general_err_msg = "Valid inputs: 2 || * 2 || / 2 || 2 20 || * 2 20 || / 2 20 || clean || =: var || op var || clean || help || debug || exit" - -// Actually, I should look up how do do a) enums in go, b) union types -type Lognormal struct { - low float64 - high float64 -} - -type Dist struct { - Type string - Lognormal Lognormal - Samples []float64 -} - -// Parse line into Distribution -func parseLineErr(err_msg string) (string, Dist, error) { - fmt.Println(general_err_msg) - fmt.Println(err_msg) - return "", Dist{}, errors.New(err_msg) -} -func parseLine(line string, vars map[string]Dist) (string, Dist, error) { - - words := strings.Split(strings.TrimSpace(line), " ") - op := "" - var dist Dist - - switch words[0] { - case "*": - op = "*" - words = words[1:] - case "/": - op = "/" - words = words[1:] - case "+": - return parseLineErr("+ operation not implemented yet") - case "-": - return parseLineErr("- operation not implemented yet") - default: - op = "*" // later, change the below to - } - - switch len(words) { - case 0: - return parseLineErr("Operator must have operand; can't operate on nothing") - case 1: - var_word, var_word_exists := vars[words[0]] - single_float, err1 := strconv.ParseFloat(words[0], 64) - switch { - case var_word_exists: - dist = var_word - case err1 == nil: - dist = Dist{Type: "Lognormal", Lognormal: Lognormal{low: single_float, high: single_float}, Samples: nil} - case err1 != nil && !var_word_exists: - return parseLineErr("Trying to operate on a scalar, but scalar is neither a float nor an assigned variable") - } - case 2: - new_low, err1 := strconv.ParseFloat(words[0], 64) - new_high, err2 := strconv.ParseFloat(words[1], 64) - if err1 != nil || err2 != nil { - return parseLineErr("Trying to operate by a distribution, but distribution is not specified as two floats") - } - dist = Dist{Type: "Lognormal", Lognormal: Lognormal{low: new_low, high: new_high}, Samples: nil} - default: - return parseLineErr("Other input methods not implemented yet") - } - return op, dist, nil - -} - -// Join distributions -// Multiply lognormals - -func multiplyLogDists(l1 Lognormal, l2 Lognormal) Lognormal { - logmean1 := (math.Log(l1.high) + math.Log(l1.low)) / 2.0 - logstd1 := (math.Log(l1.high) - math.Log(l1.low)) / (2.0 * NORMAL90CONFIDENCE) - - logmean2 := (math.Log(l2.high) + math.Log(l2.low)) / 2.0 - logstd2 := (math.Log(l2.high) - math.Log(l2.low)) / (2.0 * NORMAL90CONFIDENCE) - - logmean_product := logmean1 + logmean2 - logstd_product := math.Sqrt(logstd1*logstd1 + logstd2*logstd2) - - h := logstd_product * NORMAL90CONFIDENCE - loglow := logmean_product - h - loghigh := logmean_product + h - return Lognormal{low: math.Exp(loglow), high: math.Exp(loghigh)} - -} - -func joinDists(old_dist Dist, new_dist Dist, op string) (Dist, error) { - switch { - case old_dist.Type == "Lognormal" && new_dist.Type == "Lognormal" && op == "*": - return Dist{Type: "Lognormal", Lognormal: multiplyLogDists(old_dist.Lognormal, new_dist.Lognormal), Samples: nil}, nil - case old_dist.Type == "Lognormal" && new_dist.Type == "Lognormal" && op == "/": - tmp_dist := Lognormal{low: 1.0 / new_dist.Lognormal.high, high: 1.0 / new_dist.Lognormal.low} - return Dist{Type: "Lognormal", Lognormal: multiplyLogDists(old_dist.Lognormal, tmp_dist), Samples: nil}, nil - default: - fmt.Printf("For now, can't do anything besides multiplying lognormals\n") - } - return old_dist, errors.New("Can't combine distributions in this way") -} - -/* Pretty print distributions */ -func prettyPrintLognormal(low float64, high float64) { - // fmt.Printf("=> %.1f %.1f\n", low, high) - fmt.Printf("=> ") - switch { - case math.Abs(low) >= 1_000_000_000_000: - fmt.Printf("%.1fT", low/1_000_000_000_000) - case math.Abs(low) >= 1_000_000_000: - fmt.Printf("%.1fB", low/1_000_000_000) - case math.Abs(low) >= 1_000_000: - fmt.Printf("%.1fM", low/1_000_000) - case math.Abs(low) >= 1_000: - fmt.Printf("%.1fK", low/1_000) - case math.Abs(low) >= 1_000: - fmt.Printf("%.1fK", low/1_000) - default: - fmt.Printf("%.1f", low) - } - fmt.Printf(" ") - switch { - case math.Abs(high) >= 1_000_000_000_000: - fmt.Printf("%.1fT", high/1_000_000_000_000) - case math.Abs(high) >= 1_000_000_000: - fmt.Printf("%.1fB", high/1_000_000_000) - case math.Abs(high) >= 1_000_000: - fmt.Printf("%.1fM", high/1_000_000) - case math.Abs(high) >= 1_000: - fmt.Printf("%.1fK", high/1_000) - case math.Abs(high) >= 1_000: - fmt.Printf("%.1fK", high/1_000) - default: - fmt.Printf("%.1f", high) - } - fmt.Printf("\n") - // fmt.Printf("=> %.1f %.1f\n", low, high) -} - -func prettyPrintDist(dist Dist) { - if dist.Type == "Lognormal" { - prettyPrintLognormal(dist.Lognormal.low, dist.Lognormal.high) - } else { - fmt.Printf("%v", dist) - } -} - -/* Main event loop */ -func main() { - reader := bufio.NewReader(os.Stdin) - init_dist := Dist{Type: "Lognormal", Lognormal: Lognormal{low: 1, high: 1}, Samples: nil} // Could also just be a scalar - old_dist := init_dist - vars := make(map[string]Dist) - // Could eventually be a more complex struct with: - // { Dist, VariableMaps, ConfigParams } or smth -EventForLoop: - for { - input, _ := reader.ReadString('\n') - if strings.TrimSpace(input) == "" { - continue EventForLoop - } - - { - words := strings.Split(strings.TrimSpace(input), " ") - switch { - case words[0] == "exit" || words[0] == "e": - break EventForLoop - case words[0] == "help" || words[0] == "h": - fmt.Println(general_err_msg) - continue EventForLoop - case words[0] == "debug" || words[0] == "d": - fmt.Printf("Old dist: %v\n", old_dist) - fmt.Printf("Vars: %v\n", vars) - continue EventForLoop - case words[0] == "=:" && len(words) == 2: - vars[words[1]] = old_dist - fmt.Printf("%s ", words[1]) - prettyPrintDist(old_dist) - continue EventForLoop - case words[0] == "." || words[0] == "clean" || words[0] == "c": - old_dist = init_dist - fmt.Println() - continue EventForLoop - case words[0] == "=." && len(words) == 2: - vars[words[1]] = old_dist - fmt.Printf("%s ", words[1]) - prettyPrintDist(old_dist) - old_dist = init_dist - fmt.Println() - continue EventForLoop - // Other possible cases: - // Save to file - // Sample n samples - // Save stack to a variable? - // clean stack - // Define a function? No, too much of a nerdsnipea - } - } - - op, new_dist, err := parseLine(input, vars) - if err != nil { - continue EventForLoop - } - - joint_dist, err := joinDists(old_dist, new_dist, op) - if err != nil { - continue EventForLoop - } - old_dist = joint_dist - prettyPrintDist(old_dist) - } -}