mathpf 0.7.2__tar.gz → 0.7.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. {mathpf-0.7.2/src/mathpf.egg-info → mathpf-0.7.3}/PKG-INFO +1 -1
  2. {mathpf-0.7.2 → mathpf-0.7.3}/src/mathpf/_kernels/mills.cpp +41 -23
  3. {mathpf-0.7.2 → mathpf-0.7.3}/src/mathpf/_kernels/mills_dd.cpp +5 -5
  4. {mathpf-0.7.2 → mathpf-0.7.3}/src/mathpf/_mills_coef.h +44 -5
  5. {mathpf-0.7.2 → mathpf-0.7.3}/src/mathpf/_pyref/mills_cheby.py +79 -32
  6. {mathpf-0.7.2 → mathpf-0.7.3}/src/mathpf/_pyref/mills_dd.py +5 -5
  7. {mathpf-0.7.2 → mathpf-0.7.3}/src/mathpf/avg_funcs.c +152 -152
  8. {mathpf-0.7.2 → mathpf-0.7.3}/src/mathpf/mills.cpp +152 -152
  9. {mathpf-0.7.2 → mathpf-0.7.3}/src/mathpf/mills_dd.cpp +152 -152
  10. {mathpf-0.7.2 → mathpf-0.7.3/src/mathpf.egg-info}/PKG-INFO +1 -1
  11. {mathpf-0.7.2 → mathpf-0.7.3}/src/mathpf.egg-info/SOURCES.txt +7 -1
  12. mathpf-0.7.3/tests/_ref_table.py +276 -0
  13. {mathpf-0.7.2 → mathpf-0.7.3}/tests/test_mills.py +7 -45
  14. mathpf-0.7.3/tests/test_mills_dd_high_prec.py +139 -0
  15. mathpf-0.7.3/tests/test_mills_high_prec.py +85 -0
  16. mathpf-0.7.3/tools/_mrdd_cf_probe.py +52 -0
  17. mathpf-0.7.3/tools/_rrel_seg_explore.py +98 -0
  18. mathpf-0.7.3/tools/gen_mills_ref.py +212 -0
  19. {mathpf-0.7.2 → mathpf-0.7.3}/.github/workflows/build_wheels.yml +0 -0
  20. {mathpf-0.7.2 → mathpf-0.7.3}/.gitignore +0 -0
  21. {mathpf-0.7.2 → mathpf-0.7.3}/MANIFEST.in +0 -0
  22. {mathpf-0.7.2 → mathpf-0.7.3}/pyproject.toml +0 -0
  23. {mathpf-0.7.2 → mathpf-0.7.3}/setup.cfg +0 -0
  24. {mathpf-0.7.2 → mathpf-0.7.3}/setup.py +0 -0
  25. {mathpf-0.7.2 → mathpf-0.7.3}/src/mathpf/__init__.py +0 -0
  26. {mathpf-0.7.2 → mathpf-0.7.3}/src/mathpf/_kernels/CommonMacro.h +0 -0
  27. {mathpf-0.7.2 → mathpf-0.7.3}/src/mathpf/_kernels/mills.h +0 -0
  28. {mathpf-0.7.2 → mathpf-0.7.3}/src/mathpf/_kernels/mills_dd.h +0 -0
  29. {mathpf-0.7.2 → mathpf-0.7.3}/src/mathpf/_pyref/__init__.py +0 -0
  30. {mathpf-0.7.2 → mathpf-0.7.3}/src/mathpf/avg_funcs.pxd +0 -0
  31. {mathpf-0.7.2 → mathpf-0.7.3}/src/mathpf/avg_funcs.pyx +0 -0
  32. {mathpf-0.7.2 → mathpf-0.7.3}/src/mathpf/mills.pxd +0 -0
  33. {mathpf-0.7.2 → mathpf-0.7.3}/src/mathpf/mills.pyx +0 -0
  34. {mathpf-0.7.2 → mathpf-0.7.3}/src/mathpf/mills_dd.pxd +0 -0
  35. {mathpf-0.7.2 → mathpf-0.7.3}/src/mathpf/mills_dd.pyx +0 -0
  36. {mathpf-0.7.2 → mathpf-0.7.3}/src/mathpf.egg-info/dependency_links.txt +0 -0
  37. {mathpf-0.7.2 → mathpf-0.7.3}/src/mathpf.egg-info/requires.txt +0 -0
  38. {mathpf-0.7.2 → mathpf-0.7.3}/src/mathpf.egg-info/top_level.txt +0 -0
  39. {mathpf-0.7.2 → mathpf-0.7.3}/tests/test_mills_dd.py +0 -0
  40. {mathpf-0.7.2 → mathpf-0.7.3}/tests/test_pyref_consistency.py +0 -0
  41. {mathpf-0.7.2 → mathpf-0.7.3}/tools/README.md +0 -0
  42. {mathpf-0.7.2 → mathpf-0.7.3}/tools/_cancel.py +0 -0
  43. {mathpf-0.7.2 → mathpf-0.7.3}/tools/_oddcf.py +0 -0
  44. {mathpf-0.7.2 → mathpf-0.7.3}/tools/_tiers.py +0 -0
  45. {mathpf-0.7.2 → mathpf-0.7.3}/tools/_wlin.py +0 -0
  46. {mathpf-0.7.2 → mathpf-0.7.3}/tools/cheby_fit.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mathpf
3
- Version: 0.7.2
3
+ Version: 0.7.3
4
4
  Summary: Numerically stable special functions and primitives (Mills ratio, normalised moment averages, etc.)
5
5
  Project-URL: Homepage, https://github.com/quants-net/MathPF
6
6
  Requires-Python: >=3.10
@@ -20,14 +20,22 @@ QNSPACE
20
20
  using std::exp;
21
21
 
22
22
  /* ----------------------------------------------------------------------
23
- * MillsRatioRel_below1(x) = (sqrt(pi/2) - R(x))/x on [0, 1]. Degree-14
24
- * Horner in C_Rrel; R = M_SQRT2PI_2 - x * Rrel_below1.
23
+ * MillsRatioRel_below1(x) = (sqrt(pi/2) - R(x))/x on [0, 1]. 12 uniform
24
+ * segments of degree 7 in C_Rrel; same per-call cost as MillsRatioDeriv1.
25
+ * The two other [0, 1] consumers (MillsRatio, MillsRatioDeriv1) inline the
26
+ * same lookup+Horner pattern, then apply their respective identities:
27
+ * R = sqrt(pi/2) - x * Rrel
28
+ * R1 = 1 - x * R = 1 - x*(sqrt(pi/2) - x*Rrel)
25
29
  * ---------------------------------------------------------------------- */
