numbl 0.1.7 → 0.2.0
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.
- package/binding.gyp +53 -2
- package/dist-cli/cli.js +35560 -23939
- package/dist-lib/lib.js +42463 -31995
- package/dist-lib/numbl-core/executeCode.d.ts +20 -0
- package/dist-lib/numbl-core/helpers/reduction-helpers.d.ts +7 -2
- package/dist-lib/numbl-core/interpreter/builtins/datetime.d.ts +39 -0
- package/dist-lib/numbl-core/interpreter/builtins/index.d.ts +1 -0
- package/dist-lib/numbl-core/interpreter/builtins/time-system.d.ts +1 -0
- package/dist-lib/numbl-core/interpreter/builtins/types.d.ts +96 -5
- package/dist-lib/numbl-core/interpreter/interpreter.d.ts +37 -3
- package/dist-lib/numbl-core/interpreter/types.d.ts +1 -1
- package/dist-lib/numbl-core/jit/c/abi.d.ts +90 -0
- package/dist-lib/numbl-core/jit/c/assemble.d.ts +56 -0
- package/dist-lib/numbl-core/jit/c/classify.d.ts +70 -0
- package/dist-lib/numbl-core/jit/c/compile.d.ts +37 -0
- package/dist-lib/numbl-core/jit/c/context.d.ts +152 -0
- package/dist-lib/numbl-core/jit/c/emit/assign.d.ts +20 -0
- package/dist-lib/numbl-core/jit/c/emit/complexScalar.d.ts +18 -0
- package/dist-lib/numbl-core/jit/c/emit/fused.d.ts +42 -0
- package/dist-lib/numbl-core/jit/c/emit/helpers.d.ts +40 -0
- package/dist-lib/numbl-core/jit/c/emit/index.d.ts +14 -0
- package/dist-lib/numbl-core/jit/c/emit/scalar.d.ts +23 -0
- package/dist-lib/numbl-core/jit/c/emit/stmt.d.ts +25 -0
- package/dist-lib/numbl-core/jit/c/emit/tensor.d.ts +127 -0
- package/dist-lib/numbl-core/jit/c/emit/userCall.d.ts +58 -0
- package/dist-lib/numbl-core/jit/c/epilogue.d.ts +26 -0
- package/dist-lib/numbl-core/jit/c/feasibility.d.ts +44 -0
- package/dist-lib/numbl-core/jit/c/hybrid.d.ts +42 -0
- package/dist-lib/numbl-core/jit/c/install.d.ts +15 -0
- package/dist-lib/numbl-core/jit/c/parityError.d.ts +26 -0
- package/dist-lib/numbl-core/jit/c/prelude.d.ts +37 -0
- package/dist-lib/numbl-core/jit/c/registry.d.ts +51 -0
- package/dist-lib/numbl-core/jit/c/visit.d.ts +63 -0
- package/dist-lib/numbl-core/jit/e1/install.d.ts +13 -0
- package/dist-lib/numbl-core/jit/e1/kernelEmit.d.ts +54 -0
- package/dist-lib/numbl-core/jit/e1/openmpFlag.d.ts +13 -0
- package/dist-lib/numbl-core/jit/e1/scalarFnKernel.d.ts +44 -0
- package/dist-lib/numbl-core/jit/fusedChainHelpers.d.ts +65 -0
- package/dist-lib/numbl-core/jit/fusedScalarEmit.d.ts +61 -0
- package/dist-lib/numbl-core/jit/fusion.d.ts +71 -0
- package/dist-lib/numbl-core/jit/fusionOps.d.ts +25 -0
- package/dist-lib/numbl-core/{interpreter/jit → jit}/index.d.ts +2 -2
- package/dist-lib/numbl-core/jit/jitBailSafety.d.ts +41 -0
- package/dist-lib/numbl-core/{interpreter/jit → jit}/jitLoop.d.ts +2 -2
- package/dist-lib/numbl-core/{interpreter/jit → jit}/jitLoopAnalysis.d.ts +6 -1
- package/dist-lib/numbl-core/jit/jitLower.d.ts +122 -0
- package/dist-lib/numbl-core/jit/jitLowerExpr.d.ts +27 -0
- package/dist-lib/numbl-core/jit/jitLowerStmt.d.ts +9 -0
- package/dist-lib/numbl-core/{interpreter/jit → jit}/jitLowerTypes.d.ts +7 -3
- package/dist-lib/numbl-core/jit/jitTopLevel.d.ts +22 -0
- package/dist-lib/numbl-core/{interpreter/jit → jit}/jitTypes.d.ts +133 -1
- package/dist-lib/numbl-core/{interpreter/jit → jit/js}/jitCodegen.d.ts +2 -2
- package/dist-lib/numbl-core/{interpreter/jit → jit/js}/jitCodegenHoist.d.ts +19 -1
- package/dist-lib/numbl-core/{interpreter/jit → jit/js}/jitHelpers.d.ts +15 -3
- package/dist-lib/numbl-core/{interpreter/jit → jit/js}/jitHelpersIndex.d.ts +7 -0
- package/dist-lib/numbl-core/jit/js/jitHelpersTensor.d.ts +34 -0
- package/dist-lib/numbl-core/jit/js/jsFusedCodegen.d.ts +17 -0
- package/dist-lib/numbl-core/jit/scalarEmit.d.ts +58 -0
- package/dist-lib/numbl-core/lexer/types.d.ts +2 -1
- package/dist-lib/numbl-core/native/lapack-bridge.d.ts +39 -1
- package/dist-lib/numbl-core/ops/bessel.d.ts +18 -0
- package/dist-lib/numbl-core/ops/comparison.d.ts +11 -0
- package/dist-lib/numbl-core/ops/complexBinaryElemwise.d.ts +10 -0
- package/dist-lib/numbl-core/ops/complexUnaryElemwise.d.ts +8 -0
- package/dist-lib/numbl-core/ops/dispatch.d.ts +26 -0
- package/dist-lib/numbl-core/ops/index.d.ts +8 -0
- package/dist-lib/numbl-core/ops/opCodes.d.ts +70 -0
- package/dist-lib/numbl-core/ops/realBinaryElemwise.d.ts +8 -0
- package/dist-lib/numbl-core/ops/realUnaryElemwise.d.ts +5 -0
- package/dist-lib/numbl-core/ops/reduce.d.ts +6 -0
- package/dist-lib/numbl-core/parser/types.d.ts +6 -0
- package/dist-lib/numbl-core/runtime/alloc.d.ts +23 -0
- package/dist-lib/numbl-core/runtime/runtime.d.ts +1 -0
- package/dist-lib/numbl-core/version.d.ts +1 -1
- package/native/jit_runtime/jit_runtime.c +261 -0
- package/native/jit_runtime/jit_runtime.h +204 -0
- package/native/numbl_addon.cpp +53 -1
- package/native/ops/bessel.c +572 -0
- package/native/ops/comparison.c +150 -0
- package/native/ops/complex_binary_elemwise.c +192 -0
- package/native/ops/complex_unary_elemwise.c +152 -0
- package/native/ops/numbl_ops.c +66 -0
- package/native/ops/numbl_ops.h +262 -0
- package/native/ops/real_binary_elemwise.c +85 -0
- package/native/ops/real_unary_elemwise.c +104 -0
- package/native/ops/reduce.c +162 -0
- package/native/ops_napi.cpp +320 -0
- package/package.json +10 -9
- package/dist-lib/numbl-core/interpreter/jit/jitHelpersTensor.d.ts +0 -28
- package/dist-lib/numbl-core/interpreter/jit/jitLower.d.ts +0 -23
- /package/dist-lib/numbl-core/{interpreter/jit → jit/js}/jitHelpersComplex.d.ts +0 -0
|
@@ -0,0 +1,572 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bessel tensor ops for real arguments.
|
|
3
|
+
*
|
|
4
|
+
* C port of src/numbl-core/helpers/bessel.ts. Matches that implementation
|
|
5
|
+
* bit-for-bit so the TS and native paths return identical results.
|
|
6
|
+
*
|
|
7
|
+
* Integer orders 0,1 use Cephes rational polynomial approximations.
|
|
8
|
+
* Higher integer orders use forward recurrence (stable for x >= n).
|
|
9
|
+
* Non-integer orders use power series (small x) or Hankel asymptotic (large x).
|
|
10
|
+
*
|
|
11
|
+
* Cephes coefficients: Copyright 1984-2000 by Stephen L. Moshier, BSD license.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
#include "numbl_ops.h"
|
|
15
|
+
|
|
16
|
+
#include <math.h>
|
|
17
|
+
#include <stddef.h>
|
|
18
|
+
|
|
19
|
+
static const double PI_C = 3.14159265358979323846;
|
|
20
|
+
|
|
21
|
+
/* ── Polynomial evaluation (Horner, descending powers) ─────────────────── */
|
|
22
|
+
|
|
23
|
+
static inline double polyeval(const double* c, int len, double x) {
|
|
24
|
+
double r = c[0];
|
|
25
|
+
for (int i = 1; i < len; i++) r = r * x + c[i];
|
|
26
|
+
return r;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* ── Lanczos gamma (matches helpers/bessel.ts lanczosGamma) ─────────────── */
|
|
30
|
+
|
|
31
|
+
static double lgamma_lanczos(double x) {
|
|
32
|
+
if (x < 0.5) {
|
|
33
|
+
return PI_C / (sin(PI_C * x) * lgamma_lanczos(1.0 - x));
|
|
34
|
+
}
|
|
35
|
+
static const double coef[9] = {
|
|
36
|
+
0.99999999999980993, 676.5203681218851, -1259.1392167224028,
|
|
37
|
+
771.32342877765313, -176.61502916214059, 12.507343278686905,
|
|
38
|
+
-0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7,
|
|
39
|
+
};
|
|
40
|
+
x -= 1.0;
|
|
41
|
+
double a = coef[0];
|
|
42
|
+
for (int i = 1; i < 9; i++) a += coef[i] / (x + i);
|
|
43
|
+
const double g = 7.0;
|
|
44
|
+
double t = x + g + 0.5;
|
|
45
|
+
return sqrt(2.0 * PI_C) * pow(t, x + 0.5) * exp(-t) * a;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* ── Cephes J0 ──────────────────────────────────────────────────────────── */
|
|
49
|
+
|
|
50
|
+
static double j0_large(double x);
|
|
51
|
+
static double j1_large(double x);
|
|
52
|
+
static double y0_large(double x);
|
|
53
|
+
static double y1_large(double x);
|
|
54
|
+
|
|
55
|
+
static double cephes_j0(double x) {
|
|
56
|
+
if (x < 0) x = -x;
|
|
57
|
+
if (x <= 5.0) {
|
|
58
|
+
double z = x * x;
|
|
59
|
+
const double DR1 = 5.78318596294678452118;
|
|
60
|
+
const double DR2 = 30.4712623436620863991;
|
|
61
|
+
static const double RP[4] = {
|
|
62
|
+
-4.79443220978201773821e9, 1.95617491946556577543e12,
|
|
63
|
+
-2.49248344360967716204e14, 9.70862251047306323952e15,
|
|
64
|
+
};
|
|
65
|
+
static const double RQ[9] = {
|
|
66
|
+
1.0, 4.99563147152651017219e2, 1.73785401676374683123e5,
|
|
67
|
+
4.84409658339962045305e7, 1.11855537045356834862e10,
|
|
68
|
+
2.11277520115489217587e12, 3.10518229857422583814e14,
|
|
69
|
+
3.18121955943204943306e16, 1.71086294081043136091e18,
|
|
70
|
+
};
|
|
71
|
+
double p = polyeval(RP, 4, z);
|
|
72
|
+
double q = polyeval(RQ, 9, z);
|
|
73
|
+
return (z - DR1) * (z - DR2) * (p / q);
|
|
74
|
+
}
|
|
75
|
+
return j0_large(x);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static double j0_large(double x) {
|
|
79
|
+
static const double PP[7] = {
|
|
80
|
+
7.96936729297347051624e-4, 8.28352392107440799803e-2,
|
|
81
|
+
1.23953371646414299388, 5.4472500305876877509, 8.74716500199817011941,
|
|
82
|
+
5.30324038235394892183, 9.99999999999999997821e-1,
|
|
83
|
+
};
|
|
84
|
+
static const double PQ[7] = {
|
|
85
|
+
9.24408810558863637013e-4, 8.56288474354474431428e-2,
|
|
86
|
+
1.25352743901058953537, 5.47097740330417105182, 8.76190883237069594232,
|
|
87
|
+
5.30605288235394617618, 1.00000000000000000218,
|
|
88
|
+
};
|
|
89
|
+
static const double QP[8] = {
|
|
90
|
+
-1.13663838898469149931e-2, -1.28252718670509318512,
|
|
91
|
+
-1.95539544257735972385e1, -9.32060152123768231369e1,
|
|
92
|
+
-1.77681167980488050595e2, -1.47077505154951170175e2,
|
|
93
|
+
-5.1410532676659933022e1, -6.05014350600728481186,
|
|
94
|
+
};
|
|
95
|
+
static const double QQ[8] = {
|
|
96
|
+
1.0, 6.43178256118178023184e1, 8.56430025976980587198e2,
|
|
97
|
+
3.88240183605401609683e3, 7.24046774195652478189e3,
|
|
98
|
+
5.93072701187316984827e3, 2.06209331660327847417e3,
|
|
99
|
+
2.42005740240291393179e2,
|
|
100
|
+
};
|
|
101
|
+
double w = 5.0 / x;
|
|
102
|
+
double z = w * w;
|
|
103
|
+
double p = polyeval(PP, 7, z) / polyeval(PQ, 7, z);
|
|
104
|
+
double q = polyeval(QP, 8, z) / polyeval(QQ, 8, z);
|
|
105
|
+
double xn = x - PI_C / 4.0;
|
|
106
|
+
return sqrt(2.0 / (PI_C * x)) * (p * cos(xn) - w * q * sin(xn));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/* ── Cephes J1 ──────────────────────────────────────────────────────────── */
|
|
110
|
+
|
|
111
|
+
static double cephes_j1(double x) {
|
|
112
|
+
double sign = x < 0 ? -1.0 : 1.0;
|
|
113
|
+
if (x < 0) x = -x;
|
|
114
|
+
if (x <= 5.0) {
|
|
115
|
+
double z = x * x;
|
|
116
|
+
const double Z1 = 1.46819706421238932572e1;
|
|
117
|
+
const double Z2 = 4.92184563216946036703e1;
|
|
118
|
+
static const double RP[4] = {
|
|
119
|
+
-8.99971225705559398224e8, 4.52228297998194034323e11,
|
|
120
|
+
-7.27494245221818276015e13, 3.68295732863852883286e15,
|
|
121
|
+
};
|
|
122
|
+
static const double RQ[9] = {
|
|
123
|
+
1.0, 6.20836478118054335476e2, 2.56987256757748830383e5,
|
|
124
|
+
8.35146791431949253037e7, 2.21511595479792499675e10,
|
|
125
|
+
4.74914122079991414898e12, 7.84369607876235854894e14,
|
|
126
|
+
8.95222336184627338078e16, 5.32278620332680085395e18,
|
|
127
|
+
};
|
|
128
|
+
double p = polyeval(RP, 4, z);
|
|
129
|
+
double q = polyeval(RQ, 9, z);
|
|
130
|
+
return sign * x * (z - Z1) * (z - Z2) * (p / q);
|
|
131
|
+
}
|
|
132
|
+
return sign * j1_large(x);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
static double j1_large(double x) {
|
|
136
|
+
static const double PP[7] = {
|
|
137
|
+
7.62125616208173112003e-4, 7.31397056940917570436e-2,
|
|
138
|
+
1.12719608129684925192, 5.11207951146807644818, 8.42404590141772420927,
|
|
139
|
+
5.21451598682361821619, 1.00000000000000000254,
|
|
140
|
+
};
|
|
141
|
+
static const double PQ[7] = {
|
|
142
|
+
5.71323128072548699714e-4, 6.88455908754495404082e-2,
|
|
143
|
+
1.10514232634061696926, 5.07386386128601488557, 8.39985554327604159757,
|
|
144
|
+
5.20982848682361821619, 9.99999999999999997461e-1,
|
|
145
|
+
};
|
|
146
|
+
static const double QP[8] = {
|
|
147
|
+
5.10862594750176621635e-2, 4.9821387295123344942, 7.58238284132545283818e1,
|
|
148
|
+
3.667796093601507778e2, 7.10856304998926107277e2, 5.97489612400613639965e2,
|
|
149
|
+
2.11688757100572135698e2, 2.52070205858023719784e1,
|
|
150
|
+
};
|
|
151
|
+
static const double QQ[8] = {
|
|
152
|
+
1.0, 7.42373277035675149943e1, 1.05644886038262816351e3,
|
|
153
|
+
4.98641058337653607651e3, 9.56231892404756170795e3, 7.9970416044735068365e3,
|
|
154
|
+
2.826192785176390966e3, 3.36093607810698293419e2,
|
|
155
|
+
};
|
|
156
|
+
double w = 5.0 / x;
|
|
157
|
+
double z = w * w;
|
|
158
|
+
double p = polyeval(PP, 7, z) / polyeval(PQ, 7, z);
|
|
159
|
+
double q = polyeval(QP, 8, z) / polyeval(QQ, 8, z);
|
|
160
|
+
double xn = x - 3.0 * PI_C / 4.0;
|
|
161
|
+
return sqrt(2.0 / (PI_C * x)) * (p * cos(xn) - w * q * sin(xn));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/* ── Cephes Y0 ──────────────────────────────────────────────────────────── */
|
|
165
|
+
|
|
166
|
+
static double cephes_y0(double x) {
|
|
167
|
+
if (x <= 5.0) {
|
|
168
|
+
static const double YP[8] = {
|
|
169
|
+
1.55924367855235737965e4, -1.46639295903971606143e7,
|
|
170
|
+
5.43526477051876500413e9, -9.82136065717911466409e11,
|
|
171
|
+
8.75906394395366999549e13, -3.46628303384729719441e15,
|
|
172
|
+
4.42733268572569800351e16, -1.84950800436986690637e16,
|
|
173
|
+
};
|
|
174
|
+
static const double YQ[8] = {
|
|
175
|
+
1.0, 1.04128353664259848412e3, 6.26107330137134956842e5,
|
|
176
|
+
2.68919633393814121987e8, 8.64002487103935000337e10,
|
|
177
|
+
2.02979612750105546709e13, 3.17157752842975028269e15,
|
|
178
|
+
2.50596256172653059228e17,
|
|
179
|
+
};
|
|
180
|
+
double z = x * x;
|
|
181
|
+
double p = polyeval(YP, 8, z);
|
|
182
|
+
double q = polyeval(YQ, 8, z);
|
|
183
|
+
return p / q + (2.0 / PI_C) * log(x) * cephes_j0(x);
|
|
184
|
+
}
|
|
185
|
+
return y0_large(x);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
static double y0_large(double x) {
|
|
189
|
+
/* Same P/Q polynomials as J0 large; sin/cos swapped. */
|
|
190
|
+
static const double PP[7] = {
|
|
191
|
+
7.96936729297347051624e-4, 8.28352392107440799803e-2,
|
|
192
|
+
1.23953371646414299388, 5.4472500305876877509, 8.74716500199817011941,
|
|
193
|
+
5.30324038235394892183, 9.99999999999999997821e-1,
|
|
194
|
+
};
|
|
195
|
+
static const double PQ[7] = {
|
|
196
|
+
9.24408810558863637013e-4, 8.56288474354474431428e-2,
|
|
197
|
+
1.25352743901058953537, 5.47097740330417105182, 8.76190883237069594232,
|
|
198
|
+
5.30605288235394617618, 1.00000000000000000218,
|
|
199
|
+
};
|
|
200
|
+
static const double QP[8] = {
|
|
201
|
+
-1.13663838898469149931e-2, -1.28252718670509318512,
|
|
202
|
+
-1.95539544257735972385e1, -9.32060152123768231369e1,
|
|
203
|
+
-1.77681167980488050595e2, -1.47077505154951170175e2,
|
|
204
|
+
-5.1410532676659933022e1, -6.05014350600728481186,
|
|
205
|
+
};
|
|
206
|
+
static const double QQ[8] = {
|
|
207
|
+
1.0, 6.43178256118178023184e1, 8.56430025976980587198e2,
|
|
208
|
+
3.88240183605401609683e3, 7.24046774195652478189e3,
|
|
209
|
+
5.93072701187316984827e3, 2.06209331660327847417e3,
|
|
210
|
+
2.42005740240291393179e2,
|
|
211
|
+
};
|
|
212
|
+
double w = 5.0 / x;
|
|
213
|
+
double z = w * w;
|
|
214
|
+
double p = polyeval(PP, 7, z) / polyeval(PQ, 7, z);
|
|
215
|
+
double q = polyeval(QP, 8, z) / polyeval(QQ, 8, z);
|
|
216
|
+
double xn = x - PI_C / 4.0;
|
|
217
|
+
return sqrt(2.0 / (PI_C * x)) * (p * sin(xn) + w * q * cos(xn));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/* ── Cephes Y1 ──────────────────────────────────────────────────────────── */
|
|
221
|
+
|
|
222
|
+
static double cephes_y1(double x) {
|
|
223
|
+
if (x <= 5.0) {
|
|
224
|
+
static const double YP[6] = {
|
|
225
|
+
1.2632047479017802644e9, -6.47355876379160291031e11,
|
|
226
|
+
1.14509511541823727583e14, -8.12770255501325109621e15,
|
|
227
|
+
2.02439475713594898196e17, -7.78877196265950026825e17,
|
|
228
|
+
};
|
|
229
|
+
static const double YQ[9] = {
|
|
230
|
+
1.0, 5.94301592346128195359e2, 2.35564092943068577943e5,
|
|
231
|
+
7.3481194445972170566e7, 1.87601316108706159478e10,
|
|
232
|
+
3.88231277496238566008e12, 6.20557727146953693363e14,
|
|
233
|
+
6.87141087355300489866e16, 3.97270608116560655612e18,
|
|
234
|
+
};
|
|
235
|
+
double z = x * x;
|
|
236
|
+
double p = polyeval(YP, 6, z);
|
|
237
|
+
double q = polyeval(YQ, 9, z);
|
|
238
|
+
return x * (p / q) + (2.0 / PI_C) * (cephes_j1(x) * log(x) - 1.0 / x);
|
|
239
|
+
}
|
|
240
|
+
return y1_large(x);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
static double y1_large(double x) {
|
|
244
|
+
static const double PP[7] = {
|
|
245
|
+
7.62125616208173112003e-4, 7.31397056940917570436e-2,
|
|
246
|
+
1.12719608129684925192, 5.11207951146807644818, 8.42404590141772420927,
|
|
247
|
+
5.21451598682361821619, 1.00000000000000000254,
|
|
248
|
+
};
|
|
249
|
+
static const double PQ[7] = {
|
|
250
|
+
5.71323128072548699714e-4, 6.88455908754495404082e-2,
|
|
251
|
+
1.10514232634061696926, 5.07386386128601488557, 8.39985554327604159757,
|
|
252
|
+
5.20982848682361821619, 9.99999999999999997461e-1,
|
|
253
|
+
};
|
|
254
|
+
static const double QP[8] = {
|
|
255
|
+
5.10862594750176621635e-2, 4.9821387295123344942, 7.58238284132545283818e1,
|
|
256
|
+
3.667796093601507778e2, 7.10856304998926107277e2, 5.97489612400613639965e2,
|
|
257
|
+
2.11688757100572135698e2, 2.52070205858023719784e1,
|
|
258
|
+
};
|
|
259
|
+
static const double QQ[8] = {
|
|
260
|
+
1.0, 7.42373277035675149943e1, 1.05644886038262816351e3,
|
|
261
|
+
4.98641058337653607651e3, 9.56231892404756170795e3, 7.9970416044735068365e3,
|
|
262
|
+
2.826192785176390966e3, 3.36093607810698293419e2,
|
|
263
|
+
};
|
|
264
|
+
double w = 5.0 / x;
|
|
265
|
+
double z = w * w;
|
|
266
|
+
double p = polyeval(PP, 7, z) / polyeval(PQ, 7, z);
|
|
267
|
+
double q = polyeval(QP, 8, z) / polyeval(QQ, 8, z);
|
|
268
|
+
double xn = x - 3.0 * PI_C / 4.0;
|
|
269
|
+
return sqrt(2.0 / (PI_C * x)) * (p * sin(xn) + w * q * cos(xn));
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/* ── Fallbacks for non-integer orders / higher orders ──────────────────── */
|
|
273
|
+
|
|
274
|
+
static double besselj_series(double nu, double x) {
|
|
275
|
+
double halfX = x * 0.5;
|
|
276
|
+
double term = pow(halfX, nu) / lgamma_lanczos(nu + 1.0);
|
|
277
|
+
double sum = term;
|
|
278
|
+
double x2over4 = -halfX * halfX;
|
|
279
|
+
for (int k = 1; k <= 300; k++) {
|
|
280
|
+
term *= x2over4 / ((double)k * (k + nu));
|
|
281
|
+
sum += term;
|
|
282
|
+
if (fabs(term) < fabs(sum) * 1e-16) break;
|
|
283
|
+
}
|
|
284
|
+
return sum;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
static double hankel_besselj(double nu, double x) {
|
|
288
|
+
double mu = 4.0 * nu * nu;
|
|
289
|
+
double chi = x - (nu * 0.5 + 0.25) * PI_C;
|
|
290
|
+
double P = 1.0, Q = 0.0, termP = 1.0, termQ = 1.0;
|
|
291
|
+
for (int k = 0; k < 30; k++) {
|
|
292
|
+
if (k > 0) {
|
|
293
|
+
double num = -(mu - (4.0 * k - 3.0) * (4.0 * k - 3.0)) *
|
|
294
|
+
(mu - (4.0 * k - 1.0) * (4.0 * k - 1.0));
|
|
295
|
+
termP *= num / ((2.0 * k - 1.0) * (2.0 * k) * 64.0 * x * x);
|
|
296
|
+
P += termP;
|
|
297
|
+
}
|
|
298
|
+
if (k == 0) {
|
|
299
|
+
termQ = (mu - 1.0) / (8.0 * x);
|
|
300
|
+
Q = termQ;
|
|
301
|
+
} else {
|
|
302
|
+
double num = -(mu - (4.0 * k - 1.0) * (4.0 * k - 1.0)) *
|
|
303
|
+
(mu - (4.0 * k + 1.0) * (4.0 * k + 1.0));
|
|
304
|
+
termQ *= num / (2.0 * k * (2.0 * k + 1.0) * 64.0 * x * x);
|
|
305
|
+
Q += termQ;
|
|
306
|
+
}
|
|
307
|
+
if (fabs(termP) + fabs(termQ) < 1e-16) break;
|
|
308
|
+
}
|
|
309
|
+
return sqrt(2.0 / (PI_C * x)) * (P * cos(chi) - Q * sin(chi));
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/* ── Public scalar entry points ────────────────────────────────────────── */
|
|
313
|
+
|
|
314
|
+
static int is_int(double x) {
|
|
315
|
+
return x == floor(x);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
static double scalar_besselj(double nu, double x) {
|
|
319
|
+
if (x == 0.0) return nu == 0.0 ? 1.0 : 0.0;
|
|
320
|
+
if (x < 0.0 && !is_int(nu)) return NAN;
|
|
321
|
+
if (x < 0.0) {
|
|
322
|
+
double n = floor(nu + 0.5); /* round */
|
|
323
|
+
double s = ((long long)n & 1LL) == 0 ? 1.0 : -1.0;
|
|
324
|
+
return s * scalar_besselj(nu, -x);
|
|
325
|
+
}
|
|
326
|
+
if (nu < 0.0 && is_int(nu)) {
|
|
327
|
+
double n = floor(-nu + 0.5);
|
|
328
|
+
double s = ((long long)n & 1LL) == 0 ? 1.0 : -1.0;
|
|
329
|
+
return s * scalar_besselj(-nu, x);
|
|
330
|
+
}
|
|
331
|
+
if (is_int(nu) && nu >= 0.0) {
|
|
332
|
+
int n = (int)floor(nu + 0.5);
|
|
333
|
+
if (n == 0) return cephes_j0(x);
|
|
334
|
+
if (n == 1) return cephes_j1(x);
|
|
335
|
+
if (x < (double)n) return besselj_series((double)n, x);
|
|
336
|
+
double jm1 = cephes_j0(x);
|
|
337
|
+
double j = cephes_j1(x);
|
|
338
|
+
for (int k = 1; k < n; k++) {
|
|
339
|
+
double jnext = ((2.0 * k) / x) * j - jm1;
|
|
340
|
+
jm1 = j;
|
|
341
|
+
j = jnext;
|
|
342
|
+
}
|
|
343
|
+
return j;
|
|
344
|
+
}
|
|
345
|
+
if (x <= 25.0 + fabs(nu) * 0.5) return besselj_series(nu, x);
|
|
346
|
+
return hankel_besselj(nu, x);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
static double bessely_integer(int n, double x) {
|
|
350
|
+
if (n < 0) {
|
|
351
|
+
double s = ((-n) & 1) == 0 ? 1.0 : -1.0;
|
|
352
|
+
return s * bessely_integer(-n, x);
|
|
353
|
+
}
|
|
354
|
+
if (n == 0) return cephes_y0(x);
|
|
355
|
+
if (n == 1) return cephes_y1(x);
|
|
356
|
+
double ym1 = cephes_y0(x);
|
|
357
|
+
double y = cephes_y1(x);
|
|
358
|
+
for (int k = 1; k < n; k++) {
|
|
359
|
+
double ynext = ((2.0 * k) / x) * y - ym1;
|
|
360
|
+
ym1 = y;
|
|
361
|
+
y = ynext;
|
|
362
|
+
}
|
|
363
|
+
return y;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
static double scalar_bessely(double nu, double x) {
|
|
367
|
+
if (x <= 0.0) return NAN;
|
|
368
|
+
if (is_int(nu)) {
|
|
369
|
+
int n = (int)floor(nu + (nu >= 0 ? 0.5 : -0.5));
|
|
370
|
+
return bessely_integer(n, x);
|
|
371
|
+
}
|
|
372
|
+
double sinPi = sin(nu * PI_C);
|
|
373
|
+
return (scalar_besselj(nu, x) * cos(nu * PI_C) - scalar_besselj(-nu, x)) / sinPi;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
static double scalar_besseli(double nu, double x) {
|
|
377
|
+
if (x == 0.0) return nu == 0.0 ? 1.0 : 0.0;
|
|
378
|
+
if (x < 0.0 && !is_int(nu)) return NAN;
|
|
379
|
+
if (x < 0.0) {
|
|
380
|
+
double n = floor(nu + 0.5);
|
|
381
|
+
double s = ((long long)n & 1LL) == 0 ? 1.0 : -1.0;
|
|
382
|
+
return s * scalar_besseli(nu, -x);
|
|
383
|
+
}
|
|
384
|
+
if (nu < 0.0 && is_int(nu)) {
|
|
385
|
+
return scalar_besseli(-nu, x); /* I_{-n} = I_n for integer n */
|
|
386
|
+
}
|
|
387
|
+
double halfX = x * 0.5;
|
|
388
|
+
double term = pow(halfX, nu) / lgamma_lanczos(nu + 1.0);
|
|
389
|
+
double sum = term;
|
|
390
|
+
double x2over4 = halfX * halfX;
|
|
391
|
+
for (int k = 1; k <= 300; k++) {
|
|
392
|
+
term *= x2over4 / ((double)k * (k + nu));
|
|
393
|
+
sum += term;
|
|
394
|
+
if (fabs(term) < fabs(sum) * 1e-16) break;
|
|
395
|
+
}
|
|
396
|
+
return sum;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
static double besselk0(double x) {
|
|
400
|
+
const double euler = 0.5772156649015329;
|
|
401
|
+
double i0 = scalar_besseli(0.0, x);
|
|
402
|
+
double logTerm = -(log(x * 0.5) + euler) * i0;
|
|
403
|
+
double halfX = x * 0.5;
|
|
404
|
+
double x2over4 = halfX * halfX;
|
|
405
|
+
double term = 1.0;
|
|
406
|
+
double hk = 0.0;
|
|
407
|
+
double sum = 0.0;
|
|
408
|
+
for (int k = 1; k <= 300; k++) {
|
|
409
|
+
hk += 1.0 / k;
|
|
410
|
+
term *= x2over4 / ((double)k * k);
|
|
411
|
+
sum += hk * term;
|
|
412
|
+
if (fabs(term * hk) < fabs(sum) * 1e-16) break;
|
|
413
|
+
}
|
|
414
|
+
return logTerm + sum;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
static double besselk1(double x) {
|
|
418
|
+
const double euler = 0.5772156649015329;
|
|
419
|
+
double halfX = x * 0.5;
|
|
420
|
+
double x2over4 = halfX * halfX;
|
|
421
|
+
double term = 1.0;
|
|
422
|
+
double psi1 = -euler;
|
|
423
|
+
double psi2 = -euler + 1.0;
|
|
424
|
+
double S1 = term;
|
|
425
|
+
double S2 = (psi1 + psi2) * term;
|
|
426
|
+
for (int k = 1; k <= 300; k++) {
|
|
427
|
+
term *= x2over4 / ((double)k * (k + 1));
|
|
428
|
+
psi1 += 1.0 / k;
|
|
429
|
+
psi2 += 1.0 / (k + 1.0);
|
|
430
|
+
S1 += term;
|
|
431
|
+
S2 += (psi1 + psi2) * term;
|
|
432
|
+
if (fabs(term) < fabs(S1) * 1e-16) break;
|
|
433
|
+
}
|
|
434
|
+
return 1.0 / x + halfX * log(halfX) * S1 - (halfX * 0.5) * S2;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
static double besselk_integer(int n, double x) {
|
|
438
|
+
if (n == 0) return besselk0(x);
|
|
439
|
+
if (n == 1) return besselk1(x);
|
|
440
|
+
double km1 = besselk0(x);
|
|
441
|
+
double k = besselk1(x);
|
|
442
|
+
for (int i = 1; i < n; i++) {
|
|
443
|
+
double knext = ((2.0 * i) / x) * k + km1;
|
|
444
|
+
km1 = k;
|
|
445
|
+
k = knext;
|
|
446
|
+
}
|
|
447
|
+
return k;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
static double scalar_besselk(double nu, double x) {
|
|
451
|
+
if (x <= 0.0) return NAN;
|
|
452
|
+
if (nu < 0.0) nu = -nu;
|
|
453
|
+
if (is_int(nu)) {
|
|
454
|
+
int n = (int)floor(nu + 0.5);
|
|
455
|
+
return besselk_integer(n, x);
|
|
456
|
+
}
|
|
457
|
+
double sinPi = sin(nu * PI_C);
|
|
458
|
+
return (PI_C * 0.5) * (scalar_besseli(-nu, x) - scalar_besseli(nu, x)) / sinPi;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/* ── Public tensor entry points ────────────────────────────────────────── */
|
|
462
|
+
|
|
463
|
+
/* Scale factors match the existing TS code in special-math.ts:
|
|
464
|
+
* J, Y, I: exp(-|z|)
|
|
465
|
+
* K: exp(z)
|
|
466
|
+
* (The J/Y choice mirrors the current TS builtin; MATLAB's correct factor
|
|
467
|
+
* for real z is 1, but we preserve existing numerical behavior.)
|
|
468
|
+
*/
|
|
469
|
+
|
|
470
|
+
/* Minimum n before bessel_real / bessel_h go multi-threaded. Below this,
|
|
471
|
+
* per-scalar work (~50-200 ns) × n can't amortize OpenMP fork/join
|
|
472
|
+
* (~10-30 us on modern x86). 4096 elems × ~100 ns each ≈ 400 us is a
|
|
473
|
+
* comfortable crossover.
|
|
474
|
+
*/
|
|
475
|
+
#define NUMBL_BESSEL_OMP_MIN 4096
|
|
476
|
+
|
|
477
|
+
int numbl_bessel_real(int op, double nu, size_t n,
|
|
478
|
+
const double* z, int scale, double* out) {
|
|
479
|
+
if (!z || !out) return NUMBL_ERR_NULL_PTR;
|
|
480
|
+
switch (op) {
|
|
481
|
+
case NUMBL_BESSEL_J: {
|
|
482
|
+
if (scale) {
|
|
483
|
+
#pragma omp parallel for schedule(static) if (n >= NUMBL_BESSEL_OMP_MIN)
|
|
484
|
+
for (size_t i = 0; i < n; i++) {
|
|
485
|
+
double zi = z[i];
|
|
486
|
+
out[i] = scalar_besselj(nu, zi) * exp(-fabs(zi));
|
|
487
|
+
}
|
|
488
|
+
} else {
|
|
489
|
+
#pragma omp parallel for schedule(static) if (n >= NUMBL_BESSEL_OMP_MIN)
|
|
490
|
+
for (size_t i = 0; i < n; i++) out[i] = scalar_besselj(nu, z[i]);
|
|
491
|
+
}
|
|
492
|
+
return NUMBL_OK;
|
|
493
|
+
}
|
|
494
|
+
case NUMBL_BESSEL_Y: {
|
|
495
|
+
if (scale) {
|
|
496
|
+
#pragma omp parallel for schedule(static) if (n >= NUMBL_BESSEL_OMP_MIN)
|
|
497
|
+
for (size_t i = 0; i < n; i++) {
|
|
498
|
+
double zi = z[i];
|
|
499
|
+
out[i] = scalar_bessely(nu, zi) * exp(-fabs(zi));
|
|
500
|
+
}
|
|
501
|
+
} else {
|
|
502
|
+
#pragma omp parallel for schedule(static) if (n >= NUMBL_BESSEL_OMP_MIN)
|
|
503
|
+
for (size_t i = 0; i < n; i++) out[i] = scalar_bessely(nu, z[i]);
|
|
504
|
+
}
|
|
505
|
+
return NUMBL_OK;
|
|
506
|
+
}
|
|
507
|
+
case NUMBL_BESSEL_I: {
|
|
508
|
+
if (scale) {
|
|
509
|
+
#pragma omp parallel for schedule(static) if (n >= NUMBL_BESSEL_OMP_MIN)
|
|
510
|
+
for (size_t i = 0; i < n; i++) {
|
|
511
|
+
double zi = z[i];
|
|
512
|
+
out[i] = scalar_besseli(nu, zi) * exp(-fabs(zi));
|
|
513
|
+
}
|
|
514
|
+
} else {
|
|
515
|
+
#pragma omp parallel for schedule(static) if (n >= NUMBL_BESSEL_OMP_MIN)
|
|
516
|
+
for (size_t i = 0; i < n; i++) out[i] = scalar_besseli(nu, z[i]);
|
|
517
|
+
}
|
|
518
|
+
return NUMBL_OK;
|
|
519
|
+
}
|
|
520
|
+
case NUMBL_BESSEL_K: {
|
|
521
|
+
if (scale) {
|
|
522
|
+
#pragma omp parallel for schedule(static) if (n >= NUMBL_BESSEL_OMP_MIN)
|
|
523
|
+
for (size_t i = 0; i < n; i++) {
|
|
524
|
+
double zi = z[i];
|
|
525
|
+
out[i] = scalar_besselk(nu, zi) * exp(zi);
|
|
526
|
+
}
|
|
527
|
+
} else {
|
|
528
|
+
#pragma omp parallel for schedule(static) if (n >= NUMBL_BESSEL_OMP_MIN)
|
|
529
|
+
for (size_t i = 0; i < n; i++) out[i] = scalar_besselk(nu, z[i]);
|
|
530
|
+
}
|
|
531
|
+
return NUMBL_OK;
|
|
532
|
+
}
|
|
533
|
+
default:
|
|
534
|
+
return NUMBL_ERR_BAD_OP;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/* besselh(nu, K, z) with real z returns J ± i*Y (K=1: +, K=2: -).
|
|
539
|
+
* Scaled variant multiplies by exp(∓i*z).
|
|
540
|
+
*/
|
|
541
|
+
int numbl_bessel_h(int k_kind, double nu, size_t n,
|
|
542
|
+
const double* z, int scale,
|
|
543
|
+
double* out_re, double* out_im) {
|
|
544
|
+
if (!z || !out_re || !out_im) return NUMBL_ERR_NULL_PTR;
|
|
545
|
+
if (k_kind != 1 && k_kind != 2) return NUMBL_ERR_BAD_OP;
|
|
546
|
+
double ysign = k_kind == 1 ? 1.0 : -1.0;
|
|
547
|
+
if (!scale) {
|
|
548
|
+
#pragma omp parallel for schedule(static) if (n >= NUMBL_BESSEL_OMP_MIN)
|
|
549
|
+
for (size_t i = 0; i < n; i++) {
|
|
550
|
+
double zi = z[i];
|
|
551
|
+
out_re[i] = scalar_besselj(nu, zi);
|
|
552
|
+
out_im[i] = ysign * scalar_bessely(nu, zi);
|
|
553
|
+
}
|
|
554
|
+
} else {
|
|
555
|
+
/* K=1 scaled: multiply by exp(-i*z) = cos(z) - i*sin(z).
|
|
556
|
+
* K=2 scaled: multiply by exp(+i*z) = cos(z) + i*sin(z).
|
|
557
|
+
*/
|
|
558
|
+
double ssign = k_kind == 1 ? -1.0 : 1.0;
|
|
559
|
+
#pragma omp parallel for schedule(static) if (n >= NUMBL_BESSEL_OMP_MIN)
|
|
560
|
+
for (size_t i = 0; i < n; i++) {
|
|
561
|
+
double zi = z[i];
|
|
562
|
+
double J = scalar_besselj(nu, zi);
|
|
563
|
+
double Y = ysign * scalar_bessely(nu, zi);
|
|
564
|
+
double c = cos(zi);
|
|
565
|
+
double s = ssign * sin(zi);
|
|
566
|
+
/* (J + iY) * (c + is) = (J*c - Y*s) + i*(J*s + Y*c). */
|
|
567
|
+
out_re[i] = J * c - Y * s;
|
|
568
|
+
out_im[i] = J * s + Y * c;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
return NUMBL_OK;
|
|
572
|
+
}
|