/rust/registry/src/index.crates.io-1949cf8c6b5b557f/pxfm-0.1.25/src/triple_double.rs
Line | Count | Source |
1 | | /* |
2 | | * // Copyright (c) Radzivon Bartoshyk 7/2025. All rights reserved. |
3 | | * // |
4 | | * // Redistribution and use in source and binary forms, with or without modification, |
5 | | * // are permitted provided that the following conditions are met: |
6 | | * // |
7 | | * // 1. Redistributions of source code must retain the above copyright notice, this |
8 | | * // list of conditions and the following disclaimer. |
9 | | * // |
10 | | * // 2. Redistributions in binary form must reproduce the above copyright notice, |
11 | | * // this list of conditions and the following disclaimer in the documentation |
12 | | * // and/or other materials provided with the distribution. |
13 | | * // |
14 | | * // 3. Neither the name of the copyright holder nor the names of its |
15 | | * // contributors may be used to endorse or promote products derived from |
16 | | * // this software without specific prior written permission. |
17 | | * // |
18 | | * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
19 | | * // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
20 | | * // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
21 | | * // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
22 | | * // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
23 | | * // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
24 | | * // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
25 | | * // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
26 | | * // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
27 | | * // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 | | */ |
29 | | use crate::common::f_fmla; |
30 | | use crate::double_double::DoubleDouble; |
31 | | use std::ops::Neg; |
32 | | |
33 | | #[derive(Clone, Copy, Debug)] |
34 | | pub(crate) struct TripleDouble { |
35 | | pub(crate) hi: f64, |
36 | | pub(crate) mid: f64, |
37 | | pub(crate) lo: f64, |
38 | | } |
39 | | |
40 | | // impl TripleDouble { |
41 | | // #[inline] |
42 | | // pub(crate) fn mul_dd_add_f64(p0: TripleDouble, p1: DoubleDouble, p2: f64) -> TripleDouble { |
43 | | // let q0 = TripleDouble::quick_mul_dd(p0, p1); |
44 | | // TripleDouble::add_f64(p2, q0) |
45 | | // } |
46 | | // } |
47 | | |
48 | | impl TripleDouble { |
49 | | // #[inline] |
50 | | // pub(crate) fn mul_dd_add(p0: TripleDouble, p1: DoubleDouble, p2: TripleDouble) -> TripleDouble { |
51 | | // let q0 = TripleDouble::quick_mul_dd(p0, p1); |
52 | | // TripleDouble::add(q0, p2) |
53 | | // } |
54 | | |
55 | | // #[inline] |
56 | | // pub(crate) fn mul_dd_add_dd( |
57 | | // p0: TripleDouble, |
58 | | // p1: DoubleDouble, |
59 | | // p2: DoubleDouble, |
60 | | // ) -> TripleDouble { |
61 | | // let q0 = TripleDouble::quick_mul_dd(p0, p1); |
62 | | // TripleDouble::add_dd(p2, q0) |
63 | | // } |
64 | | } |
65 | | |
66 | | impl TripleDouble { |
67 | | #[inline] |
68 | 0 | pub(crate) fn f64_mul_dd_add(p0: f64, p1: DoubleDouble, p2: TripleDouble) -> TripleDouble { |
69 | 0 | let q0 = TripleDouble::from_quick_mult_dd_f64(p1, p0); |
70 | 0 | TripleDouble::add(q0, p2) |
71 | 0 | } |
72 | | |
73 | | #[inline] |
74 | 0 | pub(crate) fn f64_mul_add(p0: f64, p1: TripleDouble, p2: TripleDouble) -> TripleDouble { |
75 | 0 | let q0 = TripleDouble::quick_mult_f64(p1, p0); |
76 | 0 | TripleDouble::add(q0, p2) |
77 | 0 | } |
78 | | } |
79 | | |
80 | | impl TripleDouble { |
81 | | #[inline] |
82 | 0 | pub(crate) const fn from_bit_pair(p0: (u64, u64, u64)) -> TripleDouble { |
83 | 0 | TripleDouble { |
84 | 0 | hi: f64::from_bits(p0.2), |
85 | 0 | mid: f64::from_bits(p0.1), |
86 | 0 | lo: f64::from_bits(p0.0), |
87 | 0 | } |
88 | 0 | } |
89 | | } |
90 | | |
91 | | #[inline] |
92 | 0 | fn add12(a: f64, b: f64) -> DoubleDouble { |
93 | 0 | DoubleDouble::from_full_exact_add(a, b) |
94 | 0 | } |
95 | | |
96 | | #[inline] |
97 | 0 | fn mul12(a: f64, b: f64) -> DoubleDouble { |
98 | 0 | DoubleDouble::from_exact_mult(a, b) |
99 | 0 | } |
100 | | |
101 | | #[inline] |
102 | 0 | pub(crate) fn add22(a: DoubleDouble, b: DoubleDouble) -> DoubleDouble { |
103 | 0 | let DoubleDouble { hi: v1, lo: v2 } = DoubleDouble::from_full_exact_add(a.hi, b.hi); |
104 | 0 | let v3 = a.lo + b.lo; |
105 | 0 | let v4 = v2 + v3; |
106 | 0 | DoubleDouble::from_full_exact_add(v1, v4) |
107 | 0 | } |
108 | | |
109 | | impl TripleDouble { |
110 | | // #[inline] |
111 | | // pub(crate) fn from_quick_mult_dd(a: DoubleDouble, b: DoubleDouble) -> TripleDouble { |
112 | | // /* |
113 | | // (rh , t1) ← Mul12 (ah , bh ) |
114 | | // (t2, t3) ← Mul12 (ah , bl ) |
115 | | // (t4, t5) ← Mul12 (al , bh ) |
116 | | // t6 ← al ⊗ bl |
117 | | // (t7, t8) ← Add22 (t2, t3, t4, t5) |
118 | | // (t9, t10) ← Add12 (t1, t6) |
119 | | // (rm , rl ) ← Add22 (t7, t8, t9, t10) |
120 | | // */ |
121 | | // let DoubleDouble { hi: rh, lo: t1 } = mul12(a.hi, b.hi); |
122 | | // let r0 = mul12(a.hi, b.lo); |
123 | | // let r1 = mul12(a.lo, b.hi); |
124 | | // let t6 = a.lo * b.lo; |
125 | | // let q0 = add22(r0, r1); |
126 | | // let q1 = add12(t1, t6); |
127 | | // let DoubleDouble { hi: rm, lo: rl } = add22(q0, q1); |
128 | | // TripleDouble { |
129 | | // hi: rh, |
130 | | // mid: rm, |
131 | | // lo: rl, |
132 | | // } |
133 | | // } |
134 | | |
135 | | #[inline] |
136 | 0 | pub(crate) fn from_quick_mult_dd_f64(a: DoubleDouble, b: f64) -> TripleDouble { |
137 | 0 | let DoubleDouble { hi: rh, lo: t1 } = mul12(a.hi, b); |
138 | 0 | let DoubleDouble { hi: t2, lo: t3 } = mul12(a.lo, b); |
139 | 0 | let DoubleDouble { hi: t5, lo: t4 } = add12(t1, t2); |
140 | 0 | let t6 = t3 + t4; |
141 | 0 | let DoubleDouble { hi: rm, lo: rl } = add12(t5, t6); |
142 | 0 | TripleDouble::new(rl, rm, rh) |
143 | 0 | } |
144 | | |
145 | | #[inline] |
146 | 0 | pub(crate) fn quick_mult_f64(a: TripleDouble, b: f64) -> TripleDouble { |
147 | 0 | let DoubleDouble { hi: rh, lo: t2 } = mul12(a.hi, b); |
148 | 0 | let DoubleDouble { hi: t3, lo: t4 } = mul12(a.mid, b); |
149 | 0 | let DoubleDouble { hi: t9, lo: t7 } = add12(t2, t3); |
150 | 0 | let t8 = f_fmla(a.lo, b, t4); |
151 | 0 | let t10 = t7 + t8; |
152 | 0 | let DoubleDouble { hi: rm, lo: rl } = add12(t9, t10); |
153 | 0 | TripleDouble::new(rl, rm, rh) |
154 | 0 | } |
155 | | |
156 | | #[inline] |
157 | 0 | pub(crate) fn quick_mult(b: TripleDouble, a: TripleDouble) -> TripleDouble { |
158 | | /* Mul12((resh),&_t1,(ah),(bh)); |
159 | | Mul12(&_t2,&_t3,(ah),(bm)); |
160 | | Mul12(&_t4,&_t5,(am),(bh)); |
161 | | Mul12(&_t6,&_t7,(am),(bm)); |
162 | | _t8 = (ah) * (bl); |
163 | | _t9 = (al) * (bh); |
164 | | _t10 = (am) * (bl); |
165 | | _t11 = (al) * (bm); |
166 | | _t12 = _t8 + _t9; |
167 | | _t13 = _t10 + _t11; |
168 | | Add12Cond(_t14,_t15,_t1,_t6); |
169 | | _t16 = _t7 + _t15; |
170 | | _t17 = _t12 + _t13; |
171 | | _t18 = _t16 + _t17; |
172 | | Add12Cond(_t19,_t20,_t14,_t18); |
173 | | Add22Cond(&_t21,&_t22,_t2,_t3,_t4,_t5); |
174 | | Add22Cond((resm),(resl),_t21,_t22,_t19,_t20); */ |
175 | 0 | let DoubleDouble { hi: rh, lo: t1 } = DoubleDouble::from_exact_mult(a.hi, b.hi); |
176 | 0 | let DoubleDouble { hi: t2, lo: t3 } = DoubleDouble::from_exact_mult(a.hi, b.mid); |
177 | 0 | let DoubleDouble { hi: t4, lo: t5 } = DoubleDouble::from_exact_mult(a.mid, b.hi); |
178 | 0 | let DoubleDouble { hi: t6, lo: t7 } = DoubleDouble::from_exact_mult(a.mid, b.mid); |
179 | 0 | let t12 = f_fmla(a.hi, b.lo, a.lo * b.hi); |
180 | 0 | let t13 = f_fmla(a.mid, b.lo, a.lo * b.mid); |
181 | 0 | let DoubleDouble { hi: t14, lo: t15 } = add12(t1, t6); |
182 | 0 | let t16 = t7 + t15; |
183 | 0 | let t17 = t12 + t13; |
184 | 0 | let t18 = t16 + t17; |
185 | 0 | let DoubleDouble { hi: t19, lo: t20 } = add12(t14, t18); |
186 | 0 | let DoubleDouble { hi: t21, lo: t22 } = |
187 | 0 | add22(DoubleDouble::new(t3, t2), DoubleDouble::new(t4, t5)); |
188 | 0 | let DoubleDouble { hi: rm, lo: rl } = |
189 | 0 | add22(DoubleDouble::new(t22, t21), DoubleDouble::new(t20, t19)); |
190 | 0 | TripleDouble::new(rl, rm, rh) |
191 | 0 | } |
192 | | |
193 | | #[inline] |
194 | 0 | pub(crate) fn quick_mult_dd(b: TripleDouble, a: DoubleDouble) -> TripleDouble { |
195 | | /* |
196 | | (rh , t1) ← Mul12 (ah , bh ) |
197 | | (t2, t3) ← Mul12 (ah , bm ) |
198 | | (t4, t5) ← Mul12 (ah , bl ) |
199 | | (t6, t7) ← Mul12 (al , bh ) |
200 | | (t8, t9) ← Mul12 (al , bm ) |
201 | | t10 ← al ⊗ bl |
202 | | (t11, t12) ← Add22 (t2, t3, t4, t5) |
203 | | (t13, t14) ← Add22 (t6, t7, t8, t9) |
204 | | (t15, t16) ← Add22 (t11, t12, t13, t14) |
205 | | (t17, t18) ← Add12 (t1, t10) |
206 | | (rm , rl ) ← Add22 (t17, t18, t15, t16) |
207 | | */ |
208 | 0 | let DoubleDouble { hi: rh, lo: t1 } = mul12(a.hi, b.hi); |
209 | 0 | let DoubleDouble { hi: t2, lo: t3 } = mul12(a.hi, b.mid); |
210 | 0 | let DoubleDouble { hi: t4, lo: t5 } = mul12(a.hi, b.lo); |
211 | 0 | let DoubleDouble { hi: t6, lo: t7 } = mul12(a.lo, b.hi); |
212 | 0 | let DoubleDouble { hi: t8, lo: t9 } = mul12(a.lo, b.mid); |
213 | 0 | let t10 = a.lo * b.lo; |
214 | 0 | let z0 = add22(DoubleDouble::new(t3, t2), DoubleDouble::new(t4, t5)); |
215 | 0 | let z1 = add22(DoubleDouble::new(t6, t7), DoubleDouble::new(t8, t9)); |
216 | 0 | let q0 = add22(z0, z1); |
217 | 0 | let q1 = add12(t1, t10); |
218 | 0 | let DoubleDouble { hi: rm, lo: rl } = add22(q1, q0); |
219 | 0 | TripleDouble { |
220 | 0 | hi: rh, |
221 | 0 | mid: rm, |
222 | 0 | lo: rl, |
223 | 0 | } |
224 | 0 | } |
225 | | |
226 | 0 | pub(crate) fn add(a: TripleDouble, b: TripleDouble) -> TripleDouble { |
227 | | /* |
228 | | (rh , t1) ← Add12 (ah , bh ) |
229 | | (t2, t3) ← Add12 (am , bm ) |
230 | | (t7, t4) ← Add12 (t1, t2) |
231 | | t6 ← al ⊕ bl |
232 | | t5 ← t3 ⊕ t4 |
233 | | t8 ← t5 ⊕ t6 |
234 | | (rm , rl ) ← Add12 (t7, t8) |
235 | | */ |
236 | 0 | let DoubleDouble { hi: rh, lo: t1 } = add12(a.hi, b.hi); |
237 | 0 | let DoubleDouble { hi: t2, lo: t3 } = add12(a.mid, b.mid); |
238 | 0 | let t6 = a.lo + b.lo; |
239 | 0 | let DoubleDouble { hi: t7, lo: t4 } = add12(t1, t2); |
240 | 0 | let t5 = t3 + t4; |
241 | 0 | let t8 = t5 + t6; |
242 | 0 | let DoubleDouble { hi: rm, lo: rl } = add12(t7, t8); |
243 | 0 | TripleDouble { |
244 | 0 | hi: rh, |
245 | 0 | mid: rm, |
246 | 0 | lo: rl, |
247 | 0 | } |
248 | 0 | } |
249 | | |
250 | | // #[inline] |
251 | | // pub(crate) fn add_dd(a: DoubleDouble, b: TripleDouble) -> TripleDouble { |
252 | | // /* |
253 | | // (rh , t1) ← Add12 (ah , bh ) |
254 | | // (t2, t3) ← Add12 (al , bm ) |
255 | | // (t4, t5) ← Add12 (t1, t2) |
256 | | // t6 ← t3 ⊕ bl |
257 | | // t7 ← t6 ⊕ t5 |
258 | | // (rm , rl ) ← Add12 (t4, t7) |
259 | | // */ |
260 | | // let DoubleDouble { hi: rh, lo: t1 } = add12(a.hi, b.hi); |
261 | | // let DoubleDouble { hi: t2, lo: t3 } = add12(a.hi, b.mid); |
262 | | // let DoubleDouble { hi: t4, lo: t5 } = add12(t1, t2); |
263 | | // let t6 = t3 + b.lo; |
264 | | // let t7 = t6 + t5; |
265 | | // let DoubleDouble { hi: rm, lo: rl } = add12(t4, t7); |
266 | | // TripleDouble { |
267 | | // hi: rh, |
268 | | // mid: rm, |
269 | | // lo: rl, |
270 | | // } |
271 | | // } |
272 | | |
273 | | #[inline] |
274 | 0 | pub(crate) fn add_f64(a: f64, b: TripleDouble) -> TripleDouble { |
275 | 0 | let DoubleDouble { hi: rh, lo: t1 } = add12(a, b.hi); |
276 | 0 | let DoubleDouble { hi: t2, lo: t3 } = add12(t1, b.mid); |
277 | 0 | let t4 = t3 + b.lo; |
278 | 0 | let DoubleDouble { hi: rm, lo: rl } = add12(t2, t4); |
279 | 0 | TripleDouble::new(rl, rm, rh) |
280 | 0 | } |
281 | | |
282 | | // #[inline] |
283 | | // pub(crate) fn to_dd(self) -> DoubleDouble { |
284 | | // let DoubleDouble { hi: t1, lo: t2 } = add12(self.hi, self.mid); |
285 | | // let t3 = t2 + self.lo; |
286 | | // DoubleDouble::new(t3, t1) |
287 | | // } |
288 | | |
289 | | #[inline] |
290 | 0 | pub(crate) const fn new(lo: f64, mid: f64, hi: f64) -> Self { |
291 | 0 | Self { hi, mid, lo } |
292 | 0 | } |
293 | | |
294 | | #[inline] |
295 | 0 | pub(crate) fn to_f64(self) -> f64 { |
296 | 0 | let DoubleDouble { hi: t1, lo: t2 } = add12(self.hi, self.mid); |
297 | 0 | let t3 = t2 + self.lo; |
298 | 0 | t1 + t3 |
299 | 0 | } |
300 | | |
301 | | #[inline] |
302 | 0 | pub(crate) fn from_full_exact_add(a: f64, b: f64) -> Self { |
303 | 0 | let DoubleDouble { hi: rh, lo: t1 } = add12(a, b); |
304 | 0 | TripleDouble::new(0., t1, rh).renormalize() |
305 | 0 | } |
306 | | |
307 | | #[inline] |
308 | 0 | pub(crate) fn renormalize(self) -> Self { |
309 | | /* |
310 | | double _t1h, _t1l, _t2l; |
311 | | |
312 | | Add12(_t1h, _t1l, (am), (al)); |
313 | | Add12((*(resh)), _t2l, (ah), (_t1h)); |
314 | | Add12((*(resm)), (*(resl)), _t2l, _t1l); |
315 | | */ |
316 | 0 | let DoubleDouble { hi: t1h, lo: t1l } = DoubleDouble::from_exact_add(self.mid, self.lo); |
317 | 0 | let DoubleDouble { hi: rh, lo: t2l } = DoubleDouble::from_exact_add(self.hi, t1h); |
318 | 0 | let zml = DoubleDouble::from_exact_add(t2l, t1l); |
319 | 0 | TripleDouble::new(zml.lo, zml.hi, rh) |
320 | 0 | } |
321 | | |
322 | | #[inline] |
323 | 0 | pub(crate) fn recip(self) -> Self { |
324 | | /* |
325 | | _rec_r1 = 1.0 / (dh); |
326 | | Mul12(&_rec_t1,&_rec_t2,_rec_r1,(dh)); |
327 | | _rec_t3 = _rec_t1 - 1.0; |
328 | | Add12Cond(_rec_t4,_rec_t5,_rec_t3,_rec_t2); |
329 | | Mul12(&_rec_t6,&_rec_t7,_rec_r1,(dm)); |
330 | | Add12(_rec_t8,_rec_t9,-1.0,_rec_t6); |
331 | | _rec_t10 = _rec_t9 + _rec_t7; |
332 | | Add12(_rec_t11,_rec_t12,_rec_t8,_rec_t10); |
333 | | _rec_r1 = -_rec_r1; |
334 | | Add22Cond(&_rec_t13,&_rec_t14,_rec_t4,_rec_t5,_rec_t11,_rec_t12); |
335 | | Mul122(&_rec_r2h,&_rec_r2l,_rec_r1,_rec_t13,_rec_t14); |
336 | | Mul233(&_rec_t15,&_rec_t16,&_rec_t17,_rec_r2h,_rec_r2l,(dh),(dm),(dl)); |
337 | | Renormalize3(&_rec_t18,&_rec_t19,&_rec_t20,_rec_t15,_rec_t16,_rec_t17); |
338 | | _rec_t18 = -1.0; |
339 | | Mul233(&_rec_t21,&_rec_t22,&_rec_t23,_rec_r2h,_rec_r2l,_rec_t18,_rec_t19,_rec_t20); |
340 | | _rec_t21 = -_rec_t21; _rec_t22 = -_rec_t22; _rec_t23 = -_rec_t23; |
341 | | Renormalize3((resh),(resm),(resl),_rec_t21,_rec_t22,_rec_t23); |
342 | | */ |
343 | 0 | let mut r1 = 1. / self.hi; |
344 | | let DoubleDouble { |
345 | 0 | hi: rec_t1, |
346 | 0 | lo: rec_t2, |
347 | 0 | } = DoubleDouble::from_exact_mult(r1, self.hi); |
348 | 0 | let rec_t3 = rec_t1 - 1.0; |
349 | | let DoubleDouble { |
350 | 0 | hi: rec_t4, |
351 | 0 | lo: rec_t5, |
352 | 0 | } = add12(rec_t3, rec_t2); |
353 | | let DoubleDouble { |
354 | 0 | hi: rec_t6, |
355 | 0 | lo: rec_t7, |
356 | 0 | } = mul12(r1, self.mid); |
357 | | let DoubleDouble { |
358 | 0 | hi: rec_t8, |
359 | 0 | lo: rec_t9, |
360 | 0 | } = add12(-1.0, rec_t6); |
361 | 0 | let rec_t10 = rec_t9 + rec_t7; |
362 | 0 | r1 = -r1; |
363 | | let DoubleDouble { |
364 | 0 | hi: rec_t11, |
365 | 0 | lo: rec_t12, |
366 | 0 | } = add12(rec_t8, rec_t10); |
367 | 0 | let z0 = add22( |
368 | 0 | DoubleDouble::new(rec_t5, rec_t4), |
369 | 0 | DoubleDouble::new(rec_t12, rec_t11), |
370 | | ); |
371 | 0 | let r2hl = DoubleDouble::quick_mult_f64(z0, r1); |
372 | 0 | let rec15_16_17 = TripleDouble::quick_mult_dd(self, r2hl); |
373 | 0 | let rec18_19_20 = rec15_16_17.renormalize(); |
374 | 0 | let rec_t18 = -1.0; |
375 | 0 | let rec_21_22_23 = -TripleDouble::quick_mult_dd( |
376 | 0 | TripleDouble::new(rec18_19_20.lo, rec18_19_20.mid, rec_t18), |
377 | 0 | r2hl, |
378 | 0 | ); |
379 | 0 | rec_21_22_23.renormalize() |
380 | 0 | } |
381 | | } |
382 | | |
383 | | impl Neg for TripleDouble { |
384 | | type Output = Self; |
385 | | #[inline] |
386 | 0 | fn neg(self) -> Self::Output { |
387 | 0 | TripleDouble::new(-self.lo, -self.mid, -self.hi) |
388 | 0 | } |
389 | | } |