26
30
  template<typename T>
27
31
  T MillsRatioRel_below1(T x)
28
32
  {
33
+ int i = static_cast<int>(T(NSEG_RREL) * x);
34
+ if (i >= NSEG_RREL) i = NSEG_RREL - 1;
35
+ const T s = T(NSEG_RREL) * x - T(i);
36
+ const int o = i * 8;
29
37
  const double* c = C_Rrel;
30
- return ((((((((((((((T(c[14]))*x + T(c[13]))*x + T(c[12]))*x + T(c[11]))*x + T(c[10]))*x + T(c[9]))*x + T(c[8]))*x + T(c[7]))*x + T(c[6]))*x + T(c[5]))*x + T(c[4]))*x + T(c[3]))*x + T(c[2]))*x + T(c[1]))*x + T(c[0]);
38
+ return (((((((T(c[o+7]))*s + T(c[o+6]))*s + T(c[o+5]))*s + T(c[o+4]))*s + T(c[o+3]))*s + T(c[o+2]))*s + T(c[o+1]))*s + T(c[o]);
31
39
  }
32
40
 
33
41
  /* ----------------------------------------------------------------------
@@ -94,17 +102,22 @@ QNSPACE
94
102
  return T(M_SQRT2PI) * exp(T(0.5) * x * x) - MillsRatio(-x);
95
103
  }
96
104
  if (x <= T(1.0)) {
105
+ i = static_cast<int>(T(NSEG_RREL) * x);
106
+ if (i >= NSEG_RREL) i = NSEG_RREL - 1;
107
+ s = T(NSEG_RREL) * x - T(i);
108
+ o = i * 8;
97
109
  c = C_Rrel;
98
- return T(M_SQRT2PI_2) - x * (((((((((((((((T(c[14]))*x + T(c[13]))*x + T(c[12]))*x + T(c[11]))*x + T(c[10]))*x + T(c[9]))*x + T(c[8]))*x + T(c[7]))*x + T(c[6]))*x + T(c[5]))*x + T(c[4]))*x + T(c[3]))*x + T(c[2]))*x + T(c[1]))*x + T(c[0]));
110
+ const T rrel = (((((((T(c[o+7]))*s + T(c[o+6]))*s + T(c[o+5]))*s + T(c[o+4]))*s + T(c[o+3]))*s + T(c[o+2]))*s + T(c[o+1]))*s + T(c[o]);
111
+ return T(M_SQRT2PI_2) - x * rrel;
99
112
  }
100
113
  if (x >= T(XCF_R[0])) { /* tiered CF via shared MillsRatio_CF */
101
- if (x >= T(XCF_R[6])) return T(1.0) / x; /* n=0 */
102
- if (x >= T(XCF_R[5])) return MillsRatio_CF(x, 2, 0);
103
- if (x >= T(XCF_R[4])) return MillsRatio_CF(x, 4, 0);
104
- if (x >= T(XCF_R[3])) return MillsRatio_CF(x, 6, 0);
105
- if (x >= T(XCF_R[2])) return MillsRatio_CF(x, 8, 0);
106
- if (x >= T(XCF_R[1])) return MillsRatio_CF(x, 10, 0);
107
- return MillsRatio_CF(x, 12, 0); /* bridge */
114
+ if (x >= T(XCF_R[6])) return T(1.0) / x; /* x >= 67000000: n=0 degenerate */
115
+ if (x >= T(XCF_R[5])) return MillsRatio_CF(x, NCF_R[5], 0); /* x in [548, 67e6): CF n=2 */
116
+ if (x >= T(XCF_R[4])) return MillsRatio_CF(x, NCF_R[4], 0); /* x in [59.3, 548): CF n=4 */
117
+ if (x >= T(XCF_R[3])) return MillsRatio_CF(x, NCF_R[3], 0); /* x in [24.1, 59.3): CF n=6 */
118
+ if (x >= T(XCF_R[2])) return MillsRatio_CF(x, NCF_R[2], 0); /* x in [15.1, 24.1): CF n=8 */
119
+ if (x >= T(XCF_R[1])) return MillsRatio_CF(x, NCF_R[1], 0); /* x in [11.4, 15.1): CF n=10 */
120
+ return MillsRatio_CF(x, NCF_R[0], 0); /* x in [9.5, 11.4): CF n=12 bridge */
108
121
  }
109
122
  d = T(N_FRAC_R1) + x;
110
123
  i = static_cast<int>(T(NSEG_R1) * (x - T(1.0)) / d);
@@ -130,18 +143,23 @@ QNSPACE
130
143
  return T(M_SQRT2PI) * (-x) * exp(T(0.5) * x * x) + MillsRatioDeriv1(-x);
131
144
  }
132
145
  if (x <= T(1.0)) {
146
+ i = static_cast<int>(T(NSEG_RREL) * x);
147
+ if (i >= NSEG_RREL) i = NSEG_RREL - 1;
148
+ s = T(NSEG_RREL) * x - T(i);
149
+ o = i * 8;
133
150
  c = C_Rrel;
134
- return T(1.0) - x * (T(M_SQRT2PI_2) - x * (((((((((((((((T(c[14]))*x + T(c[13]))*x + T(c[12]))*x + T(c[11]))*x + T(c[10]))*x + T(c[9]))*x + T(c[8]))*x + T(c[7]))*x + T(c[6]))*x + T(c[5]))*x + T(c[4]))*x + T(c[3]))*x + T(c[2]))*x + T(c[1]))*x + T(c[0])));
151
+ const T rrel = (((((((T(c[o+7]))*s + T(c[o+6]))*s + T(c[o+5]))*s + T(c[o+4]))*s + T(c[o+3]))*s + T(c[o+2]))*s + T(c[o+1]))*s + T(c[o]);
152
+ return T(1.0) - x * (T(M_SQRT2PI_2) - x * rrel);
135
153
  }
