datly 0.0.1 → 0.0.2

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.
@@ -0,0 +1,587 @@
1
+ class NormalityTests {
2
+ shapiroWilk(sample, alpha = 0.05) {
3
+ const validSample = sample.filter(val =>
4
+ typeof val === 'number' && !isNaN(val) && isFinite(val)
5
+ );
6
+
7
+ if (validSample.length < 3 || validSample.length > 5000) {
8
+ throw new Error('Shapiro-Wilk test requires between 3 and 5000 observations');
9
+ }
10
+
11
+ const n = validSample.length;
12
+ const sorted = [...validSample].sort((a, b) => a - b);
13
+
14
+ const mean = sorted.reduce((sum, val) => sum + val, 0) / n;
15
+ const ss = sorted.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0);
16
+
17
+ if (ss === 0) {
18
+ return {
19
+ statistic: NaN,
20
+ pValue: NaN,
21
+ isNormal: false,
22
+ error: 'All values are identical'
23
+ };
24
+ }
25
+
26
+ let b = 0;
27
+ for (let i = 0; i < Math.floor(n / 2); i++) {
28
+ const a = this.shapiroWilkCoefficient(i + 1, n);
29
+ b += a * (sorted[n - 1 - i] - sorted[i]);
30
+ }
31
+
32
+ const w = (b * b) / ss;
33
+ const pValue = this.shapiroWilkPValue(w, n);
34
+
35
+ return {
36
+ statistic: w,
37
+ pValue: pValue,
38
+ isNormal: pValue > alpha,
39
+ alpha: alpha,
40
+ sampleSize: n,
41
+ interpretation: this.interpretNormalityResult(pValue, alpha, 'Shapiro-Wilk')
42
+ };
43
+ }
44
+
45
+ shapiroWilkCoefficient(i, n) {
46
+ const c = [
47
+ 0, 0.7071, 0.7071, 0.6872, 0.6646, 0.6431, 0.6233, 0.6052, 0.5888, 0.5739, 0.5601
48
+ ];
49
+
50
+ if (n <= 10 && i <= n) {
51
+ return c[i] || 0.5;
52
+ }
53
+
54
+ const m = 0.5;
55
+ const s = 1;
56
+ return m + s * this.normalInverse((i - 0.375) / (n + 0.25));
57
+ }
58
+
59
+ shapiroWilkPValue(w, n) {
60
+ if (n < 3) return 1;
61
+ if (w >= 1) return 1;
62
+ if (w <= 0) return 0;
63
+
64
+ const ln_w = Math.log(w);
65
+ let z;
66
+
67
+ if (n <= 11) {
68
+ const gamma = 0.459 * n - 2.273;
69
+ z = -gamma * ln_w;
70
+ } else {
71
+ const mu = -1.5861 - 0.31082 * Math.log(n) - 0.083751 * Math.log(n) ** 2 + 0.0038915 * Math.log(n) ** 3;
72
+ const sigma = Math.exp(-0.4803 - 0.082676 * Math.log(n) + 0.0030302 * Math.log(n) ** 2);
73
+ z = (ln_w - mu) / sigma;
74
+ }
75
+
76
+ return 1 - this.standardNormalCDF(z);
77
+ }
78
+
79
+ kolmogorovSmirnov(sample, alpha = 0.05) {
80
+ const validSample = sample.filter(val =>
81
+ typeof val === 'number' && !isNaN(val) && isFinite(val)
82
+ );
83
+
84
+ if (validSample.length < 5) {
85
+ throw new Error('Kolmogorov-Smirnov test requires at least 5 observations');
86
+ }
87
+
88
+ const n = validSample.length;
89
+ const sorted = [...validSample].sort((a, b) => a - b);
90
+
91
+ const mean = sorted.reduce((sum, val) => sum + val, 0) / n;
92
+ const variance = sorted.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / (n - 1);
93
+ const stdDev = Math.sqrt(variance);
94
+
95
+ if (stdDev === 0) {
96
+ return {
97
+ statistic: NaN,
98
+ pValue: NaN,
99
+ isNormal: false,
100
+ error: 'All values are identical'
101
+ };
102
+ }
103
+
104
+ let maxD = 0;
105
+
106
+ for (let i = 0; i < n; i++) {
107
+ const standardized = (sorted[i] - mean) / stdDev;
108
+ const empiricalCDF = (i + 1) / n;
109
+ const theoreticalCDF = this.standardNormalCDF(standardized);
110
+
111
+ const d1 = Math.abs(empiricalCDF - theoreticalCDF);
112
+ const d2 = Math.abs((i / n) - theoreticalCDF);
113
+
114
+ maxD = Math.max(maxD, d1, d2);
115
+ }
116
+
117
+ const sqrtN = Math.sqrt(n);
118
+ const lambda = maxD * sqrtN;
119
+ const pValue = this.kolmogorovSmirnovPValue(lambda);
120
+
121
+ return {
122
+ statistic: maxD,
123
+ pValue: pValue,
124
+ isNormal: pValue > alpha,
125
+ alpha: alpha,
126
+ sampleSize: n,
127
+ lambda: lambda,
128
+ interpretation: this.interpretNormalityResult(pValue, alpha, 'Kolmogorov-Smirnov')
129
+ };
130
+ }
131
+
132
+ kolmogorovSmirnovPValue(lambda) {
133
+ if (lambda <= 0) return 1;
134
+ if (lambda > 7) return 0;
135
+
136
+ let sum = 0;
137
+ for (let k = 1; k <= 100; k++) {
138
+ const term = 2 * Math.pow(-1, k - 1) * Math.exp(-2 * k * k * lambda * lambda);
139
+ sum += term;
140
+ if (Math.abs(term) < 1e-12) break;
141
+ }
142
+
143
+ return Math.min(1, Math.max(0, sum));
144
+ }
145
+
146
+ andersonDarling(sample, alpha = 0.05) {
147
+ const validSample = sample.filter(val =>
148
+ typeof val === 'number' && !isNaN(val) && isFinite(val)
149
+ );
150
+
151
+ if (validSample.length < 8) {
152
+ throw new Error('Anderson-Darling test requires at least 8 observations');
153
+ }
154
+
155
+ const n = validSample.length;
156
+ const sorted = [...validSample].sort((a, b) => a - b);
157
+
158
+ const mean = sorted.reduce((sum, val) => sum + val, 0) / n;
159
+ const variance = sorted.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / (n - 1);
160
+ const stdDev = Math.sqrt(variance);
161
+
162
+ if (stdDev === 0) {
163
+ return {
164
+ statistic: NaN,
165
+ pValue: NaN,
166
+ isNormal: false,
167
+ error: 'All values are identical'
168
+ };
169
+ }
170
+
171
+ let sum = 0;
172
+ for (let i = 0; i < n; i++) {
173
+ const standardized = (sorted[i] - mean) / stdDev;
174
+ const phi = this.standardNormalCDF(standardized);
175
+ const phiComplement = this.standardNormalCDF(-standardized);
176
+
177
+ if (phi > 0 && phiComplement > 0) {
178
+ sum += (2 * i + 1) * (Math.log(phi) + Math.log(phiComplement));
179
+ }
180
+ }
181
+
182
+ const a2 = -n - (1 / n) * sum;
183
+ const a2Star = a2 * (1 + 0.75 / n + 2.25 / (n * n));
184
+
185
+ const pValue = this.andersonDarlingPValue(a2Star);
186
+
187
+ return {
188
+ statistic: a2,
189
+ adjustedStatistic: a2Star,
190
+ pValue: pValue,
191
+ isNormal: pValue > alpha,
192
+ alpha: alpha,
193
+ sampleSize: n,
194
+ interpretation: this.interpretNormalityResult(pValue, alpha, 'Anderson-Darling')
195
+ };
196
+ }
197
+
198
+ andersonDarlingPValue(a2Star) {
199
+ if (a2Star <= 0.2) {
200
+ return 1 - Math.exp(-1.2337141 / a2Star) * (2.00012 + (0.247105 - (0.0649821 - (0.0347962 - (0.011672 - 0.00168691 * a2Star) * a2Star) * a2Star) * a2Star) * a2Star);
201
+ } else if (a2Star <= 0.34) {
202
+ return 1 - Math.exp(-0.9177603 - 1.25156 * a2Star) * (1.38033 + (0.421981 - 0.668119 * a2Star) * a2Star);
203
+ } else if (a2Star < 0.6) {
204
+ return Math.exp(0.731 - 3.009 * a2Star + 4.86 * a2Star * a2Star);
205
+ } else if (a2Star < 10) {
206
+ return Math.exp(1.0776 - (2.30695 - (0.43424 - (0.082433 - (0.008056 - 0.0003146 * a2Star) * a2Star) * a2Star) * a2Star) * a2Star);
207
+ } else {
208
+ return 0;
209
+ }
210
+ }
211
+
212
+ jarqueBera(sample, alpha = 0.05) {
213
+ const validSample = sample.filter(val =>
214
+ typeof val === 'number' && !isNaN(val) && isFinite(val)
215
+ );
216
+
217
+ if (validSample.length < 4) {
218
+ throw new Error('Jarque-Bera test requires at least 4 observations');
219
+ }
220
+
221
+ const n = validSample.length;
222
+ const skewness = this.calculateSkewness(validSample);
223
+ const kurtosis = this.calculateKurtosis(validSample, true);
224
+
225
+ const jb = (n / 6) * (Math.pow(skewness, 2) + Math.pow(kurtosis, 2) / 4);
226
+ const pValue = 1 - this.chiSquareCDF(jb, 2);
227
+
228
+ return {
229
+ statistic: jb,
230
+ pValue: pValue,
231
+ isNormal: pValue > alpha,
232
+ alpha: alpha,
233
+ sampleSize: n,
234
+ skewness: skewness,
235
+ excessKurtosis: kurtosis,
236
+ interpretation: this.interpretNormalityResult(pValue, alpha, 'Jarque-Bera')
237
+ };
238
+ }
239
+
240
+ dagoTest(sample, alpha = 0.05) {
241
+ const validSample = sample.filter(val =>
242
+ typeof val === 'number' && !isNaN(val) && isFinite(val)
243
+ );
244
+
245
+ if (validSample.length < 20) {
246
+ throw new Error("D'Agostino test requires at least 20 observations");
247
+ }
248
+
249
+ const n = validSample.length;
250
+ const skewness = this.calculateSkewness(validSample);
251
+ const kurtosis = this.calculateKurtosis(validSample, true);
252
+
253
+ const skewnessZ = this.skewnessZScore(skewness, n);
254
+ const kurtosisZ = this.kurtosisZScore(kurtosis, n);
255
+
256
+ const k2 = skewnessZ * skewnessZ + kurtosisZ * kurtosisZ;
257
+ const pValue = 1 - this.chiSquareCDF(k2, 2);
258
+
259
+ return {
260
+ statistic: k2,
261
+ pValue: pValue,
262
+ isNormal: pValue > alpha,
263
+ alpha: alpha,
264
+ sampleSize: n,
265
+ skewness: skewness,
266
+ excessKurtosis: kurtosis,
267
+ skewnessZ: skewnessZ,
268
+ kurtosisZ: kurtosisZ,
269
+ interpretation: this.interpretNormalityResult(pValue, alpha, "D'Agostino K-squared")
270
+ };
271
+ }
272
+
273
+ skewnessZScore(skewness, n) {
274
+ const y = skewness * Math.sqrt((n + 1) * (n + 3) / (6 * (n - 2)));
275
+ const beta2 = 3 * (n * n + 27 * n - 70) * (n + 1) * (n + 3) / ((n - 2) * (n + 5) * (n + 7) * (n + 9));
276
+ const w2 = -1 + Math.sqrt(2 * (beta2 - 1));
277
+ const delta = 1 / Math.sqrt(0.5 * Math.log(w2));
278
+ const alpha = Math.sqrt(2 / (w2 - 1));
279
+
280
+ return delta * Math.log(y / alpha + Math.sqrt((y / alpha) ** 2 + 1));
281
+ }
282
+
283
+ kurtosisZScore(kurtosis, n) {
284
+ const e = 3 * (n - 1) / (n + 1);
285
+ const varb2 = 24 * n * (n - 2) * (n - 3) / ((n + 1) * (n + 1) * (n + 3) * (n + 5));
286
+ const x = (kurtosis - e) / Math.sqrt(varb2);
287
+ const sqrtb1 = 6 * (n * n - 5 * n + 2) / ((n + 7) * (n + 9)) * Math.sqrt(6 * (n + 3) * (n + 5) / (n * (n - 2) * (n - 3)));
288
+
289
+ const a = 6 + 8 / sqrtb1 * (2 / sqrtb1 + Math.sqrt(1 + 4 / (sqrtb1 ** 2)));
290
+
291
+ return Math.sqrt(9 * a / 2) * ((1 - 2 / a) / (1 + x * Math.sqrt(2 / (a - 4))) - 1);
292
+ }
293
+
294
+ lillieforsTest(sample, alpha = 0.05) {
295
+ const validSample = sample.filter(val =>
296
+ typeof val === 'number' && !isNaN(val) && isFinite(val)
297
+ );
298
+
299
+ if (validSample.length < 4 || validSample.length > 1000) {
300
+ throw new Error('Lilliefors test requires between 4 and 1000 observations');
301
+ }
302
+
303
+ const n = validSample.length;
304
+ const sorted = [...validSample].sort((a, b) => a - b);
305
+
306
+ const mean = sorted.reduce((sum, val) => sum + val, 0) / n;
307
+ const variance = sorted.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / (n - 1);
308
+ const stdDev = Math.sqrt(variance);
309
+
310
+ if (stdDev === 0) {
311
+ return {
312
+ statistic: NaN,
313
+ pValue: NaN,
314
+ isNormal: false,
315
+ error: 'All values are identical'
316
+ };
317
+ }
318
+
319
+ let maxD = 0;
320
+
321
+ for (let i = 0; i < n; i++) {
322
+ const standardized = (sorted[i] - mean) / stdDev;
323
+ const empiricalCDF = (i + 1) / n;
324
+ const theoreticalCDF = this.standardNormalCDF(standardized);
325
+
326
+ const d1 = Math.abs(empiricalCDF - theoreticalCDF);
327
+ const d2 = Math.abs((i / n) - theoreticalCDF);
328
+
329
+ maxD = Math.max(maxD, d1, d2);
330
+ }
331
+
332
+ const pValue = this.lillieforsPValue(maxD, n);
333
+
334
+ return {
335
+ statistic: maxD,
336
+ pValue: pValue,
337
+ isNormal: pValue > alpha,
338
+ alpha: alpha,
339
+ sampleSize: n,
340
+ interpretation: this.interpretNormalityResult(pValue, alpha, 'Lilliefors')
341
+ };
342
+ }
343
+
344
+ lillieforsPValue(d, n) {
345
+ const criticalValues = {
346
+ 4: 0.381, 5: 0.337, 6: 0.319, 7: 0.300, 8: 0.285,
347
+ 9: 0.271, 10: 0.258, 11: 0.249, 12: 0.242, 13: 0.234,
348
+ 14: 0.227, 15: 0.220, 16: 0.213, 17: 0.206, 18: 0.200,
349
+ 19: 0.195, 20: 0.190, 25: 0.173, 30: 0.161, 40: 0.144,
350
+ 50: 0.131, 100: 0.096
351
+ };
352
+
353
+ let criticalValue;
354
+ if (criticalValues[n]) {
355
+ criticalValue = criticalValues[n];
356
+ } else if (n > 100) {
357
+ criticalValue = 0.886 / Math.sqrt(n);
358
+ } else {
359
+ const keys = Object.keys(criticalValues).map(Number).sort((a, b) => a - b);
360
+ const lower = keys.filter(k => k <= n).pop();
361
+ const upper = keys.filter(k => k >= n)[0];
362
+
363
+ if (lower === upper) {
364
+ criticalValue = criticalValues[lower];
365
+ } else {
366
+ const ratio = (n - lower) / (upper - lower);
367
+ criticalValue = criticalValues[lower] + ratio * (criticalValues[upper] - criticalValues[lower]);
368
+ }
369
+ }
370
+
371
+ if (d > criticalValue) {
372
+ return 0.01;
373
+ } else if (d < criticalValue * 0.8) {
374
+ return 0.2;
375
+ } else {
376
+ return 0.05;
377
+ }
378
+ }
379
+
380
+ batchNormalityTest(sample, alpha = 0.05) {
381
+ const results = {};
382
+
383
+ try {
384
+ results.shapiroWilk = this.shapiroWilk(sample, alpha);
385
+ } catch (error) {
386
+ results.shapiroWilk = { error: error.message };
387
+ }
388
+
389
+ try {
390
+ results.jarqueBera = this.jarqueBera(sample, alpha);
391
+ } catch (error) {
392
+ results.jarqueBera = { error: error.message };
393
+ }
394
+
395
+ try {
396
+ results.andersonDarling = this.andersonDarling(sample, alpha);
397
+ } catch (error) {
398
+ results.andersonDarling = { error: error.message };
399
+ }
400
+
401
+ try {
402
+ results.kolmogorovSmirnov = this.kolmogorovSmirnov(sample, alpha);
403
+ } catch (error) {
404
+ results.kolmogorovSmirnov = { error: error.message };
405
+ }
406
+
407
+ try {
408
+ if (sample.length >= 20) {
409
+ results.dagostino = this.dagoTest(sample, alpha);
410
+ }
411
+ } catch (error) {
412
+ results.dagostino = { error: error.message };
413
+ }
414
+
415
+ const validTests = Object.entries(results).filter(([_, result]) => !result.error && result.pValue !== undefined);
416
+ const normalCount = validTests.filter(([_, result]) => result.isNormal).length;
417
+ const totalTests = validTests.length;
418
+
419
+ return {
420
+ individualTests: results,
421
+ summary: {
422
+ testsRun: totalTests,
423
+ testsPassingNormality: normalCount,
424
+ consensusNormal: normalCount >= Math.ceil(totalTests / 2),
425
+ strongNormalEvidence: normalCount === totalTests,
426
+ strongNonNormalEvidence: normalCount === 0
427
+ },
428
+ recommendation: this.getNormalityRecommendation(results, totalTests, normalCount)
429
+ };
430
+ }
431
+
432
+ getNormalityRecommendation(results, totalTests, normalCount) {
433
+ if (totalTests === 0) {
434
+ return "Unable to assess normality - insufficient data or all tests failed";
435
+ }
436
+
437
+ const ratio = normalCount / totalTests;
438
+
439
+ if (ratio === 1) {
440
+ return "Strong evidence for normality - all tests indicate normal distribution";
441
+ } else if (ratio >= 0.75) {
442
+ return "Good evidence for normality - most tests indicate normal distribution";
443
+ } else if (ratio >= 0.5) {
444
+ return "Mixed evidence - consider visual inspection and domain knowledge";
445
+ } else if (ratio > 0) {
446
+ return "Evidence against normality - most tests indicate non-normal distribution";
447
+ } else {
448
+ return "Strong evidence against normality - all tests indicate non-normal distribution";
449
+ }
450
+ }
451
+
452
+ calculateSkewness(sample, bias = false) {
453
+ const n = sample.length;
454
+ const mean = sample.reduce((sum, val) => sum + val, 0) / n;
455
+ const variance = sample.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / (n - 1);
456
+ const stdDev = Math.sqrt(variance);
457
+
458
+ if (stdDev === 0) return 0;
459
+
460
+ const skewSum = sample.reduce((sum, val) => {
461
+ return sum + Math.pow((val - mean) / stdDev, 3);
462
+ }, 0);
463
+
464
+ if (bias) {
465
+ return skewSum / n;
466
+ } else {
467
+ return (n / ((n - 1) * (n - 2))) * skewSum;
468
+ }
469
+ }
470
+
471
+ calculateKurtosis(sample, fisher = true, bias = false) {
472
+ const n = sample.length;
473
+ const mean = sample.reduce((sum, val) => sum + val, 0) / n;
474
+ const variance = sample.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / (n - 1);
475
+ const stdDev = Math.sqrt(variance);
476
+
477
+ if (stdDev === 0) return fisher ? -3 : 0;
478
+
479
+ const kurtSum = sample.reduce((sum, val) => {
480
+ return sum + Math.pow((val - mean) / stdDev, 4);
481
+ }, 0);
482
+
483
+ let kurtosis;
484
+ if (bias) {
485
+ kurtosis = kurtSum / n;
486
+ } else {
487
+ kurtosis = ((n * (n + 1)) / ((n - 1) * (n - 2) * (n - 3))) * kurtSum -
488
+ (3 * Math.pow(n - 1, 2)) / ((n - 2) * (n - 3));
489
+ }
490
+
491
+ return fisher ? kurtosis - 3 : kurtosis;
492
+ }
493
+
494
+ interpretNormalityResult(pValue, alpha, testName) {
495
+ if (pValue > alpha) {
496
+ return `${testName} test: Fail to reject null hypothesis (p-value = ${pValue.toFixed(4)} > α = ${alpha}). Data appears to be normally distributed.`;
497
+ } else {
498
+ return `${testName} test: Reject null hypothesis (p-value = ${pValue.toFixed(4)} ≤ α = ${alpha}). Data appears to be non-normally distributed.`;
499
+ }
500
+ }
501
+
502
+ standardNormalCDF(z) {
503
+ return 0.5 * (1 + this.erf(z / Math.sqrt(2)));
504
+ }
505
+
506
+ erf(x) {
507
+ const a1 = 0.254829592;
508
+ const a2 = -0.284496736;
509
+ const a3 = 1.421413741;
510
+ const a4 = -1.453152027;
511
+ const a5 = 1.061405429;
512
+ const p = 0.3275911;
513
+
514
+ const sign = x < 0 ? -1 : 1;
515
+ x = Math.abs(x);
516
+
517
+ const t = 1 / (1 + p * x);
518
+ const y = 1 - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t * Math.exp(-x * x);
519
+
520
+ return sign * y;
521
+ }
522
+
523
+ normalInverse(p) {
524
+ if (p <= 0 || p >= 1) throw new Error('p must be between 0 and 1');
525
+
526
+ const a = [-3.969683028665376e+01, 2.209460984245205e+02, -2.759285104469687e+02,
527
+ 1.383577518672690e+02, -3.066479806614716e+01, 2.506628277459239e+00];
528
+ const b = [-5.447609879822406e+01, 1.615858368580409e+02, -1.556989798598866e+02,
529
+ 6.680131188771972e+01, -1.328068155288572e+01, 1];
530
+
531
+ if (p > 0.5) return -this.normalInverse(1 - p);
532
+
533
+ const q = Math.sqrt(-2 * Math.log(p));
534
+ let num = a[5];
535
+ let den = b[5];
536
+
537
+ for (let i = 4; i >= 0; i--) {
538
+ num = num * q + a[i];
539
+ den = den * q + b[i];
540
+ }
541
+
542
+ return num / den;
543
+ }
544
+
545
+ chiSquareCDF(x, df) {
546
+ if (x <= 0) return 0;
547
+ return this.incompleteGamma(df / 2, x / 2) / this.gamma(df / 2);
548
+ }
549
+
550
+ incompleteGamma(a, x) {
551
+ if (x <= 0) return 0;
552
+
553
+ let sum = 1;
554
+ let term = 1;
555
+
556
+ for (let n = 1; n < 100; n++) {
557
+ term *= x / (a + n - 1);
558
+ sum += term;
559
+ if (Math.abs(term) < 1e-12) break;
560
+ }
561
+
562
+ return Math.pow(x, a) * Math.exp(-x) * sum;
563
+ }
564
+
565
+ gamma(x) {
566
+ const coefficients = [
567
+ 0.99999999999980993, 676.5203681218851, -1259.1392167224028,
568
+ 771.32342877765313, -176.61502916214059, 12.507343278686905,
569
+ -0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7
570
+ ];
571
+
572
+ if (x < 0.5) {
573
+ return Math.PI / (Math.sin(Math.PI * x) * this.gamma(1 - x));
574
+ }
575
+
576
+ x -= 1;
577
+ let result = coefficients[0];
578
+ for (let i = 1; i < coefficients.length; i++) {
579
+ result += coefficients[i] / (x + i);
580
+ }
581
+
582
+ const t = x + coefficients.length - 1.5;
583
+ return Math.sqrt(2 * Math.PI) * Math.pow(t, x + 0.5) * Math.exp(-t) * result;
584
+ }
585
+ }
586
+
587
+ export default NormalityTests;