go.starlark.net@v0.0.0-20231101134539-556fd59b42f6/lib/math/math.go (about) 1 // Copyright 2021 The Bazel Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package math provides basic constants and mathematical functions. 6 package math // import "go.starlark.net/lib/math" 7 8 import ( 9 "errors" 10 "fmt" 11 "math" 12 13 "go.starlark.net/starlark" 14 "go.starlark.net/starlarkstruct" 15 ) 16 17 // Module math is a Starlark module of math-related functions and constants. 18 // The module defines the following functions: 19 // 20 // ceil(x) - Returns the ceiling of x, the smallest integer greater than or equal to x. 21 // copysign(x, y) - Returns a value with the magnitude of x and the sign of y. 22 // fabs(x) - Returns the absolute value of x as float. 23 // floor(x) - Returns the floor of x, the largest integer less than or equal to x. 24 // mod(x, y) - Returns the floating-point remainder of x/y. The magnitude of the result is less than y and its sign agrees with that of x. 25 // pow(x, y) - Returns x**y, the base-x exponential of y. 26 // remainder(x, y) - Returns the IEEE 754 floating-point remainder of x/y. 27 // round(x) - Returns the nearest integer, rounding half away from zero. 28 // 29 // exp(x) - Returns e raised to the power x, where e = 2.718281… is the base of natural logarithms. 30 // sqrt(x) - Returns the square root of x. 31 // 32 // acos(x) - Returns the arc cosine of x, in radians. 33 // asin(x) - Returns the arc sine of x, in radians. 34 // atan(x) - Returns the arc tangent of x, in radians. 35 // atan2(y, x) - Returns atan(y / x), in radians. 36 // The result is between -pi and pi. 37 // The vector in the plane from the origin to point (x, y) makes this angle with the positive X axis. 38 // The point of atan2() is that the signs of both inputs are known to it, so it can compute the correct 39 // quadrant for the angle. 40 // For example, atan(1) and atan2(1, 1) are both pi/4, but atan2(-1, -1) is -3*pi/4. 41 // cos(x) - Returns the cosine of x, in radians. 42 // hypot(x, y) - Returns the Euclidean norm, sqrt(x*x + y*y). This is the length of the vector from the origin to point (x, y). 43 // sin(x) - Returns the sine of x, in radians. 44 // tan(x) - Returns the tangent of x, in radians. 45 // 46 // degrees(x) - Converts angle x from radians to degrees. 47 // radians(x) - Converts angle x from degrees to radians. 48 // 49 // acosh(x) - Returns the inverse hyperbolic cosine of x. 50 // asinh(x) - Returns the inverse hyperbolic sine of x. 51 // atanh(x) - Returns the inverse hyperbolic tangent of x. 52 // cosh(x) - Returns the hyperbolic cosine of x. 53 // sinh(x) - Returns the hyperbolic sine of x. 54 // tanh(x) - Returns the hyperbolic tangent of x. 55 // 56 // log(x, base) - Returns the logarithm of x in the given base, or natural logarithm by default. 57 // 58 // gamma(x) - Returns the Gamma function of x. 59 // 60 // All functions accept both int and float values as arguments. 61 // 62 // The module also defines approximations of the following constants: 63 // 64 // e - The base of natural logarithms, approximately 2.71828. 65 // pi - The ratio of a circle's circumference to its diameter, approximately 3.14159. 66 // 67 var Module = &starlarkstruct.Module{ 68 Name: "math", 69 Members: starlark.StringDict{ 70 "ceil": starlark.NewBuiltin("ceil", ceil), 71 "copysign": newBinaryBuiltin("copysign", math.Copysign), 72 "fabs": newUnaryBuiltin("fabs", math.Abs), 73 "floor": starlark.NewBuiltin("floor", floor), 74 "mod": newBinaryBuiltin("mod", math.Mod), 75 "pow": newBinaryBuiltin("pow", math.Pow), 76 "remainder": newBinaryBuiltin("remainder", math.Remainder), 77 "round": newUnaryBuiltin("round", math.Round), 78 79 "exp": newUnaryBuiltin("exp", math.Exp), 80 "sqrt": newUnaryBuiltin("sqrt", math.Sqrt), 81 82 "acos": newUnaryBuiltin("acos", math.Acos), 83 "asin": newUnaryBuiltin("asin", math.Asin), 84 "atan": newUnaryBuiltin("atan", math.Atan), 85 "atan2": newBinaryBuiltin("atan2", math.Atan2), 86 "cos": newUnaryBuiltin("cos", math.Cos), 87 "hypot": newBinaryBuiltin("hypot", math.Hypot), 88 "sin": newUnaryBuiltin("sin", math.Sin), 89 "tan": newUnaryBuiltin("tan", math.Tan), 90 91 "degrees": newUnaryBuiltin("degrees", degrees), 92 "radians": newUnaryBuiltin("radians", radians), 93 94 "acosh": newUnaryBuiltin("acosh", math.Acosh), 95 "asinh": newUnaryBuiltin("asinh", math.Asinh), 96 "atanh": newUnaryBuiltin("atanh", math.Atanh), 97 "cosh": newUnaryBuiltin("cosh", math.Cosh), 98 "sinh": newUnaryBuiltin("sinh", math.Sinh), 99 "tanh": newUnaryBuiltin("tanh", math.Tanh), 100 101 "log": starlark.NewBuiltin("log", log), 102 103 "gamma": newUnaryBuiltin("gamma", math.Gamma), 104 105 "e": starlark.Float(math.E), 106 "pi": starlark.Float(math.Pi), 107 }, 108 } 109 110 // floatOrInt is an Unpacker that converts a Starlark int or float to Go's float64. 111 type floatOrInt float64 112 113 func (p *floatOrInt) Unpack(v starlark.Value) error { 114 switch v := v.(type) { 115 case starlark.Int: 116 *p = floatOrInt(v.Float()) 117 return nil 118 case starlark.Float: 119 *p = floatOrInt(v) 120 return nil 121 } 122 return fmt.Errorf("got %s, want float or int", v.Type()) 123 } 124 125 // newUnaryBuiltin wraps a unary floating-point Go function 126 // as a Starlark built-in that accepts int or float arguments. 127 func newUnaryBuiltin(name string, fn func(float64) float64) *starlark.Builtin { 128 return starlark.NewBuiltin(name, func(thread *starlark.Thread, b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { 129 var x floatOrInt 130 if err := starlark.UnpackPositionalArgs(name, args, kwargs, 1, &x); err != nil { 131 return nil, err 132 } 133 return starlark.Float(fn(float64(x))), nil 134 }) 135 } 136 137 // newBinaryBuiltin wraps a binary floating-point Go function 138 // as a Starlark built-in that accepts int or float arguments. 139 func newBinaryBuiltin(name string, fn func(float64, float64) float64) *starlark.Builtin { 140 return starlark.NewBuiltin(name, func(thread *starlark.Thread, b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { 141 var x, y floatOrInt 142 if err := starlark.UnpackPositionalArgs(name, args, kwargs, 2, &x, &y); err != nil { 143 return nil, err 144 } 145 return starlark.Float(fn(float64(x), float64(y))), nil 146 }) 147 } 148 149 // log wraps the Log function 150 // as a Starlark built-in that accepts int or float arguments. 151 func log(thread *starlark.Thread, b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { 152 var ( 153 x floatOrInt 154 base floatOrInt = math.E 155 ) 156 if err := starlark.UnpackPositionalArgs("log", args, kwargs, 1, &x, &base); err != nil { 157 return nil, err 158 } 159 if base == 1 { 160 return nil, errors.New("division by zero") 161 } 162 return starlark.Float(math.Log(float64(x)) / math.Log(float64(base))), nil 163 } 164 165 func ceil(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { 166 var x starlark.Value 167 168 if err := starlark.UnpackPositionalArgs("ceil", args, kwargs, 1, &x); err != nil { 169 return nil, err 170 } 171 172 switch t := x.(type) { 173 case starlark.Int: 174 return t, nil 175 case starlark.Float: 176 return starlark.NumberToInt(starlark.Float(math.Ceil(float64(t)))) 177 } 178 179 return nil, fmt.Errorf("got %s, want float or int", x.Type()) 180 } 181 182 func floor(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { 183 var x starlark.Value 184 185 if err := starlark.UnpackPositionalArgs("floor", args, kwargs, 1, &x); err != nil { 186 return nil, err 187 } 188 189 switch t := x.(type) { 190 case starlark.Int: 191 return t, nil 192 case starlark.Float: 193 return starlark.NumberToInt(starlark.Float(math.Floor(float64(t)))) 194 } 195 196 return nil, fmt.Errorf("got %s, want float or int", x.Type()) 197 } 198 199 func degrees(x float64) float64 { 200 return 360 * x / (2 * math.Pi) 201 } 202 203 func radians(x float64) float64 { 204 return 2 * math.Pi * x / 360 205 }