add rounding

This commit is contained in:
2023-03-10 21:39:58 +00:00
parent fe05d818de
commit 7e10423b54
11 changed files with 161 additions and 39 deletions

2
go.mod
View File

@@ -1,3 +1,5 @@
module wbell.dev/m/v2 module wbell.dev/m/v2
go 1.19 go 1.19
require github.com/wadey/go-rounding v1.1.0 // indirect

2
go.sum Normal file
View File

@@ -0,0 +1,2 @@
github.com/wadey/go-rounding v1.1.0 h1:RAs9dMkB/uUHFv9ljlbRFC8/kBrQ5jhwt1GQq+2cciY=
github.com/wadey/go-rounding v1.1.0/go.mod h1:/uD953tCL6Fea2Yp+LZBBp8d60QSObkMJxY6SPOJ5QE=

View File

@@ -1,5 +1,7 @@
package main package main
import "github.com/wadey/go-rounding"
var vars = scope{} var vars = scope{}
func init() { func init() {
@@ -41,7 +43,53 @@ func init() {
} }
return newmap, ArErr{} return newmap, ArErr{}
} }
return nil, ArErr{TYPE: "TypeError", message: "Cannot create map from " + typeof(a[0]), EXISTS: true} return nil, ArErr{TYPE: "TypeError", message: "Cannot create map from '" + typeof(a[0]) + "'", EXISTS: true}
}}
vars["array"] = builtinFunc{"array", func(a ...any) (any, ArErr) {
if len(a) == 0 {
return ArArray{}, ArErr{}
}
switch x := a[0].(type) {
case ArArray:
return x, ArErr{}
case string:
newarray := ArArray{}
for _, v := range x {
newarray = append(newarray, string(v))
}
return newarray, ArErr{}
case ArMap:
newarray := ArArray{}
for _, v := range x {
newarray = append(newarray, v)
}
return newarray, ArErr{}
}
return nil, ArErr{TYPE: "TypeError", message: "Cannot create array from '" + typeof(a[0]) + "'", EXISTS: true}
}}
vars["round"] = builtinFunc{"round", func(a ...any) (any, ArErr) {
if len(a) == 0 {
return nil, ArErr{TYPE: "round", message: "round takes 1 argument",
EXISTS: true}
}
precision := newNumber()
if len(a) > 1 {
switch x := a[1].(type) {
case number:
if !x.IsInt() {
return nil, ArErr{TYPE: "TypeError", message: "Cannot round to '" + typeof(a[1]) + "'", EXISTS: true}
}
precision = x
default:
return nil, ArErr{TYPE: "TypeError", message: "Cannot round to '" + typeof(a[1]) + "'", EXISTS: true}
}
}
switch x := a[0].(type) {
case number:
return rounding.Round(newNumber().Set(x), int(precision.Num().Int64()), rounding.HalfUp), ArErr{}
}
return nil, ArErr{TYPE: "TypeError", message: "Cannot round '" + typeof(a[0]) + "'", EXISTS: true}
}} }}
vars["time"] = ArTime vars["time"] = ArTime
vars["PI"] = PI vars["PI"] = PI

59
src/factorial.go Normal file
View File

@@ -0,0 +1,59 @@
package main
import (
"strings"
)
var factorialCompiled = makeRegex(`( *)(.|\n)+\!( *)`)
type factorial struct {
value any
code string
line int
path string
}
func parseFactorial(code UNPARSEcode, index int, codeline []UNPARSEcode) (factorial, bool, ArErr, int) {
trim := strings.TrimSpace(code.code)
trim = trim[:len(trim)-1]
val, success, err, i := translateVal(UNPARSEcode{code: trim, realcode: code.realcode, line: 1, path: ""}, 0, []UNPARSEcode{}, false)
if !success {
return factorial{}, false, err, i
}
return factorial{val, code.code, code.line, code.path}, success, ArErr{}, i
}
func isFactorial(code UNPARSEcode) bool {
return factorialCompiled.MatchString(code.code)
}
func fact(n number) number {
if n.Cmp(newNumber().SetInt64(0)) == 0 {
return newNumber().SetInt64(1)
}
result := newNumber().SetInt64(1)
for i := newNumber().SetInt64(2); i.Cmp(n) <= 0; i.Add(i, newNumber().SetInt64(1)) {
result.Mul(result, i)
}
return result
}
func runFactorial(f factorial, stack stack) (any, ArErr) {
val, err := runVal(f.value, stack)
if err.EXISTS {
return nil, err
}
switch x := val.(type) {
case number:
if !x.IsInt() {
return nil, ArErr{"Runtime Error", "cannot use factorial on non-integer", f.line, f.path, f.code, true}
}
if x.Cmp(newNumber().SetInt64(0)) == -1 {
return nil, ArErr{"Runtime Error", "cannot use factorial on negative number", f.line, f.path, f.code, true}
}
return fact(x), ArErr{}
default:
return nil, ArErr{"Runtime Error", "cannot use factorial on non-number of type '" + typeof(val) + "'", f.line, f.path, f.code, true}
}
}

View File