136
154
  if (x >= T(XCF_R1[0])) {
137
155
  u = x * x + T(3.0); /* shared with U_MAX guard and MillsRatio_CF */
138
156
  if (u > T(U_MAX)) return T(0.0); /* +3 shift invisible at the saturation threshold */
139
- if (x >= T(XCF_R1[5])) return MillsRatio_CF(u, 2, 1);
140
- if (x >= T(XCF_R1[4])) return MillsRatio_CF(u, 4, 1);
141
- if (x >= T(XCF_R1[3])) return MillsRatio_CF(u, 6, 1);
142
- if (x >= T(XCF_R1[2])) return MillsRatio_CF(u, 8, 1);
143
- if (x >= T(XCF_R1[1])) return MillsRatio_CF(u, 10, 1);
144
- return MillsRatio_CF(u, 12, 1); /* bridge */
157
+ if (x >= T(XCF_R1[5])) return MillsRatio_CF(u, NCF_R1[5], 1); /* x >= 12800: CF n=2 */
158
+ if (x >= T(XCF_R1[4])) return MillsRatio_CF(u, NCF_R1[4], 1); /* x in [165, 12800): CF n=4 */
159
+ if (x >= T(XCF_R1[3])) return MillsRatio_CF(u, NCF_R1[3], 1); /* x in [41, 165): CF n=6 */
160
+ if (x >= T(XCF_R1[2])) return MillsRatio_CF(u, NCF_R1[2], 1); /* x in [21.2, 41): CF n=8 */
161
+ if (x >= T(XCF_R1[1])) return MillsRatio_CF(u, NCF_R1[1], 1); /* x in [14.5, 21.2): CF n=10 */
162
+ return MillsRatio_CF(u, NCF_R1[0], 1); /* x in [11.5, 14.5): CF n=12 bridge */
145
163
  }
146
164
  d = T(N_FRAC_R1) + x;
147
165
  i = static_cast<int>(T(NSEG_R1) * (x - T(1.0)) / d);
@@ -169,11 +187,11 @@ QNSPACE
169
187
  if (x >= T(XCF_R3[0])) {
170
188
  u = x * x + T(3.0);
171
189
  if (u > T(U_MAX)) return T(0.0);
172
- if (x >= T(XCF_R3[4])) return MillsRatio_CF(u, 4, 3);
173
- if (x >= T(XCF_R3[3])) return MillsRatio_CF(u, 6, 3);
174
- if (x >= T(XCF_R3[2])) return MillsRatio_CF(u, 8, 3);
175
- if (x >= T(XCF_R3[1])) return MillsRatio_CF(u, 10, 3);
176
- return MillsRatio_CF(u, 12, 3); /* bridge */
190
+ if (x >= T(XCF_R3[4])) return MillsRatio_CF(u, NCF_R3[4], 3); /* x >= 17300: CF n=4 */
191
+ if (x >= T(XCF_R3[3])) return MillsRatio_CF(u, NCF_R3[3], 3); /* x in [210, 17300): CF n=6 */
192
+ if (x >= T(XCF_R3[2])) return MillsRatio_CF(u, NCF_R3[2], 3); /* x in [50.5, 210): CF n=8 */
193
+ if (x >= T(XCF_R3[1])) return MillsRatio_CF(u, NCF_R3[1], 3); /* x in [25.4, 50.5): CF n=10 */
194
+ return MillsRatio_CF(u, NCF_R3[0], 3); /* x in [17.1, 25.4): CF n=12 bridge */
177
195
  }
178
196
  d = T(N_FRAC_R3) + x;
179
197
  i = static_cast<int>(x / d * T(NSEG_R3));
@@ -79,16 +79,16 @@ QNSPACE
79
79
  /* Asymp CF DD ladder, even-only n aligned with R_hat_1's CF cutoffs
80
80
  * XCF_R1[5..2] = 12800, 165, 41, 21.2. Falls through to Taylor when
81
81
  * a < XCF_R1[2] = 21.2. */
82
- if (a >= T(XCF_R1[5])) return MillsRatioDiff_CF<T>(x, dx, 2); /* a >= 12800 */
83
- else if (a >= T(XCF_R1[4])) return MillsRatioDiff_CF<T>(x, dx, 4); /* a >= 165 */
84
- else if (a >= T(XCF_R1[3])) return MillsRatioDiff_CF<T>(x, dx, 6); /* a >= 41 */
85
- else if (a >= T(XCF_R1[2])) return MillsRatioDiff_CF<T>(x, dx, 8); /* a in [21.2, 41) */
82
+ if (a >= T(XCF_R1[5])) return MillsRatioDiff_CF<T>(x, dx, NCF_R1[5]); /* a >= 12800: CF n=2 */
83
+ else if (a >= T(XCF_R1[4])) return MillsRatioDiff_CF<T>(x, dx, NCF_R1[4]); /* a in [165, 12800): CF n=4 */
84
+ else if (a >= T(XCF_R1[3])) return MillsRatioDiff_CF<T>(x, dx, NCF_R1[3]); /* a in [41, 165): CF n=6 */
85
+ else if (a >= T(XCF_R1[2])) return MillsRatioDiff_CF<T>(x, dx, NCF_R1[2]); /* a in [21.2, 41): CF n=8 */
86
86
 
87
87
  /* a < 21.2: 5-term Taylor seeded by R''' (N=5 balance, ~38 eps at gate) */
88
88
  T u = x * x + T(3.0); /* shared shifted variable */
89
89
  T r_d3;
90
90
  if (x >= T(XCF_R3[0])) /* x in [17.1, ~22): CF n=12 directly */
91
- r_d3 = MillsRatio_CF<T>(u, 12, 3);
91
+ r_d3 = MillsRatio_CF<T>(u, NCF_R3[0], 3);
92
92
  else /* x < 17.1: segmented Chebyshev path */
93
93
  r_d3 = MillsRatioDeriv3<T>(x);
94
94
  T r_d1 = (r_d3 + T(1.0)) / u; /* descend: -R'(x), cancellation-free */
@@ -9,9 +9,19 @@ inline constexpr double M_SQRT2PI_2 = 1.2533141373155001; /* R(0) = sqrt(pi/2)
9
9
  inline constexpr double U_MAX = 1.3407807929942596e+154; /* sqrt(DBL_MAX); R1/R3 -> 0 beyond */
10
10
  inline constexpr double X_NEG_MAX = -37.5; /* x < this: R/R1/R3 reflection's exp(x^2/2) overflows; saturate to +inf */
11
11
 
