1use std::ops::{Add, Div, Mul, Neg, Sub};
8
9#[derive(Clone, Copy, Debug, Default)]
11pub struct Jet3 {
12 pub v: f64,
13 pub d1: f64,
14 pub d2: f64,
15 pub d3: f64,
16}
17
18impl Jet3 {
19 #[inline(always)]
21 pub fn constant(v: f64) -> Self {
22 Self {
23 v,
24 d1: 0.0,
25 d2: 0.0,
26 d3: 0.0,
27 }
28 }
29
30 #[inline(always)]
32 pub fn seed(v: f64) -> Self {
33 Self {
34 v,
35 d1: 1.0,
36 d2: 0.0,
37 d3: 0.0,
38 }
39 }
40
41 #[inline(always)]
42 pub fn sin(self) -> Self {
43 let sv = self.v.sin();
44 let cv = self.v.cos();
45 let d1sq = self.d1 * self.d1;
46 let d1 = cv * self.d1;
47 let d2 = -sv * d1sq + cv * self.d2;
48 let d3 = -cv * d1sq * self.d1 - 3.0 * sv * self.d1 * self.d2 + cv * self.d3;
49 Self { v: sv, d1, d2, d3 }
50 }
51
52 #[inline(always)]
53 pub fn cos(self) -> Self {
54 let sv = self.v.sin();
55 let cv = self.v.cos();
56 let d1sq = self.d1 * self.d1;
57 let d1 = -sv * self.d1;
58 let d2 = -cv * d1sq - sv * self.d2;
59 let d3 = sv * d1sq * self.d1 - 3.0 * cv * self.d1 * self.d2 - sv * self.d3;
60 Self { v: cv, d1, d2, d3 }
61 }
62
63 #[inline(always)]
64 pub fn exp(self) -> Self {
65 let ev = self.v.exp();
66 let d1sq = self.d1 * self.d1;
67 let d1 = ev * self.d1;
68 let d2 = ev * (d1sq + self.d2);
69 let d3 = ev * (d1sq * self.d1 + 3.0 * self.d1 * self.d2 + self.d3);
70 Self { v: ev, d1, d2, d3 }
71 }
72
73 #[inline(always)]
74 pub fn ln(self) -> Self {
75 let v = self.v.ln();
76 let inv_x = 1.0 / self.v;
77 let inv_x2 = inv_x * inv_x;
78 let inv_x3 = inv_x2 * inv_x;
79 let d1sq = self.d1 * self.d1;
80 let d1 = inv_x * self.d1;
81 let d2 = -inv_x2 * d1sq + inv_x * self.d2;
82 let d3 = 2.0 * inv_x3 * d1sq * self.d1 - 3.0 * inv_x2 * self.d1 * self.d2 + inv_x * self.d3;
83 Self { v, d1, d2, d3 }
84 }
85
86 #[inline(always)]
87 pub fn sqrt(self) -> Self {
88 let sqrtv = self.v.sqrt();
89 let inv_sqrt = 1.0 / sqrtv;
90 let inv_v_sqrt = inv_sqrt / self.v;
91 let inv_v2_sqrt = inv_v_sqrt / self.v;
92 let d1sq = self.d1 * self.d1;
93 let d1 = 0.5 * inv_sqrt * self.d1;
94 let d2 = -0.25 * inv_v_sqrt * d1sq + 0.5 * inv_sqrt * self.d2;
95 let d3 = 0.375 * inv_v2_sqrt * d1sq * self.d1 - 0.75 * inv_v_sqrt * self.d1 * self.d2
96 + 0.5 * inv_sqrt * self.d3;
97 Self {
98 v: sqrtv,
99 d1,
100 d2,
101 d3,
102 }
103 }
104
105 #[inline(always)]
106 pub fn powi(self, n: i32) -> Self {
107 if n == 0 {
108 return Self::constant(1.0);
109 }
110 let nf = n as f64;
111 let vn3 = self.v.powi(n - 3);
115 let vn2 = vn3 * self.v;
116 let vn1 = vn2 * self.v;
117 let vn = vn1 * self.v;
118 let dv = nf * vn1;
119 let ddv = nf * (nf - 1.0) * vn2;
120 let dddv = nf * (nf - 1.0) * (nf - 2.0) * vn3;
121 let d1sq = self.d1 * self.d1;
122 let d1 = dv * self.d1;
123 let d2 = ddv * d1sq + dv * self.d2;
124 let d3 = dddv * d1sq * self.d1 + 3.0 * ddv * self.d1 * self.d2 + dv * self.d3;
125 Self { v: vn, d1, d2, d3 }
126 }
127
128 #[inline(always)]
129 fn inv(self) -> Self {
130 let v = 1.0 / self.v;
131 let inv_x2 = v * v;
132 let inv_x3 = inv_x2 * v;
133 let inv_x4 = inv_x3 * v;
134 let d1sq = self.d1 * self.d1;
135 let d1 = -inv_x2 * self.d1;
136 let d2 = 2.0 * inv_x3 * d1sq - inv_x2 * self.d2;
137 let d3 =
138 -6.0 * inv_x4 * d1sq * self.d1 + 6.0 * inv_x3 * self.d1 * self.d2 - inv_x2 * self.d3;
139 Self { v, d1, d2, d3 }
140 }
141}
142
143#[inline(always)]
144pub fn sin(x: Jet3) -> Jet3 {
145 x.sin()
146}
147
148#[inline(always)]
149pub fn cos(x: Jet3) -> Jet3 {
150 x.cos()
151}
152
153#[inline(always)]
154pub fn exp(x: Jet3) -> Jet3 {
155 x.exp()
156}
157
158#[inline(always)]
159pub fn ln(x: Jet3) -> Jet3 {
160 x.ln()
161}
162
163#[inline(always)]
164pub fn sqrt(x: Jet3) -> Jet3 {
165 x.sqrt()
166}
167
168#[inline(always)]
169pub fn powi(x: Jet3, n: i32) -> Jet3 {
170 x.powi(n)
171}
172
173impl From<f64> for Jet3 {
174 #[inline(always)]
175 fn from(value: f64) -> Self {
176 Self::constant(value)
177 }
178}
179
180impl Add for Jet3 {
181 type Output = Self;
182
183 #[inline(always)]
184 fn add(self, rhs: Self) -> Self::Output {
185 Self {
186 v: self.v + rhs.v,
187 d1: self.d1 + rhs.d1,
188 d2: self.d2 + rhs.d2,
189 d3: self.d3 + rhs.d3,
190 }
191 }
192}
193
194impl Add<f64> for Jet3 {
195 type Output = Self;
196
197 #[inline(always)]
198 fn add(self, rhs: f64) -> Self::Output {
199 Self {
200 v: self.v + rhs,
201 ..self
202 }
203 }
204}
205
206impl Add<Jet3> for f64 {
207 type Output = Jet3;
208
209 #[inline(always)]
210 fn add(self, rhs: Jet3) -> Self::Output {
211 rhs + self
212 }
213}
214
215impl Sub for Jet3 {
216 type Output = Self;
217
218 #[inline(always)]
219 fn sub(self, rhs: Self) -> Self::Output {
220 Self {
221 v: self.v - rhs.v,
222 d1: self.d1 - rhs.d1,
223 d2: self.d2 - rhs.d2,
224 d3: self.d3 - rhs.d3,
225 }
226 }
227}
228
229impl Sub<f64> for Jet3 {
230 type Output = Self;
231
232 #[inline(always)]
233 fn sub(self, rhs: f64) -> Self::Output {
234 Self {
235 v: self.v - rhs,
236 ..self
237 }
238 }
239}
240
241impl Sub<Jet3> for f64 {
242 type Output = Jet3;
243
244 #[inline(always)]
245 fn sub(self, rhs: Jet3) -> Self::Output {
246 Jet3::constant(self) - rhs
247 }
248}
249
250impl Mul for Jet3 {
251 type Output = Self;
252
253 #[inline(always)]
254 fn mul(self, rhs: Self) -> Self::Output {
255 Self {
256 v: self.v * rhs.v,
257 d1: self.d1 * rhs.v + self.v * rhs.d1,
258 d2: self.d2 * rhs.v + 2.0 * self.d1 * rhs.d1 + self.v * rhs.d2,
259 d3: self.d3 * rhs.v + 3.0 * (self.d2 * rhs.d1 + self.d1 * rhs.d2) + self.v * rhs.d3,
260 }
261 }
262}
263
264impl Mul<f64> for Jet3 {
265 type Output = Self;
266
267 #[inline(always)]
268 fn mul(self, rhs: f64) -> Self::Output {
269 Self {
270 v: self.v * rhs,
271 d1: self.d1 * rhs,
272 d2: self.d2 * rhs,
273 d3: self.d3 * rhs,
274 }
275 }
276}
277
278impl Mul<Jet3> for f64 {
279 type Output = Jet3;
280
281 #[inline(always)]
282 fn mul(self, rhs: Jet3) -> Self::Output {
283 rhs * self
284 }
285}
286
287impl Div for Jet3 {
288 type Output = Self;
289
290 #[allow(clippy::suspicious_arithmetic_impl)]
291 #[inline(always)]
292 fn div(self, rhs: Self) -> Self::Output {
293 self * rhs.inv()
294 }
295}
296
297impl Div<f64> for Jet3 {
298 type Output = Self;
299
300 #[inline(always)]
301 fn div(self, rhs: f64) -> Self::Output {
302 self * (1.0 / rhs)
303 }
304}
305
306impl Div<Jet3> for f64 {
307 type Output = Jet3;
308
309 #[inline(always)]
310 fn div(self, rhs: Jet3) -> Self::Output {
311 Jet3::constant(self) / rhs
312 }
313}
314
315impl Neg for Jet3 {
316 type Output = Self;
317
318 #[inline(always)]
319 fn neg(self) -> Self::Output {
320 Self {
321 v: -self.v,
322 d1: -self.d1,
323 d2: -self.d2,
324 d3: -self.d3,
325 }
326 }
327}