blob: 039cb4fb4501676c93aeecfa6cd5e81a564dd271 (
plain) (
blame)
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
120
121
122
123
|
package main
import (
"fmt"
"math"
)
// parseFunction returns nil is fn is not a valid function.
func parseFunction(fn string) func(*Calculator) {
switch fn {
case "sin", "cos", "tan":
return trig(fn)
case "asin", "acos", "atan":
return invTrig(fn)
case "deg":
return deg
case "rad":
return rad
case "fac":
return fac
}
return nil
}
// trig returns a closure that performs the trig function specified by fn.
// Panics if fn is not one of "sin", "cos" or "tan".
func trig(fn string) func(*Calculator) {
return func(c *Calculator) {
if len(c.stack) <= 0 {
return
}
v := &c.stack[len(c.stack)-1]
// The math package expects arguments to trig functions to be in radians.
if c.angleMode == degrees {
*v = degToRad(*v)
}
switch fn {
case "sin":
*v = math.Sin(*v)
case "cos":
*v = math.Cos(*v)
case "tan":
*v = math.Tan(*v)
default:
panic(fmt.Sprintf("invalid trig function: '%s'", fn))
}
}
}
// invTrig returns a closure that performs the inverse trig function specified
// by fn. Panics if fn is not one of "asin", "acos" or "atan".
func invTrig(fn string) func(*Calculator) {
return func(c *Calculator) {
if len(c.stack) <= 0 {
return
}
v := &c.stack[len(c.stack)-1]
switch fn {
case "asin":
*v = math.Asin(*v)
case "acos":
*v = math.Acos(*v)
case "atan":
*v = math.Atan(*v)
default:
panic(fmt.Sprintf("invalid inverse trig function: '%s'", fn))
}
if c.angleMode == degrees {
*v = radToDeg(*v)
}
}
}
// Convert radians to degrees.
func deg(c *Calculator) {
if n, err := c.stack.pop(); err == nil {
c.stack.push(radToDeg(n))
}
}
// Convert degrees to radians.
func rad(c *Calculator) {
if n, err := c.stack.pop(); err == nil {
c.stack.push(degToRad(n))
}
}
// Factorial (!).
func fac(c *Calculator) {
n, err := c.stack.pop()
if err != nil {
return
}
if !isUint(n) { // undefined on non-ints
c.stack.push(n)
return
}
c.stack.push(float64(factorial(uint(n))))
}
func degToRad(deg float64) (rad float64) {
return deg * math.Pi / 180.0
}
func radToDeg(rad float64) (deg float64) {
return rad * 180 / math.Pi
}
// factorial returns n! (n factorial).
func factorial(n uint) uint {
if n == 0 { // 0! = 1
return 1
}
// n! = n*(n-1)!
for i := n - 1; i > 1; i-- {
n *= i
}
return n
}
func isUint(n float64) bool {
return float64(uint(n)) == n
}
|