12
- inline constexpr double XCF_R[7] = {9.5, 11.4, 15.1, 24.1, 59.3, 548.0, 67000000.0}; /* bridge n=12, then n=10,8,6,4,2,0 */
13
- inline constexpr double XCF_R1[6] = {11.5, 14.5, 21.2, 41.0, 165.0, 12800.0}; /* bridge n=12, then n=10,8,6,4,2 */
14
- inline constexpr double XCF_R3[5] = {17.1, 25.4, 50.5, 210.0, 17300.0}; /* bridge n=12, then n=10,8,6,4 */
12
+ /* XCF_R* ladders: lower-edge cutoffs for each CF tier. XCF_R*[0] is the
13
+ * bridge entry (smallest x in CF region); subsequent entries are tier
14
+ * boundaries. NCF_R* are parallel arrays giving the CF order n_terms to
15
+ * use at each tier (NCF_R*[k] applies when x >= XCF_R*[k] and x < XCF_R*[k+1];
16
+ * the last entry of NCF_R covers x above the last XCF_R cutoff). */
17
+ inline constexpr double XCF_R[7] = {9.5, 11.4, 15.1, 24.1, 59.3, 548.0, 67000000.0};
18
+ inline constexpr int NCF_R[7] = { 12, 10, 8, 6, 4, 2, 0};
19
+
20
+ inline constexpr double XCF_R1[6] = {11.5, 14.5, 21.2, 41.0, 165.0, 12800.0};
21
+ inline constexpr int NCF_R1[6] = { 12, 10, 8, 6, 4, 2};
22
+
23
+ inline constexpr double XCF_R3[5] = {17.1, 25.4, 50.5, 210.0, 17300.0};
24
+ inline constexpr int NCF_R3[5] = { 12, 10, 8, 6, 4};
15
25
 
16
26
  inline constexpr double N_FRAC_R1 = 2.5;
17
27
  inline constexpr int NSEG_R1 = 32;
@@ -20,8 +30,37 @@ inline constexpr double N_FRAC_R3 = 3.5;
20
30
  inline constexpr int NSEG_R3 = 50;
21
31
  inline constexpr int TMAX_R3 = 45;
22
32
 
23
- /* Rrel_below1: deg-14, single segment on [0,1] */
24
- inline constexpr double C_Rrel[15] = {1.0, -0.6266570686593154, 0.3333333334079696, -0.1566642686167042, 0.06666668208874643, -0.026110812434658907, 0.0095242488364147, -0.0032651464622909286, 0.0010609141093610216, -0.0003302935739398907, 9.998664887097097e-05, -2.9417736033873193e-05, 7.859376331521683e-06, -1.5910288145548496e-06, 1.689407651021219e-07};
33
+ /* Rrel_below1: deg-7, 12 uniform segments on [0, 1]; max per-seg rel-err = 7.13e-17.
34
+ * Per-call cost matches R1 (8 Horner mults + 1 segment lookup), down from the
35
+ * previous deg-14 single-segment form (14 mults). Also speeds up R(x) and
36
+ * R1(x) at small x since both use the identity R = sqrt(pi/2) - x * Rrel_below1. */
37
+ inline constexpr int NSEG_RREL = 12;
38
+ inline constexpr double C_Rrel[96] = {
39
+ 0.99999999999999989, -0.052221422388137158, 0.002314814814632304, -9.066219018308359e-05,
40
+ 3.2150148093635393e-06, -1.049207214667232e-07, 3.1747412868461658e-09, -8.1818321557437068e-11,
41
+ 0.95000584342332284, -0.04785142539805684, 0.0020611150286913332, -7.8790704394343048e-05,
42
+ 2.7351696394277882e-06, -8.7568840012488809e-08, 2.6040490377601506e-09, -6.6128211226567048e-11,
43
+ 0.90413939248828323, -0.043955049458090562, 0.0018403159170131999, -6.8675945685293206e-05,
44
+ 2.3340724416270501e-06, -7.3316002324167622e-08, 2.1427519540086741e-09, -5.3618158471580657e-11,
45
+ 0.86195824584709368, -0.040471463270170725, 0.001647590369901791, -6.0031835892380922e-05,
46
+ 1.9977576684326855e-06, -6.1571686018192153e-08, 1.7686869030624921e-09, -4.3611606027074922e-11,
47
+ 0.8230762790219901, -0.037348684558952627, 0.0014788913058506813, -5.2622673426225258e-05,
48
+ 1.7149036061140052e-06, -5.1864346992849886e-08, 1.464404082345293e-09, -3.558226982637687e-11,
49
+ 0.7871555275635429, -0.03454216113748549, 0.0013308152825848647, -4.6253658706491024e-05,
50
+ 1.4763029262718868e-06, -4.381624734045847e-08, 1.2161205298368843e-09, -2.9119444573423483e-11,
51
+ 0.75389936172361582, -0.032013598325074694, 0.0012004915918592111, -4.0763305386601887e-05,
52
+ 1.2744446141417648e-06, -3.7123845055879282e-08, 1.0129151506068687e-09, -2.3901605254302183e-11,
53
+ 0.72304672999479636, -0.029729986988100948, 0.0010854917967352113, -3.6017342938875408e-05,
54
+ 1.1031827972270407e-06, -3.1542467834696725e-08, 8.461075312198616e-10, -1.96762563556725e-11,
55
+ 0.69436728992725238, -0.027662795465682701, 0.00098375571844156904, -3.1903802382321565e-05,
56
+ 9.5747359208258599e-07, -2.6874297328552898e-08, 7.0877706144625224e-10, -1.6244501366989223e-11,
57
+ 0.66765727766945626, -0.025787295774111246, 0.00089353070040033291, -2.832904354394483e-05,
58
+ 8.331653564502964e-07, -2.2958919563475081e-08, 5.9538950878966358e-10, -1.3449189871286501e-11,
59
+ 0.6427359943405786, -0.024082000158919439, 0.0008133216211253367, -2.5214533869796095e-05,
60
+ 7.2683100257424873e-07, -1.9665870750764083e-08, 5.0150614189839877e-10, -1.1165784642725488e-11,
61
+ 0.61944280892438686, -0.022528188592743449, 0.00074184963493787457, -2.249422893909321e-05,
62
+ 6.3563353781433684e-07, -1.6888739426799828e-08, 4.2355646646197732e-10, -9.2953031295141281e-12,
63
+ };
25
64
  /* R1 = -R': flat 26 x 8 (deg-7); bucket i = C_R1[i*8+k] */
