Coverage Report

Created: 2025-10-12 08:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}