-
Notifications
You must be signed in to change notification settings - Fork 16
/
floatmath.go
77 lines (73 loc) · 1.75 KB
/
floatmath.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
package dynaml
import (
"math"
"reflect"
"runtime"
"strings"
)
var float_functions = []func(float64) float64{
math.Floor, math.Ceil, math.Round, math.RoundToEven,
math.Abs,
math.Sin, math.Cos, math.Sinh, math.Cosh,
math.Asin, math.Acos, math.Asinh, math.Acosh,
math.Sqrt, math.Exp, math.Log, math.Log10,
}
func init() {
for _, f := range float_functions {
s := strings.Split(runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name(), ".")
n := strings.ToLower(s[len(s)-1])
f := f
RegisterFunction(n, func(arguments []interface{}, binding Binding) (interface{}, EvaluationInfo, bool) {
return _float(n, f, arguments)
})
}
}
func _float(name string, f func(float64) float64, arguments []interface{}) (val interface{}, info EvaluationInfo, ok bool) {
info = DefaultInfo()
defer func() {
if r := recover(); r != nil {
val, info, ok = info.Error("%s", r)
}
}()
if len(arguments) != 1 {
return info.Error("%s requires one argument", name)
}
if name == "ceil" || name == "floor" || name == "round" || name == "roundtoeven" {
switch v := arguments[0].(type) {
case int64:
return v, info, true
case float64:
return int64(f(v)), info, true
case bool:
if v {
return 1, info, true
}
return 0, info, true
default:
return info.Error("invalid argument type for %s: %T", name, v)
}
} else {
if name == "abs" {
switch v := arguments[0].(type) {
case int64:
if v < 0 {
return -v, info, true
}
return v, info, true
}
}
var r float64
switch v := arguments[0].(type) {
case int64:
r = f(float64(v))
case float64:
r = f(v)
default:
return info.Error("invalid argument type for %s: %T", name, v)
}
if math.IsNaN(r) {
return info.Error("%s: NaN", name)
}
return r, info, true
}
}