Coverage Report

Created: 2026-06-10 07:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/pxfm-0.1.29/src/err/inverfc.rs
Line
Count
Source
1
/*
2
 * // Copyright (c) Radzivon Bartoshyk 9/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 crate::logs::{fast_log_d_to_dd, fast_log_dd};
32
use crate::polyeval::{f_polyeval4, f_polyeval5};
33
34
#[cold]
35
0
fn inverf_0p06_to_0p75(x: DoubleDouble) -> DoubleDouble {
36
    // First step rational approximant is generated, but it's ill-conditioned, thus
37
    // we're using taylor expansion to create Newton form at the point.
38
    // Generated in Wolfram Mathematica:
39
    // <<FunctionApproximations`
40
    // ClearAll["Global`*"]
41
    // f[x_]:=InverseErf[x]/x
42
    // g[x_] =f[Sqrt[x]];
43
    // {err0,approx}=MiniMaxApproximation[g[z],{z,{0.06,0.75},9,9},WorkingPrecision->75, MaxIterations->100]
44
    // num=Numerator[approx][[1]];
45
    // den=Denominator[approx][[1]];
46
    // poly=den;
47
    // coeffs=CoefficientList[poly,z];
48
    // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
49
    // x0=SetPrecision[0.5625,75];
50
    // NumberForm[Series[num[x],{x,x0,50}], ExponentFunction->(Null&)]
51
    // coeffs=Table[SeriesCoefficient[num[x],{x,x0,k}],{k,0,9}];
52
    // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]];
53
    const P: [(u64, u64); 10] = [
54
        (0xbc3e06eda42202a0, 0x3f93c2fc5d00e0c8),
55
        (0xbc6eb374406b33b4, 0xbfc76fcfd022e3ff),
56
        (0xbc857822d7ffd282, 0x3fe6f8443546010a),
57
        (0x3c68269c66dfb28a, 0xbff80996754ceb79),
58
        (0x3c543dce8990a9f9, 0x3ffcf778d5ef0504),
59
        (0xbc72fc55f73765f6, 0xbff433be821423d0),
60
        (0xbc66d05fb37c8592, 0x3fdf15f19e9d8da4),
61
        (0x3c56dfb85e83a2c5, 0xbfb770b6827e0829),
62
        (0x3bff1472ecdfa403, 0x3f7a98a2980282bb),
63
        (0x3baffb33d69d6276, 0xbf142a246fd2c07c),
64
    ];
65
0
    let x2 = DoubleDouble::quick_mult(x, x);
66
0
    let vz = DoubleDouble::full_add_f64(x2, -0.5625);
67
68
0
    let vx2 = vz * vz;
69
0
    let vx4 = vx2 * vx2;
70
0
    let vx8 = vx4 * vx4;
71
72
0
    let p0 = DoubleDouble::mul_add(
73
0
        vz,
74
0
        DoubleDouble::from_bit_pair(P[1]),
75
0
        DoubleDouble::from_bit_pair(P[0]),
76
    );
77
0
    let p1 = DoubleDouble::mul_add(
78
0
        vz,
79
0
        DoubleDouble::from_bit_pair(P[3]),
80
0
        DoubleDouble::from_bit_pair(P[2]),
81
    );
82
0
    let p2 = DoubleDouble::mul_add(
83
0
        vz,
84
0
        DoubleDouble::from_bit_pair(P[5]),
85
0
        DoubleDouble::from_bit_pair(P[4]),
86
    );
87
0
    let p3 = DoubleDouble::mul_add(
88
0
        vz,
89
0
        DoubleDouble::from_bit_pair(P[7]),
90
0
        DoubleDouble::from_bit_pair(P[6]),
91
    );
92
0
    let p4 = DoubleDouble::mul_add(
93
0
        vz,
94
0
        DoubleDouble::from_bit_pair(P[9]),
95
0
        DoubleDouble::from_bit_pair(P[8]),
96
    );
97
98
0
    let q0 = DoubleDouble::mul_add(vx2, p1, p0);
99
0
    let q1 = DoubleDouble::mul_add(vx2, p3, p2);
100
101
0
    let r0 = DoubleDouble::mul_add(vx4, q1, q0);
102
0
    let num = DoubleDouble::mul_add(vx8, p4, r0);
103
    // Generated in Wolfram Mathematica:
104
    // <<FunctionApproximations`
105
    // ClearAll["Global`*"]
106
    // f[x_]:=InverseErf[x]/x
107
    // g[x_] =f[Sqrt[x]];
108
    // {err0,approx}=MiniMaxApproximation[g[z],{z,{0.06,0.75},9,9},WorkingPrecision->75, MaxIterations->100]
109
    // num=Numerator[approx][[1]];
110
    // den=Denominator[approx][[1]];
111
    // coeffs=CoefficientList[poly,z];
112
    // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
113
    // x0=SetPrecision[0.5625,75];
114
    // NumberForm[Series[den[x],{x,x0,50}], ExponentFunction->(Null&)]
115
    // coeffs=Table[SeriesCoefficient[den[x],{x,x0,k}],{k,0,9}];
116
    // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]];
117
    const Q: [(u64, u64); 10] = [
118
        (0xbc36337f24e57cb9, 0x3f92388d5d757e3a),
119
        (0xbc63dfae43d60e0b, 0xbfc6ca7da581358c),
120
        (0xbc77656389bd0e62, 0x3fe7c82ce417b4e0),
121
        (0xbc93679667bef2f0, 0xbffad58651fd1a51),
122
        (0x3ca2c6cb9eb17fb4, 0x4001bdb67e93a242),
123
        (0xbc9b58961ba253bc, 0xbffbdaeff6fbb81c),
124
        (0x3c7861f549c6aa61, 0x3fe91b12cf47da3a),
125
        (0xbc696dfd665b2f5e, 0xbfc7c5d0ffb7f1da),
126
        (0x3c1552b0ec0ba7b3, 0x3f939ada247f7609),
127
        (0xbbcaa226fb7b30a8, 0xbf41be65038ccfe6),
128
    ];
129
130
0
    let p0 = DoubleDouble::mul_add(
131
0
        vz,
132
0
        DoubleDouble::from_bit_pair(Q[1]),
133
0
        DoubleDouble::from_bit_pair(Q[0]),
134
    );
135
0
    let p1 = DoubleDouble::mul_add(
136
0
        vz,
137
0
        DoubleDouble::from_bit_pair(Q[3]),
138
0
        DoubleDouble::from_bit_pair(Q[2]),
139
    );
140
0
    let p2 = DoubleDouble::mul_add(
141
0
        vz,
142
0
        DoubleDouble::from_bit_pair(Q[5]),
143
0
        DoubleDouble::from_bit_pair(Q[4]),
144
    );
145
0
    let p3 = DoubleDouble::mul_add(
146
0
        vz,
147
0
        DoubleDouble::from_bit_pair(Q[7]),
148
0
        DoubleDouble::from_bit_pair(Q[6]),
149
    );
150
0
    let p4 = DoubleDouble::mul_add(
151
0
        vz,
152
0
        DoubleDouble::from_bit_pair(Q[9]),
153
0
        DoubleDouble::from_bit_pair(Q[8]),
154
    );
155
156
0
    let q0 = DoubleDouble::mul_add(vx2, p1, p0);
157
0
    let q1 = DoubleDouble::mul_add(vx2, p3, p2);
158
159
0
    let r0 = DoubleDouble::mul_add(vx4, q1, q0);
160
0
    let den = DoubleDouble::mul_add(vx8, p4, r0);
161
162
0
    let r = DoubleDouble::div(num, den);
163
0
    DoubleDouble::quick_mult(r, x)
164
0
}
165
166
#[inline]
167
0
fn inverf_asympt_small(z: DoubleDouble, zeta_sqrt: DoubleDouble) -> DoubleDouble {
168
    // Generated in Wolfram Mathematica:
169
    // <<FunctionApproximations`
170
    // ClearAll["Global`*"]
171
    // f[x_]:=InverseErf[Exp[-1/(x^2)]*(-1+Exp[1/(x^2)])]/(Sqrt[-Log[1-(Exp[-1/(x^2)]*(-1+Exp[1/(x^2)]))]] )
172
    // {err0, approx,err1}=MiniMaxApproximation[f[z],{z,{0.2,0.9999999},10,10},WorkingPrecision->90]
173
    // num=Numerator[approx];
174
    // den=Denominator[approx];
175
    // poly=num;
176
    // coeffs=CoefficientList[poly,z];
177
    // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
178
    const P: [(u64, u64); 11] = [
179
        (0x3c936555853a8b2c, 0x3ff0001df06a2515),
180
        (0x3cea488e802db3c3, 0x404406ba373221da),
181
        (0xbce27d42419754e3, 0x407b0442e38a9597),
182
        (0xbd224a407624cbdf, 0x409c9277e31ef446),
183
        (0x3d4f16ce65d6fea0, 0x40aec3ec005b1d8a),
184
        (0x3d105bc37bc61b58, 0x40b46be8f860f4d9),
185
        (0x3d5ca133dcdecaa0, 0x40b3826e6a32dad7),
186
        (0x3d1d52013ba8aa38, 0x40aae93a603cf3ea),
187
        (0xbd07a75306df0fc3, 0x4098ab8357dc2e51),
188
        (0x3d1bb6770bb7a27e, 0x407ebead00879010),
189
        (0xbbfcbff4a9737936, 0x3f8936117ccbff83),
190
    ];
191
192
0
    let z2 = DoubleDouble::quick_mult(z, z);
193
0
    let z4 = DoubleDouble::quick_mult(z2, z2);
194
0
    let z8 = DoubleDouble::quick_mult(z4, z4);
195
196
0
    let q0 = DoubleDouble::mul_add(
197
0
        DoubleDouble::from_bit_pair(P[1]),
198
0
        z,
199
0
        DoubleDouble::from_bit_pair(P[0]),
200
    );
201
0
    let q1 = DoubleDouble::mul_add(
202
0
        DoubleDouble::from_bit_pair(P[3]),
203
0
        z,
204
0
        DoubleDouble::from_bit_pair(P[2]),
205
    );
206
0
    let q2 = DoubleDouble::mul_add(
207
0
        DoubleDouble::from_bit_pair(P[5]),
208
0
        z,
209
0
        DoubleDouble::from_bit_pair(P[4]),
210
    );
211
0
    let q3 = DoubleDouble::mul_add(
212
0
        DoubleDouble::from_bit_pair(P[7]),
213
0
        z,
214
0
        DoubleDouble::from_bit_pair(P[6]),
215
    );
216
0
    let q4 = DoubleDouble::mul_add(
217
0
        DoubleDouble::from_bit_pair(P[9]),
218
0
        z,
219
0
        DoubleDouble::from_bit_pair(P[8]),
220
    );
221
222
0
    let r0 = DoubleDouble::mul_add(z2, q1, q0);
223
0
    let r1 = DoubleDouble::mul_add(z2, q3, q2);
224
225
0
    let s0 = DoubleDouble::mul_add(z4, r1, r0);
226
0
    let s1 = DoubleDouble::mul_add(z2, DoubleDouble::from_bit_pair(P[10]), q4);
227
0
    let num = DoubleDouble::mul_add(z8, s1, s0);
228
229
    // See numerator generation above:
230
    // poly=den;
231
    // coeffs=CoefficientList[poly,z];
232
    // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
233
    const Q: [(u64, u64); 11] = [
234
        (0x0000000000000000, 0x3ff0000000000000),
235
        (0xbc75b1109d4a3262, 0x40440782efaab17f),
236
        (0x3d1f7775b207d84f, 0x407b2da74b0d39f2),
237
        (0xbd3291fdbab49501, 0x409dac8d9e7c90b2),
238
        (0xbd58d8fdd27707a9, 0x40b178dfeffa3192),
239
        (0xbd57fc74ad705ce0, 0x40bad19b686f219f),
240
        (0x3d4075510031f2cd, 0x40be70a598208cea),
241
        (0xbd5442e109152efb, 0x40b9683ef36ae330),
242
        (0x3d5398192933962e, 0x40b04b7c4c3ca8ee),
243
        (0x3d2d04d03598e303, 0x409bd0080799fbf1),
244
        (0x3d2a988eb552ef44, 0x40815a46f12bafe3),
245
    ];
246
247
0
    let q0 = DoubleDouble::mul_add_f64(
248
0
        DoubleDouble::from_bit_pair(Q[1]),
249
0
        z,
250
0
        f64::from_bits(0x3ff0000000000000),
251
    );
252
0
    let q1 = DoubleDouble::mul_add(
253
0
        DoubleDouble::from_bit_pair(Q[3]),
254
0
        z,
255
0
        DoubleDouble::from_bit_pair(Q[2]),
256
    );
257
0
    let q2 = DoubleDouble::mul_add(
258
0
        DoubleDouble::from_bit_pair(Q[5]),
259
0
        z,
260
0
        DoubleDouble::from_bit_pair(Q[4]),
261
    );
262
0
    let q3 = DoubleDouble::mul_add(
263
0
        DoubleDouble::from_bit_pair(Q[7]),
264
0
        z,
265
0
        DoubleDouble::from_bit_pair(Q[6]),
266
    );
267
0
    let q4 = DoubleDouble::mul_add(
268
0
        DoubleDouble::from_bit_pair(Q[9]),
269
0
        z,
270
0
        DoubleDouble::from_bit_pair(Q[8]),
271
    );
272
273
0
    let r0 = DoubleDouble::mul_add(z2, q1, q0);
274
0
    let r1 = DoubleDouble::mul_add(z2, q3, q2);
275
276
0
    let s0 = DoubleDouble::mul_add(z4, r1, r0);
277
0
    let s1 = DoubleDouble::mul_add(z2, DoubleDouble::from_bit_pair(Q[10]), q4);
278
0
    let den = DoubleDouble::mul_add(z8, s1, s0);
279
0
    let r = DoubleDouble::div(num, den);
280
0
    DoubleDouble::quick_mult(r, zeta_sqrt)
281
0
}
282
283
// branch for |x| > 0.9999 for extreme tail
284
#[cold]
285
0
fn inverf_asympt_long(z: DoubleDouble, zeta_sqrt: DoubleDouble) -> DoubleDouble {
286
    // First step rational approximant is generated, but it's ill-conditioned, thus
287
    // we're using taylor expansion to create Newton form at the point.
288
    // Generated in Wolfram Mathematica:
289
    // <<FunctionApproximations`
290
    // ClearAll["Global`*"]
291
    // f[x_]:=InverseErf[Exp[-1/(x^2)]*(-1+Exp[1/(x^2)])]/(Sqrt[-Log[1-(Exp[-1/(x^2)]*(-1+Exp[1/(x^2)]))]] )
292
    // {err0, approx}=MiniMaxApproximation[f[z],{z,{0.2,0.9999999},13,13},WorkingPrecision->90]
293
    // num=Numerator[approx][[1]];
294
    // den=Denominator[approx][[1]];
295
    // poly=num;
296
    // coeffs=CoefficientList[poly,z];
297
    // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
298
    const P: [(u64, u64); 14] = [
299
        (0x3c97612f9b24a614, 0x3ff0000ba84cc7a5),
300
        (0xbcee8fe2da463412, 0x40515246546f5d88),
301
        (0x3d2fa4a2b891b526, 0x40956b6837159b11),
302
        (0x3d5d673ffad4f817, 0x40c5a1aa3be58652),
303
        (0x3d8867a1e5506f88, 0x40e65ebb1e1e7c75),
304
        (0xbd9bbc0764ed8f5b, 0x40fd2064a652e5c2),
305
        (0xbda78e569c0d237f, 0x410a385c627c461c),
306
        (0xbdab3123ebc465d7, 0x4110f05ca2b65fe5),
307
        (0x3d960def35955192, 0x4110bb079af2fe08),
308
        (0xbd97904816054836, 0x410911c24610c11c),
309
        (0xbd937745e9192593, 0x40fc603244adca35),
310
        (0xbd65fbc476d63050, 0x40e6399103188c21),
311
        (0xbd61016ef381cce6, 0x40c6482b44995b89),
312
        (0x3c326105c49e5a1a, 0xbfab44bd8b4e3138),
313
    ];
314
315
0
    let z2 = z * z;
316
0
    let z4 = z2 * z2;
317
0
    let z8 = z4 * z4;
318
319
0
    let g0 = DoubleDouble::mul_add(
320
0
        z,
321
0
        DoubleDouble::from_bit_pair(P[1]),
322
0
        DoubleDouble::from_bit_pair(P[0]),
323
    );
324
0
    let g1 = DoubleDouble::mul_add(
325
0
        z,
326
0
        DoubleDouble::from_bit_pair(P[3]),
327
0
        DoubleDouble::from_bit_pair(P[2]),
328
    );
329
0
    let g2 = DoubleDouble::mul_add(
330
0
        z,
331
0
        DoubleDouble::from_bit_pair(P[5]),
332
0
        DoubleDouble::from_bit_pair(P[4]),
333
    );
334
0
    let g3 = DoubleDouble::mul_add(
335
0
        z,
336
0
        DoubleDouble::from_bit_pair(P[7]),
337
0
        DoubleDouble::from_bit_pair(P[6]),
338
    );
339
0
    let g4 = DoubleDouble::mul_add(
340
0
        z,
341
0
        DoubleDouble::from_bit_pair(P[9]),
342
0
        DoubleDouble::from_bit_pair(P[8]),
343
    );
344
0
    let g5 = DoubleDouble::mul_add(
345
0
        z,
346
0
        DoubleDouble::from_bit_pair(P[11]),
347
0
        DoubleDouble::from_bit_pair(P[10]),
348
    );
349
0
    let g6 = DoubleDouble::mul_add(
350
0
        z,
351
0
        DoubleDouble::from_bit_pair(P[13]),
352
0
        DoubleDouble::from_bit_pair(P[12]),
353
    );
354
355
0
    let h0 = DoubleDouble::mul_add(z2, g1, g0);
356
0
    let h1 = DoubleDouble::mul_add(z2, g3, g2);
357
0
    let h2 = DoubleDouble::mul_add(z2, g5, g4);
358
359
0
    let q0 = DoubleDouble::mul_add(z4, h1, h0);
360
0
    let q1 = DoubleDouble::mul_add(z4, g6, h2);
361
362
0
    let num = DoubleDouble::mul_add(z8, q1, q0);
363
364
    // See numerator generation above:
365
    // poly=den;
366
    // coeffs=CoefficientList[poly,z];
367
    // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
368
    const Q: [(u64, u64); 14] = [
369
        (0x0000000000000000, 0x3ff0000000000000),
370
        (0xbcfc7b886ee61417, 0x405152838f711f3c),
371
        (0xbd33f933c14e831a, 0x409576cb78cab36e),
372
        (0x3d33fb09e2c4898a, 0x40c5e8a2c7602ced),
373
        (0x3d7be430c664bf7e, 0x40e766fdc8c7638c),
374
        (0x3dac662e74cdfc0e, 0x4100276b5f47b5f1),
375
        (0x3da67d06e82a8495, 0x410f843887f8a24a),
376
        (0x3dbbf2e22fc2550a, 0x4116d04271703e08),
377
        (0xbdb2fb3aed100853, 0x4119aff4ed32b74b),
378
        (0x3dba75e7b7171c3c, 0x4116b5eb8bf386bd),
379
        (0x3dab2d8b8c1937eb, 0x410f71c38e84cb34),
380
        (0xbda4e2e8a50b7370, 0x4100ca04b0f36b94),
381
        (0xbd86ed6df34fdaf9, 0x40e9151ded4cf4b7),
382
        (0x3d6938ea702c0328, 0x40c923ee1ab270c4),
383
    ];
384
385
0
    let g0 = DoubleDouble::mul_add(
386
0
        z,
387
0
        DoubleDouble::from_bit_pair(Q[1]),
388
0
        DoubleDouble::from_bit_pair(Q[0]),
389
    );
390
0
    let g1 = DoubleDouble::mul_add(
391
0
        z,
392
0
        DoubleDouble::from_bit_pair(Q[3]),
393
0
        DoubleDouble::from_bit_pair(Q[2]),
394
    );
395
0
    let g2 = DoubleDouble::mul_add(
396
0
        z,
397
0
        DoubleDouble::from_bit_pair(Q[5]),
398
0
        DoubleDouble::from_bit_pair(Q[4]),
399
    );
400
0
    let g3 = DoubleDouble::mul_add(
401
0
        z,
402
0
        DoubleDouble::from_bit_pair(Q[7]),
403
0
        DoubleDouble::from_bit_pair(Q[6]),
404
    );
405
0
    let g4 = DoubleDouble::mul_add(
406
0
        z,
407
0
        DoubleDouble::from_bit_pair(Q[9]),
408
0
        DoubleDouble::from_bit_pair(Q[8]),
409
    );
410
0
    let g5 = DoubleDouble::mul_add(
411
0
        z,
412
0
        DoubleDouble::from_bit_pair(Q[11]),
413
0
        DoubleDouble::from_bit_pair(Q[10]),
414
    );
415
0
    let g6 = DoubleDouble::mul_add(
416
0
        z,
417
0
        DoubleDouble::from_bit_pair(Q[13]),
418
0
        DoubleDouble::from_bit_pair(Q[12]),
419
    );
420
421
0
    let h0 = DoubleDouble::mul_add(z2, g1, g0);
422
0
    let h1 = DoubleDouble::mul_add(z2, g3, g2);
423
0
    let h2 = DoubleDouble::mul_add(z2, g5, g4);
424
425
0
    let q0 = DoubleDouble::mul_add(z4, h1, h0);
426
0
    let q1 = DoubleDouble::mul_add(z4, g6, h2);
427
428
0
    let den = DoubleDouble::mul_add(z8, q1, q0);
429
0
    let r = DoubleDouble::div(num, den);
430
431
0
    DoubleDouble::quick_mult(r, zeta_sqrt)
432
0
}
433
434
#[inline]
435
0
fn erf_core(x: DoubleDouble) -> DoubleDouble {
436
    // x is always positive, here, should be filtered out before the call
437
438
0
    if x.hi <= 0.0095 {
439
        // 0.0095
440
        // for small |x| using taylor series first 3 terms
441
        // Generated by SageMath:
442
        // from mpmath import mp, erf
443
        //
444
        // mp.prec = 100
445
        //
446
        // def inverf_series(n_terms):
447
        //     from mpmath import taylor
448
        //     series_erf = taylor(mp.erfinv, 0, n_terms)
449
        //     return series_erf
450
        //
451
        // ser = inverf_series(10)
452
        // for i in range(1, len(ser), 2):
453
        //     k = ser[i]
454
        //     print("f64::from_bits(" + double_to_hex(RealField(100)(k)) + "),")
455
0
        let z2 = DoubleDouble::quick_mult(x, x);
456
0
        let p = f_fmla(
457
0
            z2.hi,
458
0
            f64::from_bits(0x3fb62847c47dda48),
459
0
            f64::from_bits(0x3fc053c2c0ab91c5),
460
        );
461
0
        let mut r = DoubleDouble::mul_f64_add(
462
0
            z2,
463
0
            p,
464
0
            DoubleDouble::from_bit_pair((0xbc33ea2ef8dde075, 0x3fcdb29fb2fee5e4)),
465
        );
466
0
        r = DoubleDouble::mul_add(
467
0
            z2,
468
0
            r,
469
0
            DoubleDouble::from_bit_pair((0xbc8618f13eb7ca89, 0x3fec5bf891b4ef6b)),
470
0
        );
471
        // (rh + rl) * z = rh * z + rl*z
472
0
        let v = DoubleDouble::quick_mult(r, x);
473
0
        return v;
474
0
    } else if x.hi <= 0.06 {
475
        // 0.06
476
        // for |x| < 0.06 using taylor series first 5 terms
477
        // Generated by SageMath:
478
        // from mpmath import mp, erf
479
        //
480
        // mp.prec = 100
481
        //
482
        // def inverf_series(n_terms):
483
        //     from mpmath import taylor
484
        //     series_erf = taylor(mp.erfinv, 0, n_terms)
485
        //     return series_erf
486
        //
487
        // ser = inverf_series(10)
488
        // for i in range(1, len(ser), 2):
489
        //     k = ser[i]
490
        //     print("f64::from_bits(" + double_to_hex(RealField(100)(k)) + "),")
491
0
        let z2 = DoubleDouble::quick_mult(x, x);
492
0
        let p = f_polyeval4(
493
0
            z2.hi,
494
0
            f64::from_bits(0x3fb62847c47dda48),
495
0
            f64::from_bits(0x3fb0a13189c6ef7a),
496
0
            f64::from_bits(0x3faa7c85c89bb08b),
497
0
            f64::from_bits(0x3fa5eeb1d488e312),
498
        );
499
0
        let mut r = DoubleDouble::mul_f64_add(
500
0
            z2,
501
0
            p,
502
0
            DoubleDouble::from_bit_pair((0x3c2cec68daff0d80, 0x3fc053c2c0ab91c5)),
503
        );
504
0
        r = DoubleDouble::mul_add(
505
0
            z2,
506
0
            r,
507
0
            DoubleDouble::from_bit_pair((0xbc33ea2ef8dde075, 0x3fcdb29fb2fee5e4)),
508
0
        );
509
0
        r = DoubleDouble::mul_add(
510
0
            z2,
511
0
            r,
512
0
            DoubleDouble::from_bit_pair((0xbc8618f13eb7ca89, 0x3fec5bf891b4ef6b)),
513
0
        );
514
        // (rh + rl) * z = rh * z + rl*z
515
0
        let v = DoubleDouble::quick_mult(r, x);
516
0
        return v;
517
0
    }
518
519
0
    if x.hi <= 0.75 {
520
        // |x| < 0.75
521
522
        // First step rational approximant is generated, but it's ill-conditioned, thus
523
        // we're using taylor expansion to create Newton form at the point.
524
        // Generated in Wolfram Mathematica:
525
        // <<FunctionApproximations`
526
        // ClearAll["Global`*"]
527
        // f[x_]:=InverseErf[x]/x
528
        // g[x_] =f[Sqrt[x]];
529
        // {err0,approx}=MiniMaxApproximation[g[z],{z,{0.06,0.75},9,9},WorkingPrecision->75, MaxIterations->100]
530
        // num=Numerator[approx][[1]];
531
        // den=Denominator[approx][[1]];
532
        // poly=den;
533
        // coeffs=CoefficientList[poly,z];
534
        // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
535
        // x0=SetPrecision[0.5625,75];
536
        // NumberForm[Series[num[x],{x,x0,50}], ExponentFunction->(Null&)]
537
        // coeffs=Table[SeriesCoefficient[num[x],{x,x0,k}],{k,0,9}];
538
        // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]];
539
        const P: [(u64, u64); 5] = [
540
            (0xbc3e06eda42202a0, 0x3f93c2fc5d00e0c8),
541
            (0xbc6eb374406b33b4, 0xbfc76fcfd022e3ff),
542
            (0xbc857822d7ffd282, 0x3fe6f8443546010a),
543
            (0x3c68269c66dfb28a, 0xbff80996754ceb79),
544
            (0x3c543dce8990a9f9, 0x3ffcf778d5ef0504),
545
        ];
546
0
        let x2 = DoubleDouble::quick_mult(x, x);
547
0
        let vz = DoubleDouble::full_add_f64(x2, -0.5625);
548
0
        let ps_num = f_polyeval5(
549
0
            vz.hi,
550
0
            f64::from_bits(0xbff433be821423d0),
551
0
            f64::from_bits(0x3fdf15f19e9d8da4),
552
0
            f64::from_bits(0xbfb770b6827e0829),
553
0
            f64::from_bits(0x3f7a98a2980282bb),
554
0
            f64::from_bits(0xbf142a246fd2c07c),
555
        );
556
0
        let mut num = DoubleDouble::mul_f64_add(vz, ps_num, DoubleDouble::from_bit_pair(P[4]));
557
0
        num = DoubleDouble::mul_add(vz, num, DoubleDouble::from_bit_pair(P[3]));
558
0
        num = DoubleDouble::mul_add(vz, num, DoubleDouble::from_bit_pair(P[2]));
559
0
        num = DoubleDouble::mul_add(vz, num, DoubleDouble::from_bit_pair(P[1]));
560
0
        num = DoubleDouble::mul_add(vz, num, DoubleDouble::from_bit_pair(P[0]));
561
562
        // Generated in Wolfram Mathematica:
563
        // <<FunctionApproximations`
564
        // ClearAll["Global`*"]
565
        // f[x_]:=InverseErf[x]/x
566
        // g[x_] =f[Sqrt[x]];
567
        // {err0,approx}=MiniMaxApproximation[g[z],{z,{0.06,0.75},9,9},WorkingPrecision->75, MaxIterations->100]
568
        // num=Numerator[approx][[1]];
569
        // den=Denominator[approx][[1]];
570
        // coeffs=CoefficientList[poly,z];
571
        // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
572
        // x0=SetPrecision[0.5625,75];
573
        // NumberForm[Series[den[x],{x,x0,50}], ExponentFunction->(Null&)]
574
        // coeffs=Table[SeriesCoefficient[den[x],{x,x0,k}],{k,0,9}];
575
        // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]];
576
        const Q: [(u64, u64); 5] = [
577
            (0xbc36337f24e57cb9, 0x3f92388d5d757e3a),
578
            (0xbc63dfae43d60e0b, 0xbfc6ca7da581358c),
579
            (0xbc77656389bd0e62, 0x3fe7c82ce417b4e0),
580
            (0xbc93679667bef2f0, 0xbffad58651fd1a51),
581
            (0x3ca2c6cb9eb17fb4, 0x4001bdb67e93a242),
582
        ];
583
584
0
        let ps_den = f_polyeval5(
585
0
            vz.hi,
586
0
            f64::from_bits(0xbffbdaeff6fbb81c),
587
0
            f64::from_bits(0x3fe91b12cf47da3a),
588
0
            f64::from_bits(0xbfc7c5d0ffb7f1da),
589
0
            f64::from_bits(0x3f939ada247f7609),
590
0
            f64::from_bits(0xbf41be65038ccfe6),
591
        );
592
593
0
        let mut den = DoubleDouble::mul_f64_add(vz, ps_den, DoubleDouble::from_bit_pair(Q[4]));
594
0
        den = DoubleDouble::mul_add(vz, den, DoubleDouble::from_bit_pair(Q[3]));
595
0
        den = DoubleDouble::mul_add(vz, den, DoubleDouble::from_bit_pair(Q[2]));
596
0
        den = DoubleDouble::mul_add(vz, den, DoubleDouble::from_bit_pair(Q[1]));
597
0
        den = DoubleDouble::mul_add(vz, den, DoubleDouble::from_bit_pair(Q[0]));
598
0
        let r = DoubleDouble::div(num, den);
599
0
        let k = DoubleDouble::quick_mult(r, x);
600
0
        let err = f_fmla(
601
0
            k.hi,
602
0
            f64::from_bits(0x3c70000000000000), // 2^-56
603
0
            f64::from_bits(0x3c40000000000000), // 2^-59
604
        );
605
0
        let ub = k.hi + (k.lo + err);
606
0
        let lb = k.hi + (k.lo - err);
607
0
        if ub == lb {
608
0
            return k;
609
0
        }
610
0
        return inverf_0p06_to_0p75(x);
611
0
    }
612
613
0
    let q = DoubleDouble::full_add_f64(-x, 1.0);
614
615
0
    let mut zeta = fast_log_dd(q);
616
0
    zeta = DoubleDouble::from_exact_add(zeta.hi, zeta.lo);
617
0
    zeta = -zeta;
618
0
    let zeta_sqrt = zeta.fast_sqrt();
619
0
    let rz = zeta_sqrt.recip();
620
621
0
    if x.hi < 0.9999 {
622
0
        inverf_asympt_small(rz, zeta_sqrt)
623
    } else {
624
0
        inverf_asympt_long(rz, zeta_sqrt)
625
    }
626
0
}
627
628
#[cold]
629
0
fn inverfc_extra_small(x: f64) -> DoubleDouble {
630
    // Reversed order for erfinv with direct identity without subtraction.
631
0
    let q = x;
632
633
0
    let mut zeta = fast_log_d_to_dd(q);
634
0
    zeta = DoubleDouble::from_exact_add(zeta.hi, zeta.lo);
635
0
    zeta = -zeta;
636
0
    let zeta_sqrt = zeta.fast_sqrt();
637
0
    let rz = zeta_sqrt.recip();
638
0
    if x >= 0.0001 {
639
0
        inverf_asympt_small(rz, zeta_sqrt)
640
    } else {
641
0
        inverf_asympt_long(rz, zeta_sqrt)
642
    }
643
0
}
644
645
/// Complementary inverse error function
646
0
pub fn f_erfcinv(x: f64) -> f64 {
647
0
    let ix = x.to_bits();
648
649
0
    if ix >= 0x4000000000000000u64 || ix == 0 {
650
        // |x| == NaN, x == inf, |x| == 0, x < 0
651
0
        if ix.wrapping_shl(1) == 0 {
652
0
            return f64::INFINITY;
653
0
        }
654
0
        if ix == 0x4000000000000000u64 {
655
0
            return f64::NEG_INFINITY;
656
0
        }
657
0
        return f64::NAN; // x == NaN, x == Inf, x > 2
658
0
    }
659
660
0
    if x == 1. {
661
0
        return 0.;
662
0
    }
663
664
    // we compute erfcinv through identity
665
    // erfcinv(x) = -erfinv(1-x)
666
667
    static SIGN: [f64; 2] = [1.0, -1.0];
668
669
0
    if x < 0.1 {
670
0
        return inverfc_extra_small(x).to_f64();
671
0
    }
672
673
0
    let dx = if x > 1. {
674
0
        DoubleDouble::from_full_exact_sub(2., x)
675
    } else {
676
0
        DoubleDouble::new(0., x)
677
    };
678
0
    let sign = SIGN[(x > 1.) as usize];
679
680
0
    let mut dx = DoubleDouble::full_add_f64(-dx, 1.);
681
0
    dx = DoubleDouble::from_exact_add(dx.hi, dx.lo);
682
0
    erf_core(dx).to_f64() * sign
683
0
}
684
685
#[cfg(test)]
686
mod tests {
687
    use super::*;
688
689
    #[test]
690
    fn test_inverfc() {
691
        assert_eq!(f_erfcinv(0.12), 1.0993909519492193);
692
        assert_eq!(f_erfcinv(1.0000000000027623e-13), 5.261512368864527);
693
        assert_eq!(f_erfcinv(1.0001200000182189), -0.00010634724760131264);
694
        assert_eq!(f_erfcinv(0.7001200000182189), 0.2723481758403576);
695
        assert_eq!(f_erfcinv(1.5231200000182189), -0.502985998867995);
696
        assert_eq!(f_erfcinv(1.99545434324323243), -2.0064739778442213);
697
        assert_eq!(f_erfcinv(1.), 0.);
698
        assert!(f_erfcinv(2.05).is_nan());
699
        assert!(f_erfcinv(-0.01).is_nan());
700
        assert!(f_erfcinv(f64::NAN).is_nan());
701
        assert!(f_erfcinv(f64::NEG_INFINITY).is_nan());
702
        assert!(f_erfcinv(f64::INFINITY).is_nan());
703
    }
704
}