26
65
  inline constexpr double C_R1[208] = {0.34432045758120156, -0.03405489990411223, 0.001192475013485524, -1.3635915460280841e-05, -1.3251365677088036e-07, 2.4578598186034305e-09, 4.7259798016565235e-11, -2.1299291732726891e-13, 0.3114442667663644, -0.031711375106782305, 0.0011507974681864693, -1.4140453769849712e-05, -1.1952291224066734e-07, 2.7367623481353177e-09, 4.577568410470565e-11, -3.4644867471321874e-13, 0.28086943193327807, -0.029452665667327314, 0.0011076870163868847, -1.4590274431017942e-05, -1.051645883314536e-07, 3.00394263963843e-09, 4.3356088452077136e-11, -4.908348064347212e-13, 0.25250976089012617, -0.02728146783978619, 0.001063315885024093, -1.4980043440399068e-05, -8.9511711273763e-08, 3.2535620231815327e-09, 3.9923965131252817e-11, -6.434215671525449e-13, 0.22627654267305497, -0.025200117744054493, 0.0010178718054031299, -1.5304778731445228e-05, -7.266756081693456e-08, 3.4793782218609222e-09, 3.542133108597344e-11, -8.005004273636312e-13, 0.2020789228021104, -0.023210561535870394, 0.0009715567721355419, -1.555997480906793e-05, -5.476736805112463e-08, 3.6748803621119108e-09, 2.981614382368417e-11, -9.573261822764798e-13, 0.1798243069999376, -0.021314328438901478, 0.0009245854194418766, -1.574173268587291e-05, -3.597923298071676e-08, 3.833466388717661e-09, 2.3109595935902425e-11, -1.108115098551026e-12, 0.15941879012402702, -0.019512507416774686, 0.0008771830040236347, -1.5846891568595946e-05, -1.650404553414359e-08, 3.948664179564567e-09, 1.5343435068724515e-11, -1.2461203413548787e-12, 0.14076760627842333, -0.01780572827295679, 0.0008295829956692178, -1.587315787368715e-05, 3.4258061653874034e-09, 4.014394860143601e-09, 6.6067680330346175e-12, -1.3638064663876794e-12, 0.12377559528870606, -0.01619414794994658, 0.0007820242912950428, -1.5819226312877644e-05, 2.3549140060769075e-08, 4.025273115508551e-09, -2.958346618579145e-12, -1.4531425859246267e-12, 0.10834767997374334, -0.014677442751291432, 0.0007347480850363722, -1.568488705701397e-05, 4.3580259611923756e-08, 3.976934719948031e-09, -1.3153353021684132e-11, -1.5060277702761603e-12, 0.0943893479629662, -0.013254807126140003, 0.0006879944458428944, -1.547111245079173e-05, 6.321490918831119e-08, 3.8663762221956915e-09, -2.3722632943972796e-11, -1.5148512230532907e-12, 0.08180713122626623, -0.011924959533228441, 0.0006419986740560224, -1.5180116517391639e-05, 8.213791675062653e-08, 3.6922860926877568e-09, -3.4356875881364274e-11, -1.4731730171396532e-12, 0.07050907604494921, -0.010686155738024478, 0.0005969875285749982, -1.48153806721575e-05, 1.0003241787830908e-07, 3.4553412408264596e-09, -4.4701242481255216e-11, -1.3764887281773427e-12, 0.06040519589650897, -0.009536209694355962, 0.0005531754350527934, -1.438163976502519e-05, 1.1659041314902527e-07, 3.158438467770723e-09, -5.436892460793421e-11, -1.2230145032238319e-12, 0.051407899690700455, -0.008472521924474962, 0.0005107608014036381, -1.3884823877572707e-05, 1.3152425187566604e-07, 2.806828171228694e-09, -6.296026047136019e-11, -1.014401164890225e-12, 0.04343238801085694, -0.007492115047014164, 0.0004699225778571462, -1.3331953255339888e-05, 1.4457847261351243e-07, 2.408118619722417e-09, -7.008691905435431e-11, -7.562622998141824e-13, 0.03639701050419264, -0.006591675822397399, 0.00043081720292740893, -1.273098633749718e-05, 1.5554128375514165e-07, 1.972124460314804e-09, -7.539985358319632e-11, -4.583894179026021e-13, 0.03022357833593512, -0.0057676028054052825, 0.00039357607223790807, -1.2090623945587052e-05, 1.6425485980300317e-07, 1.510543578358e-09, -7.861882135731254e-11, -1.3453580375042955e-13, 0.024837626665472186, -0.005016058433263478, 0.0003583036528881787, -1.1420076101325395e-05, 1.706235866941693e-07, 1.036462079424263e-09, -7.95604210426085e-11, 1.9831276835300475e-13, 0.020168623389682224, -0.004333024155107946, 0.00032507634148359177, -1.072880134841987e-05, 1.746194370082991e-07, 5.637070820781498e-10, -7.816100808861748e-11, 5.211942931994726e-13, 0.016150121880213728, -0.0037143570452199816, 0.0002939421296615079, -1.002623145989574e-05, 1.7628380941330315e-07, 1.0608900697596745e-10, -7.449073982704427e-11, 8.148726397980141e-13, 0.01271985704941791, -0.003155846255834055, 0.0002649210987800892, -9.321496586034821e-06, 1.7572542851795311e-07, -3.234043106873131e-10, -6.875556935207283e-11, 1.061797613056228e-12, 0.009819785730108346, -0.002653267668440114, 0.00023800671851479017, -8.62316683305915e-06, 1.7311425406524061e-07, -7.133843445508475e-10, -6.12853392609736e-11, 1.2480422998988533e-12, 0.007396073954182386, -0.0022024352007907985, 0.00021316787662600472, -7.93902566639996e-06, 1.6867175299844368e-07, -1.0547269597103247e-09, -5.250812569094551e-11, 1.364889655169418e-12, 0.005399035170233996, -0.0017992474166552762, 0.00019035152391663708, -7.275888307985233e-06, 1.626582865548259e-07, -1.3410511347824749e-09, -4.2913325720609484e-11, 1.409765189350702e-12};
27
66
  /* R3 = -R''': flat 45 x 9 (deg-8); bucket i = C_R3[i*9+k] */
@@ -18,20 +18,49 @@ from array import array
18
18
 
19
19
  M_SQRT2PI = 2.5066282746310002
20
20
  M_SQRT2PI_2 = 1.2533141373155001 # R(0) = sqrt(pi/2) = M_SQRT2PI/2
21
- XCF_R = (9.5, 11.4, 15.1, 24.1, 59.3, 548.0, 67000000.0) # (bridge x_cf=n=12, then ascending CF tiers n=10,8,6,4,2,0)
21
+ XCF_R = (9.5, 11.4, 15.1, 24.1, 59.3, 548.0, 67000000.0)
22
+ NCF_R = (12, 10, 8, 6, 4, 2, 0) # CF order paired with each XCF_R tier
22
23
  # _U_MAX = sqrt(DBL_MAX) ~ 1.34e154. Past it x*x overflows the quadratic CF
23
24
  # denominators of R1/R3; there the functions are ~0, so the guard returns 0.
