use std::f64::consts::FRAC_2_PI;
use super::bessel_util::{high_word, split_words, FRAC_2_SQRT_PI, HUGE};
const R02: f64 = 1.562_499_999_999_999_5e-2; const R03: f64 = -1.899_792_942_388_547_2e-4; const R04: f64 = 1.829_540_495_327_006_7e-6; const R05: f64 = -4.618_326_885_321_032e-9; const S01: f64 = 1.561_910_294_648_900_1e-2; const S02: f64 = 1.169_267_846_633_374_5e-4; const S03: f64 = 5.135_465_502_073_181e-7; const S04: f64 = 1.166_140_033_337_9e-9;
const P_R8: [f64; 6] = [
0.00000000000000000000e+00,
-7.031_249_999_999_004e-2,
-8.081_670_412_753_498,
-2.570_631_056_797_048_5e2,
-2.485_216_410_094_288e3,
-5.253_043_804_907_295e3,
];
const P_S8: [f64; 5] = [
1.165_343_646_196_681_8e2,
3.833_744_753_641_218_3e3,
4.059_785_726_484_725_5e4,
1.167_529_725_643_759_2e5,
4.762_772_841_467_309_6e4,
];
const P_R5: [f64; 6] = [
-1.141_254_646_918_945e-11,
-7.031_249_408_735_993e-2,
-4.159_610_644_705_878,
-6.767_476_522_651_673e1,
-3.312_312_996_491_729_7e2,
-3.464_333_883_656_049e2,
];
const P_S5: [f64; 5] = [
6.075_393_826_923_003_4e1,
1.051_252_305_957_045_8e3,
5.978_970_943_338_558e3,
9.625_445_143_577_745e3,
2.406_058_159_229_391e3,
];
const P_R3: [f64; 6] = [
-2.547_046_017_719_519e-9,
-7.031_196_163_814_817e-2,
-2.409_032_215_495_296,
-2.196_597_747_348_831e1,
-5.807_917_047_017_376e1,
-3.144_794_705_948_885e1,
];
const P_S3: [f64; 5] = [
3.585_603_380_552_097e1,
3.615_139_830_503_038_6e2,
1.193_607_837_921_115_3e3,
1.127_996_798_569_074_1e3,
1.735_809_308_133_357_5e2,
];
const P_R2: [f64; 6] = [
-8.875_343_330_325_264e-8,
-7.030_309_954_836_247e-2,
-1.450_738_467_809_529_9,
-7.635_696_138_235_278,
-1.119_316_688_603_567_5e1,
-3.233_645_793_513_353_4,
];
const P_S2: [f64; 5] = [
2.222_029_975_320_888e1,
1.362_067_942_182_152e2,
2.704_702_786_580_835e2,
1.538_753_942_083_203_3e2,
1.465_761_769_482_562e1,
];
fn pzero(x: f64) -> f64 {
let ix = high_word(x) & 0x7fffffff;
let (p, q) = if ix >= 0x40200000 {
(P_R8, P_S8)
} else if ix >= 0x40122E8B {
(P_R5, P_S5)
} else if ix >= 0x4006DB6D {
(P_R3, P_S3)
} else {
(P_R2, P_S2)
};
let z = 1.0 / (x * x);
let r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5]))));
let s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4]))));
1.0 + r / s
}
const Q_R8: [f64; 6] = [
0.00000000000000000000e+00,
7.324_218_749_999_35e-2,
1.176_820_646_822_527e1,
5.576_733_802_564_019e2,
8.859_197_207_564_686e3,
3.701_462_677_768_878e4,
];
const Q_S8: [f64; 6] = [
1.637_760_268_956_898_2e2,
8.098_344_946_564_498e3,
1.425_382_914_191_204_8e5,
8.033_092_571_195_144e5,
8.405_015_798_190_605e5,
-3.438_992_935_378_666e5,
];
const Q_R5: [f64; 6] = [
1.840_859_635_945_155_3e-11,
7.324_217_666_126_848e-2,
5.835_635_089_620_569_5,
1.351_115_772_864_498_3e2,
1.027_243_765_961_641e3,
1.989_977_858_646_053_8e3,
];
const Q_S5: [f64; 6] = [
8.277_661_022_365_378e1,
2.077_814_164_213_93e3,
1.884_728_877_857_181e4,
5.675_111_228_949_473e4,
3.597_675_384_251_145e4,
-5.354_342_756_019_448e3,
];
const Q_R3: [f64; 6] = [
4.377_410_140_897_386e-9,
7.324_111_800_429_114e-2,
3.344_231_375_161_707,
4.262_184_407_454_126_5e1,
1.708_080_913_405_656e2,
1.667_339_486_966_511_7e2,
];
const Q_S3: [f64; 6] = [
4.875_887_297_245_872e1,
7.096_892_210_566_06e2,
3.704_148_226_201_113_6e3,
6.460_425_167_525_689e3,
2.516_333_689_203_689_6e3,
-1.492_474_518_361_564e2,
];
const Q_R2: [f64; 6] = [
1.504_444_448_869_832_7e-7,
7.322_342_659_630_793e-2,
1.998_191_740_938_16,
1.449_560_293_478_857_4e1,
3.166_623_175_047_815_4e1,
1.625_270_757_109_292_7e1,
];
const Q_S2: [f64; 6] = [
3.036_558_483_552_192e1,
2.693_481_186_080_498_4e2,
8.447_837_575_953_201e2,
8.829_358_451_124_886e2,
2.126_663_885_117_988_3e2,
-5.310_954_938_826_669_5,
];
fn qzero(x: f64) -> f64 {
let ix = high_word(x) & 0x7fffffff;
let (p, q) = if ix >= 0x40200000 {
(Q_R8, Q_S8)
} else if ix >= 0x40122E8B {
(Q_R5, Q_S5)
} else if ix >= 0x4006DB6D {
(Q_R3, Q_S3)
} else {
(Q_R2, Q_S2)
};
let z = 1.0 / (x * x);
let r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5]))));
let s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5])))));
(-0.125 + r / s) / x
}
const U00: f64 = -7.380_429_510_868_723e-2;
const U01: f64 = 1.766_664_525_091_811_2e-1;
const U02: f64 = -1.381_856_719_455_969e-2;
const U03: f64 = 3.474_534_320_936_836_5e-4;
const U04: f64 = -3.814_070_537_243_641_6e-6;
const U05: f64 = 1.955_901_370_350_229_2e-8;
const U06: f64 = -3.982_051_941_321_034e-11;
const V01: f64 = 1.273_048_348_341_237e-2;
const V02: f64 = 7.600_686_273_503_533e-5;
const V03: f64 = 2.591_508_518_404_578e-7;
const V04: f64 = 4.411_103_113_326_754_7e-10;
pub(crate) fn y0(x: f64) -> f64 {
let (lx, hx) = split_words(x);
let ix = 0x7fffffff & hx;
if ix >= 0x7ff00000 {
return 1.0 / (x + x * x);
}
if (ix | lx) == 0 {
return f64::NEG_INFINITY;
}
if hx < 0 {
return f64::NAN;
}
if ix >= 0x40000000 {
let s = x.sin();
let c = x.cos();
let mut ss = s - c;
let mut cc = s + c;
if ix < 0x7fe00000 {
let z = -(x + x).cos();
if (s * c) < 0.0 {
cc = z / ss;
} else {
ss = z / cc;
}
}
return if ix > 0x48000000 {
FRAC_2_SQRT_PI * ss / x.sqrt()
} else {
let u = pzero(x);
let v = qzero(x);
FRAC_2_SQRT_PI * (u * ss + v * cc) / x.sqrt()
};
}
if ix <= 0x3e400000 {
return U00 + FRAC_2_PI * x.ln();
}
let z = x * x;
let u = U00 + z * (U01 + z * (U02 + z * (U03 + z * (U04 + z * (U05 + z * U06)))));
let v = 1.0 + z * (V01 + z * (V02 + z * (V03 + z * V04)));
u / v + FRAC_2_PI * (j0(x) * x.ln())
}
pub(crate) fn j0(x: f64) -> f64 {
let hx = high_word(x);
let ix = hx & 0x7fffffff;
if x.is_nan() {
return x;
} else if x.is_infinite() {
return 0.0;
}
let x = x.abs();
if ix >= 0x40000000 {
let s = x.sin();
let c = x.cos();
let mut ss = s - c;
let mut cc = s + c;
if ix < 0x7fe00000 {
let z = -(x + x).cos();
if s * c < 0.0 {
cc = z / ss;
} else {
ss = z / cc;
}
}
return if ix > 0x48000000 {
FRAC_2_SQRT_PI * cc / (x.sqrt())
} else {
let u = pzero(x);
let v = qzero(x);
FRAC_2_SQRT_PI * (u * cc - v * ss) / x.sqrt()
};
};
if ix < 0x3f200000 {
if HUGE + x > 1.0 {
if ix < 0x3e400000 {
return 1.0; } else {
return 1.0 - 0.25 * x * x;
}
}
}
let z = x * x;
let r = z * (R02 + z * (R03 + z * (R04 + z * R05)));
let s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * S04)));
if ix < 0x3FF00000 {
1.0 + z * (-0.25 + (r / s))
} else {
let u = 0.5 * x;
(1.0 + u) * (1.0 - u) + z * (r / s)
}
}