Coverage Report

Created: 2025-11-11 07:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/pxfm-0.1.25/src/err/erffc.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::{dd_fmla, f_fmla};
30
use std::hint::black_box;
31
32
static ERR0: [u64; 128] = [
33
    0x3ff0000000000000,
34
    0x3ff0163da9fb3335,
35
    0x3ff02c9a3e778061,
36
    0x3ff04315e86e7f85,
37
    0x3ff059b0d3158574,
38
    0x3ff0706b29ddf6de,
39
    0x3ff0874518759bc8,
40
    0x3ff09e3ecac6f383,
41
    0x3ff0b5586cf9890f,
42
    0x3ff0cc922b7247f7,
43
    0x3ff0e3ec32d3d1a2,
44
    0x3ff0fb66affed31b,
45
    0x3ff11301d0125b51,
46
    0x3ff12abdc06c31cc,
47
    0x3ff1429aaea92de0,
48
    0x3ff15a98c8a58e51,
49
    0x3ff172b83c7d517b,
50
    0x3ff18af9388c8dea,
51
    0x3ff1a35beb6fcb75,
52
    0x3ff1bbe084045cd4,
53
    0x3ff1d4873168b9aa,
54
    0x3ff1ed5022fcd91d,
55
    0x3ff2063b88628cd6,
56
    0x3ff21f49917ddc96,
57
    0x3ff2387a6e756238,
58
    0x3ff251ce4fb2a63f,
59
    0x3ff26b4565e27cdd,
60
    0x3ff284dfe1f56381,
61
    0x3ff29e9df51fdee1,
62
    0x3ff2b87fd0dad990,
63
    0x3ff2d285a6e4030b,
64
    0x3ff2ecafa93e2f56,
65
    0x3ff306fe0a31b715,
66
    0x3ff32170fc4cd831,
67
    0x3ff33c08b26416ff,
68
    0x3ff356c55f929ff1,
69
    0x3ff371a7373aa9cb,
70
    0x3ff38cae6d05d866,
71
    0x3ff3a7db34e59ff7,
72
    0x3ff3c32dc313a8e5,
73
    0x3ff3dea64c123422,
74
    0x3ff3fa4504ac801c,
75
    0x3ff4160a21f72e2a,
76
    0x3ff431f5d950a897,
77
    0x3ff44e086061892d,
78
    0x3ff46a41ed1d0057,
79
    0x3ff486a2b5c13cd0,
80
    0x3ff4a32af0d7d3de,
81
    0x3ff4bfdad5362a27,
82
    0x3ff4dcb299fddd0d,
83
    0x3ff4f9b2769d2ca7,
84
    0x3ff516daa2cf6642,
85
    0x3ff5342b569d4f82,
86
    0x3ff551a4ca5d920f,
87
    0x3ff56f4736b527da,
88
    0x3ff58d12d497c7fd,
89
    0x3ff5ab07dd485429,
90
    0x3ff5c9268a5946b7,
91
    0x3ff5e76f15ad2148,
92
    0x3ff605e1b976dc09,
93
    0x3ff6247eb03a5585,
94
    0x3ff6434634ccc320,
95
    0x3ff6623882552225,
96
    0x3ff68155d44ca973,
97
    0x3ff6a09e667f3bcd,
98
    0x3ff6c012750bdabf,
99
    0x3ff6dfb23c651a2f,
100
    0x3ff6ff7df9519484,
101
    0x3ff71f75e8ec5f74,
102
    0x3ff73f9a48a58174,
103
    0x3ff75feb564267c9,
104
    0x3ff780694fde5d3f,
105
    0x3ff7a11473eb0187,
106
    0x3ff7c1ed0130c132,
107
    0x3ff7e2f336cf4e62,
108
    0x3ff80427543e1a12,
109
    0x3ff82589994cce13,
110
    0x3ff8471a4623c7ad,
111
    0x3ff868d99b4492ed,
112
    0x3ff88ac7d98a6699,
113
    0x3ff8ace5422aa0db,
114
    0x3ff8cf3216b5448c,
115
    0x3ff8f1ae99157736,
116
    0x3ff9145b0b91ffc6,
117
    0x3ff93737b0cdc5e5,
118
    0x3ff95a44cbc8520f,
119
    0x3ff97d829fde4e50,
120
    0x3ff9a0f170ca07ba,
121
    0x3ff9c49182a3f090,
122
    0x3ff9e86319e32323,
123
    0x3ffa0c667b5de565,
124
    0x3ffa309bec4a2d33,
125
    0x3ffa5503b23e255d,
126
    0x3ffa799e1330b358,
127
    0x3ffa9e6b5579fdbf,
128
    0x3ffac36bbfd3f37a,
129
    0x3ffae89f995ad3ad,
130
    0x3ffb0e07298db666,
131
    0x3ffb33a2b84f15fb,
132
    0x3ffb59728de5593a,
133
    0x3ffb7f76f2fb5e47,
134
    0x3ffba5b030a1064a,
135
    0x3ffbcc1e904bc1d2,
136
    0x3ffbf2c25bd71e09,
137
    0x3ffc199bdd85529c,
138
    0x3ffc40ab5fffd07a,
139
    0x3ffc67f12e57d14b,
140
    0x3ffc8f6d9406e7b5,
141
    0x3ffcb720dcef9069,
142
    0x3ffcdf0b555dc3fa,
143
    0x3ffd072d4a07897c,
144
    0x3ffd2f87080d89f2,
145
    0x3ffd5818dcfba487,
146
    0x3ffd80e316c98398,
147
    0x3ffda9e603db3285,
148
    0x3ffdd321f301b460,
149
    0x3ffdfc97337b9b5f,
150
    0x3ffe264614f5a129,
151
    0x3ffe502ee78b3ff6,
152
    0x3ffe7a51fbc74c83,
153
    0x3ffea4afa2a490da,
154
    0x3ffecf482d8e67f1,
155
    0x3ffefa1bee615a27,
156
    0x3fff252b376bba97,
157
    0x3fff50765b6e4540,
158
    0x3fff7bfdad9cbe14,
159
    0x3fffa7c1819e90d8,
160
    0x3fffd3c22b8f71f1,
161
];
162
163
static ERFC_COEFFS: [[u64; 16]; 2] = [
164
    [
165
        0x3fec162355429b28,
166
        0x400d99999999999a,
167
        0x3fdda951cece2b85,
168
        0xbff70ef6cff4bcc4,
169
        0x4003d7f7b3d617de,
170
        0xc009d0aa47537c51,
171
        0x4009754ea9a3fcb1,
172
        0xc0027a5453fcc015,
173
        0x3ff1ef2e0531aeba,
174
        0xbfceca090f5a1c06,
175
        0xbfb7a3cd173a063c,
176
        0x3fb30fa68a68fddd,
177
        0x3f555ad9a326993a,
178
        0xbf907e7b0bb39fbf,
179
        0x3f52328706c0e950,
180
        0x3f6d6aa0b7b19cfe,
181
    ],
182
    [
183
        0x401137c8983f8516,
184
        0x400799999999999a,
185
        0x3fc05b53aa241333,
186
        0xbfca3f53872bf870,
187
        0x3fbde4c30742c9d5,
188
        0xbfacb24bfa591986,
189
        0x3f9666aec059ca5f,
190
        0xbf7a61250eb26b0b,
191
        0x3f52b28b7924b34d,
192
        0x3f041b13a9d45013,
193
        0xbf16dd5e8a273613,
194
        0x3ef09ce8ea5e8da5,
195
        0x3ed33923b4102981,
196
        0xbec1dfd161e3f984,
197
        0xbe8c87618fcae3b3,
198
        0x3e8e8a6ffa0ba2c7,
199
    ],
200
];
201
202
/// Complementary error function
203
///
204
/// Max ULP 0.5
205
0
pub fn f_erfcf(x: f32) -> f32 {
206
0
    let ax = f32::from_bits(x.to_bits() & 0x7fff_ffff);
207
0
    let axd = ax as f64;
208
0
    let x2 = axd * axd;
209
0
    let t = x.to_bits();
210
0
    let at = t & 0x7fff_ffff;
211
0
    let sgn = t >> 31;
212
0
    let i: i64 = (at > 0x40051000) as i64;
213
    /* for x < -0x1.ea8f94p+1, erfc(x) rounds to 2 (to nearest) */
214
0
    if t > 0xc07547cau32 {
215
        // x < -0x1.ea8f94p+1
216
0
        if t >= 0xff800000u32 {
217
            // -Inf or NaN
218
0
            if t == 0xff800000u32 {
219
0
                return 2.0;
220
0
            } // -Inf
221
0
            return x + x; // NaN
222
0
        }
223
0
        return black_box(2.0) - black_box(f32::from_bits(0x33000000)); // rounds to 2 or nextbelow(2)
224
0
    }
225
    /* at is the absolute value of x
226
    for x >= 0x1.41bbf8p+3, erfc(x) < 2^-150, thus rounds to 0 or to 2^-149
227
    depending on the rounding mode */
228
0
    if at >= 0x4120ddfcu32 {
229
        // |x| >= 0x1.41bbf8p+3
230
0
        if at >= 0x7f800000u32 {
231
            // +Inf or NaN
232
0
            if at == 0x7f800000u32 {
233
0
                return 0.0;
234
0
            } // +Inf
235
0
            return x + x; // NaN
236
0
        }
237
        // 0x1p-149f * 0.25f rounds to 0 or 2^-149 depending on rounding
238
0
        return black_box(f32::from_bits(0x00000001)) * black_box(0.25);
239
0
    }
240
0
    if at <= 0x3db80000u32 {
241
        // |x| <= 0x1.7p-4
242
0
        if t == 0xb76c9f62u32 {
243
            // x = -0x1.d93ec4p-17
244
0
            return black_box(f32::from_bits(0x3f800085)) + black_box(f32::from_bits(0x33000000)); // exceptional case
245
0
        }
246
        /* for |x| <= 0x1.c5bf88p-26. erfc(x) rounds to 1 (to nearest) */
247
0
        if at <= 0x32e2dfc4u32 {
248
            // |x| <= 0x1.c5bf88p-26
249
0
            if at == 0 {
250
0
                return 1.0;
251
0
            }
252
            static D: [f32; 2] = [f32::from_bits(0xb2800000), f32::from_bits(0x33000000)];
253
0
            return 1.0 + D[sgn as usize];
254
0
        }
255
        /* around 0, erfc(x) behaves as 1 - (odd polynomial) */
256
        const C: [u64; 5] = [
257
            0x3ff20dd750429b6d,
258
            0xbfd812746b03610b,
259
            0x3fbce2f218831d2f,
260
            0xbf9b82c609607dcb,
261
            0x3f7553af09b8008e,
262
        ];
263
264
0
        let fw0 = f_fmla(x2, f64::from_bits(C[4]), f64::from_bits(C[3]));
265
0
        let fw1 = f_fmla(x2, fw0, f64::from_bits(C[2]));
266
0
        let fw2 = f_fmla(x2, fw1, f64::from_bits(C[1]));
267
268
0
        let f0 = x as f64 * f_fmla(x2, fw2, f64::from_bits(C[0]));
269
0
        return (1.0 - f0) as f32;
270
0
    }
271
272
    /* now -0x1.ea8f94p+1 <= x <= 0x1.41bbf8p+3, with |x| > 0x1.7p-4 */
273
    const ILN2: f64 = f64::from_bits(0x3ff71547652b82fe);
274
    const LN2H: f64 = f64::from_bits(0x3f762e42fefa0000);
275
    const LN2L: f64 = f64::from_bits(0x3d0cf79abd6f5dc8);
276
277
0
    let jt = dd_fmla(x2, ILN2, -(1024. + f64::from_bits(0x3f70000000000000))).to_bits();
278
0
    let j: i64 = ((jt << 12) as i64) >> 48;
279
0
    let sf = ((j >> 7) as u64)
280
0
        .wrapping_add(0x3ffu64 | (sgn as u64) << 11)
281
0
        .wrapping_shl(52);
282
283
    const CH: [u64; 4] = [
284
        0xbfdffffffffff333,
285
        0x3fc5555555556a14,
286
        0xbfa55556666659b4,
287
        0x3f81111074cc7b22,
288
    ];
289
0
    let d = f_fmla(LN2L, j as f64, f_fmla(LN2H, j as f64, x2));
290
0
    let d2 = d * d;
291
0
    let e0 = f64::from_bits(ERR0[(j & 127) as usize]);
292
293
0
    let fw0 = f_fmla(d, f64::from_bits(CH[3]), f64::from_bits(CH[2]));
294
0
    let fw1 = f_fmla(d, f64::from_bits(CH[1]), f64::from_bits(CH[0]));
295
0
    let fw2 = f_fmla(d2, fw0, fw1);
296
297
0
    let f = f_fmla(d2, fw2, d);
298
299
0
    let ct = ERFC_COEFFS[i as usize];
300
0
    let z = (axd - f64::from_bits(ct[0])) / (axd + f64::from_bits(ct[1]));
301
0
    let z2 = z * z;
302
0
    let z4 = z2 * z2;
303
0
    let z8 = z4 * z4;
304
0
    let c = &ct[3..];
305
306
0
    let sw0 = f_fmla(z, f64::from_bits(c[1]), f64::from_bits(c[0]));
307
0
    let sw1 = f_fmla(z, f64::from_bits(c[3]), f64::from_bits(c[2]));
308
0
    let sw2 = f_fmla(z, f64::from_bits(c[5]), f64::from_bits(c[4]));
309
0
    let sw3 = f_fmla(z, f64::from_bits(c[7]), f64::from_bits(c[6]));
310
311
0
    let zw0 = f_fmla(z2, sw1, sw0);
312
0
    let zw1 = f_fmla(z2, sw3, sw2);
313
314
0
    let sw4 = f_fmla(z, f64::from_bits(c[9]), f64::from_bits(c[8]));
315
0
    let sw5 = f_fmla(z, f64::from_bits(c[11]), f64::from_bits(c[10]));
316
317
0
    let zw2 = f_fmla(z4, zw1, zw0);
318
0
    let zw3 = f_fmla(z2, sw5, sw4);
319
0
    let zw4 = f_fmla(z4, f64::from_bits(c[12]), zw3);
320
321
0
    let mut s = f_fmla(z8, zw4, zw2);
322
323
0
    s = f_fmla(z, s, f64::from_bits(ct[2]));
324
325
    static OFF: [f64; 2] = [0., 2.];
326
327
0
    let r = (f64::from_bits(sf) * f_fmla(-f, e0, e0)) * s;
328
0
    let y = OFF[sgn as usize] + r;
329
0
    y as f32
330
0
}
331
332
#[cfg(test)]
333
mod tests {
334
    use crate::f_erfcf;
335
336
    #[test]
337
    fn test_erfc() {
338
        assert_eq!(f_erfcf(0.0), 1.0);
339
        assert_eq!(f_erfcf(0.5), 0.47950011);
340
        assert_eq!(f_erfcf(1.0), 0.1572992);
341
        assert!(f_erfcf(f32::NAN).is_nan());
342
        assert_eq!(f_erfcf(f32::INFINITY), 0.0);
343
        assert_eq!(f_erfcf(f32::NEG_INFINITY), 2.0);
344
    }
345
}