24
25
  _U_MAX = math.sqrt(sys.float_info.max)
25
26
 
26
- # --- Rrel_below1: the [0,1] primitive shared by R and R1 (see emit_R_R1_Rrel) ---
27
- # C_Rrel: deg-14 Horner of Rrel_below1(x) = (sqrt(pi/2)-R(x))/x over x in [0,1]
28
- # (15 coeffs, ascending, >0). Recover R = sqrt(pi/2) - x*Rrel_below1, R1 = 1 - x*R.
29
- C_Rrel = array('d', (1.0, -0.6266570686593154, 0.3333333334079696, -0.1566642686167042, 0.06666668208874643, -0.026110812434658907, 0.0095242488364147, -0.0032651464622909286, 0.0010609141093610216, -0.0003302935739398907, 9.998664887097097e-05, -2.9417736033873193e-05, 7.859376331521683e-06, -1.5910288145548496e-06, 1.689407651021219e-07))
27
+ # --- Rrel_below1: the [0,1] primitive shared by R and R1 ---
28
+ # Deg-7 in 12 uniform segments on [0, 1]; bucket i = C_Rrel[i*8 + k], lookup by
29
+ # i = floor(x * NSEG_RREL), local coord s = x*NSEG_RREL - i. Same per-call cost
30
+ # as R1 (8 Horner mults + 1 lookup); was deg-14 single segment (14 mults).
31
+ NSEG_RREL = 12
32
+ C_Rrel = array('d', (
33
+ 0.99999999999999989, -0.052221422388137158, 0.002314814814632304, -9.066219018308359e-05,
34
+ 3.2150148093635393e-06, -1.049207214667232e-07, 3.1747412868461658e-09, -8.1818321557437068e-11,
35
+ 0.95000584342332284, -0.04785142539805684, 0.0020611150286913332, -7.8790704394343048e-05,
36
+ 2.7351696394277882e-06, -8.7568840012488809e-08, 2.6040490377601506e-09, -6.6128211226567048e-11,
37
+ 0.90413939248828323, -0.043955049458090562, 0.0018403159170131999, -6.8675945685293206e-05,
38
+ 2.3340724416270501e-06, -7.3316002324167622e-08, 2.1427519540086741e-09, -5.3618158471580657e-11,
39
+ 0.86195824584709368, -0.040471463270170725, 0.001647590369901791, -6.0031835892380922e-05,
40
+ 1.9977576684326855e-06, -6.1571686018192153e-08, 1.7686869030624921e-09, -4.3611606027074922e-11,
41
+ 0.8230762790219901, -0.037348684558952627, 0.0014788913058506813, -5.2622673426225258e-05,
42
+ 1.7149036061140052e-06, -5.1864346992849886e-08, 1.464404082345293e-09, -3.558226982637687e-11,
43
+ 0.7871555275635429, -0.03454216113748549, 0.0013308152825848647, -4.6253658706491024e-05,
44
+ 1.4763029262718868e-06, -4.381624734045847e-08, 1.2161205298368843e-09, -2.9119444573423483e-11,
45
+ 0.75389936172361582, -0.032013598325074694, 0.0012004915918592111, -4.0763305386601887e-05,
46
+ 1.2744446141417648e-06, -3.7123845055879282e-08, 1.0129151506068687e-09, -2.3901605254302183e-11,
47
+ 0.72304672999479636, -0.029729986988100948, 0.0010854917967352113, -3.6017342938875408e-05,
48
+ 1.1031827972270407e-06, -3.1542467834696725e-08, 8.461075312198616e-10, -1.96762563556725e-11,
49
+ 0.69436728992725238, -0.027662795465682701, 0.00098375571844156904, -3.1903802382321565e-05,
50
+ 9.5747359208258599e-07, -2.6874297328552898e-08, 7.0877706144625224e-10, -1.6244501366989223e-11,
51
+ 0.66765727766945626, -0.025787295774111246, 0.00089353070040033291, -2.832904354394483e-05,
52
+ 8.331653564502964e-07, -2.2958919563475081e-08, 5.9538950878966358e-10, -1.3449189871286501e-11,
53
+ 0.6427359943405786, -0.024082000158919439, 0.0008133216211253367, -2.5214533869796095e-05,
54
+ 7.2683100257424873e-07, -1.9665870750764083e-08, 5.0150614189839877e-10, -1.1165784642725488e-11,
55
+ 0.61944280892438686, -0.022528188592743449, 0.00074184963493787457, -2.249422893909321e-05,
56
+ 6.3563353781433684e-07, -1.6888739426799828e-08, 4.2355646646197732e-10, -9.2953031295141281e-12,
57
+ ))
30
58
 
31
59
  # --- R / R1: hybrid split at x=1 (memory-minimal; see emit_R_R1_Rrel) ---
32
60
  # x<=1: use C_Rrel above. x>1: R1 has a deg-7 table (C_R1) in t=(x-1)/(N_FRAC_R1+x),
33
61
  # R = (1-R1)/x. Beyond x_cf each uses its own tiered CF (XCF_R at top, XCF_R1 below).
34
- XCF_R1 = (11.5, 14.5, 21.2, 41.0, 165.0, 12800.0) # (bridge x_cf=n=12, then ascending CF tiers n=10,8,6,4,2)
62
+ XCF_R1 = (11.5, 14.5, 21.2, 41.0, 165.0, 12800.0)
63
+ NCF_R1 = (12, 10, 8, 6, 4, 2) # CF order paired with each XCF_R1 tier
35
64
  N_FRAC_R1 = 2.5 # shifted-t scale: t = (x-1)/(N_FRAC_R1 + x), t=0 at x=1
36
65
  NSEG_R1 = 32 # equal t-buckets over [0,1] (XCF-independent partition)
37
66
  TMAX_R1 = 26 # stored buckets 0..TMAX_R1-1 of C_R1; cover x in [1, XMAX_R1]
