Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add math module #357

Merged
merged 8 commits into from
Mar 12, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cmd/starlark/starlark.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"strings"

"go.starlark.net/internal/compile"
"go.starlark.net/lib/math"
"go.starlark.net/lib/time"
"go.starlark.net/repl"
"go.starlark.net/resolve"
Expand Down Expand Up @@ -93,6 +94,7 @@ func doMain() int {
// TODO(adonovan): plumb predeclared env through to the REPL.
starlark.Universe["json"] = starlarkjson.Module
starlark.Universe["time"] = time.Module
starlark.Universe["math"] = math.Module

switch {
case flag.NArg() == 1 || *execprog != "":
Expand Down
198 changes: 198 additions & 0 deletions lib/math/math.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
// Copyright 2021 The Bazel Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package math provides basic constants and mathematical functions.
package math // import "go.starlark.net/lib/math"

import (
"math"

"go.starlark.net/starlark"
"go.starlark.net/starlarkstruct"
)

const (
adonovan marked this conversation as resolved.
Show resolved Hide resolved
tau = math.Pi * 2
oneRad = tau / 360
)

var (
toDeg = func(x float64) float64 { return x / oneRad }
adonovan marked this conversation as resolved.
Show resolved Hide resolved
toRad = func(x float64) float64 { return x * oneRad }
)

// Module math is a Starlark module of math-related functions and constants.
adonovan marked this conversation as resolved.
Show resolved Hide resolved
var Module = &starlarkstruct.Module{
Name: "math",
Members: starlark.StringDict{
"abs": starlark.NewBuiltin("abs", abs),
adonovan marked this conversation as resolved.
Show resolved Hide resolved
"ceil": starlark.NewBuiltin("ceil", ceil),
"floor": starlark.NewBuiltin("floor", floor),
"round": starlark.NewBuiltin("round", round),

"exp": starlark.NewBuiltin("exp", exp),
"sqrt": starlark.NewBuiltin("sqrt", sqrt),

"acos": starlark.NewBuiltin("acos", acos),
"asin": starlark.NewBuiltin("asin", asin),
"atan": starlark.NewBuiltin("atan", atan),
"atan2": starlark.NewBuiltin("atan2", atan2),
"cos": starlark.NewBuiltin("cos", cos),
"hypot": starlark.NewBuiltin("hypot", hypot),
"sin": starlark.NewBuiltin("sin", sin),
"tan": starlark.NewBuiltin("tan", tan),

"degrees": starlark.NewBuiltin("degrees", degrees),
adonovan marked this conversation as resolved.
Show resolved Hide resolved
"radians": starlark.NewBuiltin("radians", radians),

"acosh": starlark.NewBuiltin("acosh", acosh),
"asinh": starlark.NewBuiltin("asinh", asinh),
"atanh": starlark.NewBuiltin("atanh", atanh),
"cosh": starlark.NewBuiltin("cosh", cosh),
"sinh": starlark.NewBuiltin("sinh", sinh),
"tanh": starlark.NewBuiltin("tanh", tanh),

"e": starlark.Float(math.E),
"phi": starlark.Float(math.Phi),
"pi": starlark.Float(math.Pi),
},
}

// oneArgFunc unpacks a starlark function call with one argument, calls a passed in function taking one float64 as argument
// and returns the result as a starlark value.
func oneArgFunc(name string, args starlark.Tuple, kwargs []starlark.Tuple, fn func(float64) float64) (starlark.Value, error) {
var x float64
if err := starlark.UnpackPositionalArgs(name, args, kwargs, 1, &x); err != nil {
adonovan marked this conversation as resolved.
Show resolved Hide resolved
var i int64
if starlark.UnpackPositionalArgs(name, args, kwargs, 1, &i) != nil {
return nil, err
}
x = float64(i)
}
return starlark.Float(fn(x)), nil
}

// twoArgFunc unpacks a starlark function call with two arguments, calls a passed in function taking two float64 as argument
adonovan marked this conversation as resolved.
Show resolved Hide resolved
// and returns the result as a starlark value.
func twoArgFunc(name string, args starlark.Tuple, kwargs []starlark.Tuple, fn func(float64, float64) float64) (starlark.Value, error) {
var x, y float64
if err := starlark.UnpackPositionalArgs(name, args, kwargs, 2, &x, &y); err != nil {
return nil, err
}
return starlark.Float(fn(x, y)), nil
}

// floor(x) - Return the floor of x, the largest integer less than or equal to x.
adonovan marked this conversation as resolved.
Show resolved Hide resolved
func floor(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
return oneArgFunc("floor", args, kwargs, math.Floor)
}

// ceil(x) - Return the ceiling of x, the smallest integer greater than or equal to x.
func ceil(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
return oneArgFunc("ceil", args, kwargs, math.Ceil)
}

// abs(x) - Return the absolute value of x.
func abs(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
return oneArgFunc("abs", args, kwargs, math.Abs)
}

// round(x) - Round returns the nearest integer, rounding half away from zero.
func round(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
return oneArgFunc("round", args, kwargs, math.Round)
}

// exp(x) - Return e raised to the power x, where e = 2.718281… is the base of natural logarithms.
func exp(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
return oneArgFunc("exp", args, kwargs, math.Exp)
}

// sqrt(x) - Return the square root of x.
func sqrt(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
return oneArgFunc("sqrt", args, kwargs, math.Sqrt)
}

// acos(x) - Return the arc cosine of x, in radians.
func acos(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
return oneArgFunc("acos", args, kwargs, math.Acos)
}

// asin(x) - Return the arc sine of x, in radians.
func asin(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
return oneArgFunc("asin", args, kwargs, math.Asin)
}

// atan(x) - Return the arc tangent of x, in radians.
func atan(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
return oneArgFunc("atan", args, kwargs, math.Atan)
}

// atan2(y, x) - Return atan(y / x), in radians.
// The result is between -pi and pi.
// The vector in the plane from the origin to point (x, y) makes this angle with the positive X axis.
// The point of atan2() is that the signs of both inputs are known to it, so it can compute the correct quadrant for the angle.
// For example, atan(1) and atan2(1, 1) are both pi/4, but atan2(-1, -1) is -3*pi/4.
func atan2(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
return twoArgFunc("atan2", args, kwargs, math.Atan2)
}

// cos(x) - Return the cosine of x, in radians.
func cos(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
return oneArgFunc("cos", args, kwargs, math.Cos)
}

// hypot(x, y) - Return the Euclidean norm, sqrt(x*x + y*y). This is the length of the vector from the origin to point (x, y).
func hypot(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
return twoArgFunc("hypot", args, kwargs, math.Hypot)
}

// sin(x) - Return the sine of x, in radians.
func sin(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
return oneArgFunc("sin", args, kwargs, math.Sin)
}

// tan(x) - Return the tangent of x, in radians.
func tan(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
return oneArgFunc("tan", args, kwargs, math.Tan)
}

// degrees(x) - Convert angle x from radians to degrees.
func degrees(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
return oneArgFunc("degrees", args, kwargs, toDeg)
}

// radians(x) - Convert angle x from degrees to radians.
func radians(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
return oneArgFunc("radians", args, kwargs, toRad)
}

// acosh(x) - Return the inverse hyperbolic cosine of x.
func acosh(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
return oneArgFunc("acosh", args, kwargs, math.Acosh)
}

// asinh(x) - Return the inverse hyperbolic sine of x.
func asinh(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
return oneArgFunc("asinh", args, kwargs, math.Asinh)
}

// atanh(x) - Return the inverse hyperbolic tangent of x.
func atanh(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
return oneArgFunc("atanh", args, kwargs, math.Atanh)
}

// cosh(x) - Return the hyperbolic cosine of x.
func cosh(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
return oneArgFunc("cosh", args, kwargs, math.Cosh)
}

// sinh(x) - Return the hyperbolic sine of x.
func sinh(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
return oneArgFunc("sinh", args, kwargs, math.Sinh)
}

// tanh(x) - Return the hyperbolic tangent of x.
func tanh(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
return oneArgFunc("tanh", args, kwargs, math.Tanh)
}
5 changes: 5 additions & 0 deletions starlark/eval_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"testing"

"go.starlark.net/internal/chunkedfile"
starlarkmath "go.starlark.net/lib/math"
"go.starlark.net/lib/time"
"go.starlark.net/resolve"
"go.starlark.net/starlark"
Expand Down Expand Up @@ -124,6 +125,7 @@ func TestExecFile(t *testing.T) {
"testdata/int.star",
"testdata/json.star",
"testdata/list.star",
"testdata/math.star",
"testdata/misc.star",
"testdata/set.star",
"testdata/string.star",
Expand Down Expand Up @@ -198,6 +200,9 @@ func load(thread *starlark.Thread, module string) (starlark.StringDict, error) {
if module == "time.star" {
return starlark.StringDict{"time": time.Module}, nil
}
if module == "math.star" {
return starlark.StringDict{"math": starlarkmath.Module}, nil
}

// TODO(adonovan): test load() using this execution path.
filename := filepath.Join(filepath.Dir(thread.CallFrame(0).Pos.Filename()), module)
Expand Down
Loading