@@ -35,40 +35,19 @@ func isAnyNumber(x any) bool {
} }
// converts a number type to a string // converts a number type to a string
func numberToString(num number, fraction int, simplify bool) string { func numberToString(num number, simplify bool) string {
if fraction != 0 {
str := num.RatString()
if fraction == 1 {
return str
}
split := strings.SplitN(str, "/", 2)
if len(str) == 1 {
return split[0]
}
numerator := split[0]
denominator := split[1]
super := []string{}
for i := 0; i <= len(numerator); i++ {
super = append(super, superscript[numerator[i]])
}
sub := []string{}
for i := 0; i < len(denominator); i++ {
sub = append(sub, subscript[denominator[i]])
}
return strings.Join(super, "") + "/" + strings.Join(sub, "")
}
if simplify { if simplify {
divPI, _ := newNumber().Quo(num, PI).Float64() divPI := newNumber().Quo(num, PI)
floated := float64(int(divPI * 100)) if divPI.Cmp(newNumber().SetInt64(1)) == 0 {
if divPI == 1 {
return "π" return "π"
} else if divPI == -1 { } else if divPI.Cmp(newNumber().SetInt64(-1)) == 0 {
return "-π" return "-π"
} else if divPI == 0 { } else if divPI.Cmp(newNumber()) == 0 {
return "0" return "0"
} else if (divPI*100) == floated && floated != 0 { } else if divPI.Denom().Cmp(new(big.Int).SetInt64(1000)) <= 0 {
return fmt.Sprint(divPI) + "π" num := divPI.RatString()
return fmt.Sprint(num, "π")
} }
} }
x, _ := num.Float64() x, _ := num.Float64()

View File

@@ -21,6 +21,8 @@ func runVal(line any, stack stack) (any, ArErr) {
return x, ArErr{} return x, ArErr{}
case call: case call:
return runCall(x, stack) return runCall(x, stack)
case factorial:
return runFactorial(x, stack)
case accessVariable: case accessVariable:
return readVariable(x, stack) return readVariable(x, stack)
case ArMapGet: case ArMapGet:

View File

@@ -24,6 +24,14 @@ var plain = ArMap{
fmt.Println(output...) fmt.Println(output...)
return nil, ArErr{} return nil, ArErr{}
}}, }},
"print": builtinFunc{"print", func(args ...any) (any, ArErr) {
output := []any{}
for i := 0; i < len(args); i++ {
output = append(output, anyToArgon(args[i], false, false, 3, 0, false, 0))
}
fmt.Println(output...)
return nil, ArErr{}
}},
} }
var ArTerm = ArMap{ var ArTerm = ArMap{

View File

@@ -48,7 +48,7 @@ func anyToArgon(x any, quote bool, simplify bool, depth int, indent int, color b
} else if math.IsInf(num, -1) { } else if math.IsInf(num, -1) {
output = append(output, "-infinity") output = append(output, "-infinity")
} else { } else {
output = append(output, numberToString(x, 0, simplify)) output = append(output, numberToString(x, simplify))
} }
if color { if color {
output = append(output, "\x1b[0m") output = append(output, "\x1b[0m")
@@ -85,6 +85,32 @@ func anyToArgon(x any, quote bool, simplify bool, depth int, indent int, color b
output = append(output, anyToArgon(key, true, true, depth, (indent+1)*plain, color, plain)+": "+anyToArgon(x[key], true, true, depth-1, indent+1, color, plain)) output = append(output, anyToArgon(key, true, true, depth, (indent+1)*plain, color, plain)+": "+anyToArgon(x[key], true, true, depth-1, indent+1, color, plain))
} }
return "{" + maybenewline + (strings.Repeat(" ", (indent+1)*plain)) + strings.Join(output, ","+maybenewline+(strings.Repeat(" ", (indent+1)*plain))) + maybenewline + (strings.Repeat(" ", indent*plain)) + "}" return "{" + maybenewline + (strings.Repeat(" ", (indent+1)*plain)) + strings.Join(output, ","+maybenewline+(strings.Repeat(" ", (indent+1)*plain))) + maybenewline + (strings.Repeat(" ", indent*plain)) + "}"
case ArArray:
if len(x) == 0 {
return "[]"
}
output := []string{}
if simplify && len(x) >= 100 {
for i := 0; i < 10; i++ {
item := x[i]
output = append(output, anyToArgon(item, true, true, depth-1, indent+1, color, plain))
}
if color {
output = append(output, "\x1b[38;5;240m(...)\x1b[0m")
} else {
output = append(output, "(...)")
}
for i := len(x) - 10; i < len(x); i++ {
item := x[i]
output = append(output, anyToArgon(item, true, true, depth-1, indent+1, color, plain))
}
} else {
for i := 0; i < len(x); i++ {
item := x[i]
output = append(output, anyToArgon(item, true, true, depth-1, indent+1, color, plain))
}
}
return "[" + maybenewline + (strings.Repeat(" ", (indent+1)*plain)) + strings.Join(output, ","+maybenewline+(strings.Repeat(" ", (indent+1)*plain))) + maybenewline + (strings.Repeat(" ", indent*plain)) + "]"
case builtinFunc: case builtinFunc:
if color { if color {
output = append(output, "\x1b[38;5;240m") output = append(output, "\x1b[38;5;240m")

View File

@@ -51,6 +51,8 @@ func translateVal(code UNPARSEcode, index int, codelines []UNPARSEcode, isLine b
return parseNumber(code) return parseNumber(code)
} else if isNegative(code) { } else if isNegative(code) {
return parseNegative(code, index, codelines) return parseNegative(code, index, codelines)
} else if isFactorial(code) {
return parseFactorial(code, index, codelines)
} else if isCall(code) { } else if isCall(code) {
call, worked, err, step := parseCall(code, index, codelines) call, worked, err, step := parseCall(code, index, codelines)
if worked { if worked {

View File

@@ -1,7 +1 @@
let t = thread(f()=time.snooze(1)) range(1e10)
term.log("start")
t.start()
term.log('started')
let val = t.join()
term.log('joined', val)