-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
float.go
158 lines (124 loc) · 3.53 KB
/
float.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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package helpers
import "math"
// This wraps float64 math operations. Why does this exist? The Go compiler
// contains some optimizations to take advantage of "fused multiply and add"
// (FMA) instructions on certain processors. These instructions lead to
// different output on those processors, which means esbuild's output is no
// longer deterministic across all platforms. From the Go specification itself
// (https://go.dev/ref/spec#Floating_point_operators):
//
// An implementation may combine multiple floating-point operations into a
// single fused operation, possibly across statements, and produce a result
// that differs from the value obtained by executing and rounding the
// instructions individually. An explicit floating-point type conversion
// rounds to the precision of the target type, preventing fusion that would
// discard that rounding.
//
// For instance, some architectures provide a "fused multiply and add" (FMA)
// instruction that computes x*y + z without rounding the intermediate result
// x*y.
//
// Therefore we need to add explicit type conversions such as "float64(x)" to
// prevent optimizations that break correctness. Rather than adding them on a
// case-by-case basis as real correctness issues are discovered, we instead
// preemptively force them to be added everywhere by using this wrapper type
// for all floating-point math.
type F64 struct {
value float64
}
func NewF64(a float64) F64 {
return F64{value: float64(a)}
}
func (a F64) Value() float64 {
return a.value
}
func (a F64) IsNaN() bool {
return math.IsNaN(a.value)
}
func (a F64) Neg() F64 {
return NewF64(-a.value)
}
func (a F64) Abs() F64 {
return NewF64(math.Abs(a.value))
}
func (a F64) Sin() F64 {
return NewF64(math.Sin(a.value))
}
func (a F64) Cos() F64 {
return NewF64(math.Cos(a.value))
}
func (a F64) Log2() F64 {
return NewF64(math.Log2(a.value))
}
func (a F64) Round() F64 {
return NewF64(math.Round(a.value))
}
func (a F64) Floor() F64 {
return NewF64(math.Floor(a.value))
}
func (a F64) Ceil() F64 {
return NewF64(math.Ceil(a.value))
}
func (a F64) Squared() F64 {
return a.Mul(a)
}
func (a F64) Cubed() F64 {
return a.Mul(a).Mul(a)
}
func (a F64) Sqrt() F64 {
return NewF64(math.Sqrt(a.value))
}
func (a F64) Cbrt() F64 {
return NewF64(math.Cbrt(a.value))
}
func (a F64) Add(b F64) F64 {
return NewF64(a.value + b.value)
}
func (a F64) AddConst(b float64) F64 {
return NewF64(a.value + b)
}
func (a F64) Sub(b F64) F64 {
return NewF64(a.value - b.value)
}
func (a F64) SubConst(b float64) F64 {
return NewF64(a.value - b)
}
func (a F64) Mul(b F64) F64 {
return NewF64(a.value * b.value)
}
func (a F64) MulConst(b float64) F64 {
return NewF64(a.value * b)
}
func (a F64) Div(b F64) F64 {
return NewF64(a.value / b.value)
}
func (a F64) DivConst(b float64) F64 {
return NewF64(a.value / b)
}
func (a F64) Pow(b F64) F64 {
return NewF64(math.Pow(a.value, b.value))
}
func (a F64) PowConst(b float64) F64 {
return NewF64(math.Pow(a.value, b))
}
func (a F64) Atan2(b F64) F64 {
return NewF64(math.Atan2(a.value, b.value))
}
func (a F64) WithSignFrom(b F64) F64 {
return NewF64(math.Copysign(a.value, b.value))
}
func Min2(a F64, b F64) F64 {
return NewF64(math.Min(a.value, b.value))
}
func Max2(a F64, b F64) F64 {
return NewF64(math.Max(a.value, b.value))
}
func Min3(a F64, b F64, c F64) F64 {
return NewF64(math.Min(math.Min(a.value, b.value), c.value))
}
func Max3(a F64, b F64, c F64) F64 {
return NewF64(math.Max(math.Max(a.value, b.value), c.value))
}
func Lerp(a F64, b F64, t F64) F64 {
return b.Sub(a).Mul(t).Add(a)
}