-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmath.go
116 lines (111 loc) · 2.85 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
package typutil
import "math"
type op struct {
opf func(float64, float64) float64
opu func(uint64, uint64) uint64
opi func(int64, int64) int64
}
var mathOps = map[string]op{
"+": op{
opf: func(a, b float64) float64 { return a + b },
opu: func(a, b uint64) uint64 { return a + b },
opi: func(a, b int64) int64 { return a + b },
},
"-": op{
opf: func(a, b float64) float64 { return a - b },
opu: func(a, b uint64) uint64 { return a - b },
opi: func(a, b int64) int64 { return a - b },
},
"/": op{
opf: func(a, b float64) float64 { return a / b },
opu: func(a, b uint64) uint64 { return a / b },
opi: func(a, b int64) int64 { return a / b },
},
"*": op{
opf: func(a, b float64) float64 { return a * b },
opu: func(a, b uint64) uint64 { return a * b },
opi: func(a, b int64) int64 { return a * b },
},
"^": op{
opf: func(a, b float64) float64 { return math.NaN() },
opu: func(a, b uint64) uint64 { return a ^ b },
opi: func(a, b int64) int64 { return a ^ b },
},
"%": op{
opf: func(a, b float64) float64 { return math.NaN() },
opu: func(a, b uint64) uint64 { return a % b },
opi: func(a, b int64) int64 { return a % b },
},
"&": op{
opf: func(a, b float64) float64 { return math.NaN() },
opu: func(a, b uint64) uint64 { return a & b },
opi: func(a, b int64) int64 { return a & b },
},
"|": op{
opf: func(a, b float64) float64 { return math.NaN() },
opu: func(a, b uint64) uint64 { return a | b },
opi: func(a, b int64) int64 { return a | b },
},
}
// Math performs a mathematical operation on two variables of any type and returns a numeric type
// and true if everything went fine.
//
// For example Math("+", 40.000, "2") will return float64(42)
//
// For now if passed any float value, the function will always return a float value in the end. This
// may change in the future.
func Math(mathop string, a, b any) (any, bool) {
op, ok := mathOps[mathop]
if !ok {
// invalid math op
return 0, false
}
na, oka := AsNumber(a)
nb, okb := AsNumber(b)
ok = oka && okb
switch ta := na.(type) {
case uint64:
switch tb := nb.(type) {
case uint64:
return op.opu(ta, tb), ok
case int64:
if tb > 0 {
return op.opu(ta, uint64(tb)), ok
} else {
return op.opi(int64(ta), tb), ok
}
case float64:
return op.opf(float64(ta), tb), ok
default:
return 0, false
}
case int64:
switch tb := nb.(type) {
case int64:
return op.opi(ta, tb), ok
case uint64:
if ta > 0 {
return op.opu(uint64(ta), tb), ok
} else {
return op.opi(ta, int64(tb)), ok
}
case float64:
return op.opf(float64(ta), tb), ok
default:
return 0, false
}
case float64:
switch tb := nb.(type) {
case int64:
return op.opf(ta, float64(tb)), ok
case uint64:
return op.opf(ta, float64(tb)), ok
case float64:
return op.opf(ta, tb), ok
default:
return 0, false
}
default:
return 0, false
}
}