@@ -71,7 +100,8 @@ C_R1 = array('d', (
71
100
  # equal buckets (FIXED partition). i = int(x/(N_FRAC_R3+x)*NSEG_R3); local coordinate
72
101
  # s = ((NSEG_R3-i)*x - i*N_FRAC_R3)/(N_FRAC_R3+x) (not NSEG*w-i) keeps precision at large x.
73
102
  N_FRAC_R3 = 3.5 # w-bucket scale: w = x/(N_FRAC_R3 + x)
74
- XCF_R3 = (17.1, 25.4, 50.5, 210.0, 17300.0) # (bridge x_cf=n=12, then ascending CF tiers n=10,8,6,4); XCF_R3[0] in bucket ~37
103
+ XCF_R3 = (17.1, 25.4, 50.5, 210.0, 17300.0) # XCF_R3[0] in bucket ~37
104
+ NCF_R3 = (12, 10, 8, 6, 4) # CF order paired with each XCF_R3 tier
75
105
  NSEG_R3 = 50 # total equal-width buckets of w=x/(N_FRAC_R3+x) over [0,1] (XCF-independent)
76
106
  TMAX_R3 = 45 # coefficients cover buckets 0..TMAX_R3-1, i.e. t in [0, TMAX_R3)
77
107
  XMAX_R3 = 31.5 # max x covered by C_R3 (~1.24x bridge); XCF_R3[0] may rise to XMAX_R3 w/o refit
@@ -127,10 +157,15 @@ C_R3 = array('d', (
127
157
 
128
158
 
129
159
  def Rrel_below1(x):
130
- """Rrel_below1(x) = (sqrt(pi/2) - R(x))/x for x in [0,1] (deg-14, >0);
131
- R(x) = M_SQRT2PI_2 - x*Rrel_below1(x). Pinned so Rrel_below1(0) = -R'(0) = 1."""
160
+ """Rrel_below1(x) = (sqrt(pi/2) - R(x))/x for x in [0,1] (12 segments,
161
+ deg-7 each, >0); R(x) = M_SQRT2PI_2 - x*Rrel_below1(x). Rrel_below1(0) = 1."""
162
+ i = int(NSEG_RREL * x)
163
+ if i >= NSEG_RREL:
164
+ i = NSEG_RREL - 1
165
+ s = NSEG_RREL * x - i
166
+ o = i * 8
132
167
  c = C_Rrel
133
- return ((((((((((((((c[14])*x + c[13])*x + c[12])*x + c[11])*x + c[10])*x + c[9])*x + c[8])*x + c[7])*x + c[6])*x + c[5])*x + c[4])*x + c[3])*x + c[2])*x + c[1])*x + c[0]
168
+ return (((((((c[o+7])*s + c[o+6])*s + c[o+5])*s + c[o+4])*s + c[o+3])*s + c[o+2])*s + c[o+1])*s + c[o]
134
169
 
135
170
 
136
171
  def R013_CF(x_or_u, n, d):
@@ -198,17 +233,23 @@ def R(x):
198
233
  """Mills ratio R(x) = N(-x)/n(x), scalar float (any sign)."""
199
234
  if x < 0.0:
200
235
  return M_SQRT2PI * math.exp(0.5 * x * x) - R(-x)
201
- if x <= 1.0: # R = sqrt(pi/2) - x*Rrel_below1(x) (inlined)
236
+ if x <= 1.0: # R = sqrt(pi/2) - x*Rrel_below1(x) (inlined segmented)
237
+ i = int(NSEG_RREL * x)
238
+ if i >= NSEG_RREL:
239
+ i = NSEG_RREL - 1
240
+ s = NSEG_RREL * x - i
241
+ o = i * 8
202
242
  c = C_Rrel
203
- return M_SQRT2PI_2 - x * (((((((((((((((c[14])*x + c[13])*x + c[12])*x + c[11])*x + c[10])*x + c[9])*x + c[8])*x + c[7])*x + c[6])*x + c[5])*x + c[4])*x + c[3])*x + c[2])*x + c[1])*x + c[0])
243
+ rrel = (((((((c[o+7])*s + c[o+6])*s + c[o+5])*s + c[o+4])*s + c[o+3])*s + c[o+2])*s + c[o+1])*s + c[o]
244
+ return M_SQRT2PI_2 - x * rrel
204
245
  if x >= XCF_R[0]: # tiered CF convergents (shared with R1, R3 via R013_CF)
205
- if x >= XCF_R[6]: return 1.0 / x # n=0
206
- if x >= XCF_R[5]: return R013_CF(x, 2, 0)
207
- if x >= XCF_R[4]: return R013_CF(x, 4, 0)
208
- if x >= XCF_R[3]: return R013_CF(x, 6, 0)
209
- if x >= XCF_R[2]: return R013_CF(x, 8, 0)
210
- if x >= XCF_R[1]: return R013_CF(x, 10, 0)
211
- return R013_CF(x, 12, 0) # bridge
246
+ if x >= XCF_R[6]: return 1.0 / x # x >= 67000000: n=0 degenerate
247
+ if x >= XCF_R[5]: return R013_CF(x, NCF_R[5], 0) # x in [548, 67e6): CF n=2
248
+ if x >= XCF_R[4]: return R013_CF(x, NCF_R[4], 0) # x in [59.3, 548): CF n=4
249
+ if x >= XCF_R[3]: return R013_CF(x, NCF_R[3], 0) # x in [24.1, 59.3): CF n=6
250
+ if x >= XCF_R[2]: return R013_CF(x, NCF_R[2], 0) # x in [15.1, 24.1): CF n=8
251
+ if x >= XCF_R[1]: return R013_CF(x, NCF_R[1], 0) # x in [11.4, 15.1): CF n=10
252
+ return R013_CF(x, NCF_R[0], 0) # x in [9.5, 11.4): CF n=12 bridge
212
253
  d = N_FRAC_R1 + x # 1 < x < XCF_R[0]: R = (1 - R1)/x, R1 from C_R1
213
254
  i = int(NSEG_R1 * (x - 1.0) / d)
214
255
  if i >= TMAX_R1:
@@ -223,18 +264,24 @@ def R1(x):
223
264
  """R1(x) = 1 - x R(x) = -R'(x), scalar float (any sign)."""
224
265
  if x < 0.0: # reflection: R1(x) = R1(-x) - M_SQRT2PI*x*exp(x^2/2)
225
266
  return M_SQRT2PI * (-x) * math.exp(0.5 * x * x) + R1(-x)
226
- if x <= 1.0: # R1 = 1 - x*R, R = sqrt(pi/2)-x*Rrel_below1 (inlined)
267
+ if x <= 1.0: # R1 = 1 - x*R, R = sqrt(pi/2)-x*Rrel_below1 (inlined segmented)
268
+ i = int(NSEG_RREL * x)
269
+ if i >= NSEG_RREL:
270
+ i = NSEG_RREL - 1
271
+ s = NSEG_RREL * x - i
272
+ o = i * 8
227
273
  c = C_Rrel
228
- return 1.0 - x * (M_SQRT2PI_2 - x * (((((((((((((((c[14])*x + c[13])*x + c[12])*x + c[11])*x + c[10])*x + c[9])*x + c[8])*x + c[7])*x + c[6])*x + c[5])*x + c[4])*x + c[3])*x + c[2])*x + c[1])*x + c[0]))
274
+ rrel = (((((((c[o+7])*s + c[o+6])*s + c[o+5])*s + c[o+4])*s + c[o+3])*s + c[o+2])*s + c[o+1])*s + c[o]
275
+ return 1.0 - x * (M_SQRT2PI_2 - x * rrel)
229
276
  if x >= XCF_R1[0]:
230
277
  u = x*x + 3.0 # kernel's shifted variable; shared with _U_MAX guard and R013_CF
231
278
  if u > _U_MAX: return 0.0 # +3 shift in threshold is invisible (_U_MAX >> 3 at saturation)
232
- if x >= XCF_R1[5]: return R013_CF(u, 2, 1)
233
- if x >= XCF_R1[4]: return R013_CF(u, 4, 1)
234
- if x >= XCF_R1[3]: return R013_CF(u, 6, 1)
235
- if x >= XCF_R1[2]: return R013_CF(u, 8, 1)
236
- if x >= XCF_R1[1]: return R013_CF(u, 10, 1)
237
- return R013_CF(u, 12, 1) # bridge
279
+ if x >= XCF_R1[5]: return R013_CF(u, NCF_R1[5], 1) # x >= 12800: CF n=2
280
+ if x >= XCF_R1[4]: return R013_CF(u, NCF_R1[4], 1) # x in [165, 12800): CF n=4
281
+ if x >= XCF_R1[3]: return R013_CF(u, NCF_R1[3], 1) # x in [41, 165): CF n=6
282
+ if x >= XCF_R1[2]: return R013_CF(u, NCF_R1[2], 1) # x in [21.2, 41): CF n=8
283
+ if x >= XCF_R1[1]: return R013_CF(u, NCF_R1[1], 1) # x in [14.5, 21.2): CF n=10
284
+ return R013_CF(u, NCF_R1[0], 1) # x in [11.5, 14.5): CF n=12 bridge
238
285
  d = N_FRAC_R1 + x # 1 < x < XCF_R1[0]: deg-7 t-bucket
239
286
  i = int(NSEG_R1 * (x - 1.0) / d)
240
287
  if i >= TMAX_R1:
@@ -252,11 +299,11 @@ def R3(x):
252
299
  if x >= XCF_R3[0]:
253
300
  u = x*x + 3.0 # kernel's shifted variable; shared with _U_MAX guard and R013_CF
254
301
  if u > _U_MAX: return 0.0 # +3 shift in threshold is invisible (_U_MAX >> 3 at saturation)
255
- if x >= XCF_R3[4]: return R013_CF(u, 4, 3)
256
- if x >= XCF_R3[3]: return R013_CF(u, 6, 3)
257
- if x >= XCF_R3[2]: return R013_CF(u, 8, 3)
258
- if x >= XCF_R3[1]: return R013_CF(u, 10, 3)
259
- return R013_CF(u, 12, 3) # bridge
302
+ if x >= XCF_R3[4]: return R013_CF(u, NCF_R3[4], 3) # x >= 17300: CF n=4
303
+ if x >= XCF_R3[3]: return R013_CF(u, NCF_R3[3], 3) # x in [210, 17300): CF n=6
304
+ if x >= XCF_R3[2]: return R013_CF(u, NCF_R3[2], 3) # x in [50.5, 210): CF n=8
305
+ if x >= XCF_R3[1]: return R013_CF(u, NCF_R3[1], 3) # x in [25.4, 50.5): CF n=10
306
+ return R013_CF(u, NCF_R3[0], 3) # x in [17.1, 25.4): CF n=12 bridge
260
307
  d = N_FRAC_R3 + x
261
308
  i = int(x / d * NSEG_R3)
262
309
  s = ((NSEG_R3 - i) * x - i * N_FRAC_R3) / d
@@ -68,14 +68,14 @@ def R_DD(x, dx, theta=1):
68
68
  # Asymp CF DD ladder, even-only n aligned with R_hat_1's CF convergent rate (n+1)!/a^(2n) ~ eps:
69
69
  # thresholds are exactly R_hat_1's CF cutoffs at n = 2, 4, 6, 8 (mc.XCF_R1[5..2]). Falls
70
70
  # through to Taylor when a < mc.XCF_R1[2] (= 21.2).
71
- if a >= mc.XCF_R1[5]: return R_DD_CF(x, dx, 2) # a >= 12800
72
- elif a >= mc.XCF_R1[4]: return R_DD_CF(x, dx, 4) # a >= 165
73
- elif a >= mc.XCF_R1[3]: return R_DD_CF(x, dx, 6) # a >= 41
74
- elif a >= mc.XCF_R1[2]: return R_DD_CF(x, dx, 8) # a in [21.2, 41): bottom row
71
+ if a >= mc.XCF_R1[5]: return R_DD_CF(x, dx, mc.NCF_R1[5]) # a >= 12800: CF n=2
72
+ elif a >= mc.XCF_R1[4]: return R_DD_CF(x, dx, mc.NCF_R1[4]) # a in [165, 12800): CF n=4
73
+ elif a >= mc.XCF_R1[3]: return R_DD_CF(x, dx, mc.NCF_R1[3]) # a in [41, 165): CF n=6
74
+ elif a >= mc.XCF_R1[2]: return R_DD_CF(x, dx, mc.NCF_R1[2]) # a in [21.2, 41): CF n=8 bottom row
75
75
  # a < mc.XCF_R1[2] (21.2): 5-term Taylor seeded by R''' (N=5 balance, ~38 eps at gate)
76
76
  u = x*x + 3.0 # kernel's shifted variable; shared with R013_CF, descent, and ascent
77
77
  if x >= _R3_XCF: # x in [17.1, ~22): mc.R3's CF n=12 path; call directly with our u
78
- r_d3 = mc.R013_CF(u, 12, 3) # skips mc.R3's sign/U_MAX/ladder dispatch + redundant x*x + 3
78
+ r_d3 = mc.R013_CF(u, mc.NCF_R3[0], 3) # skips mc.R3's sign/U_MAX/ladder dispatch + redundant x*x + 3
79
79
  else: # x < 17.1: segmented Chebyshev path inside mc.R3
80
80
  r_d3 = mc.R3(x) # = -R'''(x)
81
81
  r_d1 = (r_d3 + 1.0) / u # descend: -R'(x), cancellation-free (odd -> odd); u = x^2 + 3