-
Notifications
You must be signed in to change notification settings - Fork 192
/
math.go
119 lines (112 loc) · 3.07 KB
/
math.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package lua
import (
"math"
"math/rand"
)
const radiansPerDegree = math.Pi / 180.0
func mathUnaryOp(f func(float64) float64) Function {
return func(l *State) int {
l.PushNumber(f(CheckNumber(l, 1)))
return 1
}
}
func mathBinaryOp(f func(float64, float64) float64) Function {
return func(l *State) int {
l.PushNumber(f(CheckNumber(l, 1), CheckNumber(l, 2)))
return 1
}
}
func reduce(f func(float64, float64) float64) Function {
return func(l *State) int {
n := l.Top() // number of arguments
v := CheckNumber(l, 1)
for i := 2; i <= n; i++ {
v = f(v, CheckNumber(l, i))
}
l.PushNumber(v)
return 1
}
}
var mathLibrary = []RegistryFunction{
{"abs", mathUnaryOp(math.Abs)},
{"acos", mathUnaryOp(math.Acos)},
{"asin", mathUnaryOp(math.Asin)},
{"atan2", mathBinaryOp(math.Atan2)},
{"atan", mathUnaryOp(math.Atan)},
{"ceil", mathUnaryOp(math.Ceil)},
{"cosh", mathUnaryOp(math.Cosh)},
{"cos", mathUnaryOp(math.Cos)},
{"deg", mathUnaryOp(func(x float64) float64 { return x / radiansPerDegree })},
{"exp", mathUnaryOp(math.Exp)},
{"floor", mathUnaryOp(math.Floor)},
{"fmod", mathBinaryOp(math.Mod)},
{"frexp", func(l *State) int {
f, e := math.Frexp(CheckNumber(l, 1))
l.PushNumber(f)
l.PushInteger(e)
return 2
}},
{"ldexp", func(l *State) int {
x, e := CheckNumber(l, 1), CheckInteger(l, 2)
l.PushNumber(math.Ldexp(x, e))
return 1
}},
{"log", func(l *State) int {
x := CheckNumber(l, 1)
if l.IsNoneOrNil(2) {
l.PushNumber(math.Log(x))
} else if base := CheckNumber(l, 2); base == 10.0 {
l.PushNumber(math.Log10(x))
} else {
l.PushNumber(math.Log(x) / math.Log(base))
}
return 1
}},
{"max", reduce(math.Max)},
{"min", reduce(math.Min)},
{"modf", func(l *State) int {
i, f := math.Modf(CheckNumber(l, 1))
l.PushNumber(i)
l.PushNumber(f)
return 2
}},
{"pow", mathBinaryOp(math.Pow)},
{"rad", mathUnaryOp(func(x float64) float64 { return x * radiansPerDegree })},
{"random", func(l *State) int {
r := rand.Float64()
switch l.Top() {
case 0: // no arguments
l.PushNumber(r)
case 1: // upper limit only
u := CheckNumber(l, 1)
ArgumentCheck(l, 1.0 <= u, 1, "interval is empty")
l.PushNumber(math.Floor(r*u) + 1.0) // [1, u]
case 2: // lower and upper limits
lo, u := CheckNumber(l, 1), CheckNumber(l, 2)
ArgumentCheck(l, lo <= u, 2, "interval is empty")
l.PushNumber(math.Floor(r*(u-lo+1)) + lo) // [lo, u]
default:
Errorf(l, "wrong number of arguments")
}
return 1
}},
{"randomseed", func(l *State) int {
rand.Seed(int64(CheckUnsigned(l, 1)))
rand.Float64() // discard first value to avoid undesirable correlations
return 0
}},
{"sinh", mathUnaryOp(math.Sinh)},
{"sin", mathUnaryOp(math.Sin)},
{"sqrt", mathUnaryOp(math.Sqrt)},
{"tanh", mathUnaryOp(math.Tanh)},
{"tan", mathUnaryOp(math.Tan)},
}
// MathOpen opens the math library. Usually passed to Require.
func MathOpen(l *State) int {
NewLibrary(l, mathLibrary)
l.PushNumber(3.1415926535897932384626433832795) // TODO use math.Pi instead? Values differ.
l.SetField(-2, "pi")
l.PushNumber(math.MaxFloat64)
l.SetField(-2, "huge")
return 1
}