1 /**
2 Authors: [Ilya Yaroshenko](http://9il.github.io)
3 
4 Copyright: © 2014-2015 [Ilya Yaroshenko](http://9il.github.io)
5 
6 License: MIT
7 */
8 module atmosphere.math;
9 
10 //import core.stdc.tgmath;
11 import std.range;
12 import std.traits;
13 import std.typecons;
14 import std.math;
15 
16 
17 version (LDC)
18 {
19 	pragma(LDC_intrinsic, "llvm.fmuladd.f#")
20 		T llvm_fmuladd(T)(T vala, T valb, T valc) @safe pure nothrow @nogc;
21 }
22 
23 /**
24 Computes accurate sum of binary logarithms of input range $(D r).
25  */
26 ElementType!Range sumOfLog2s(Range)(Range r)
27 	if (isInputRange!Range && isFloatingPoint!(ElementType!Range))
28 {
29 	import std.math: frexp;
30 	long exp = 0;
31 	Unqual!(typeof(return)) x = 1;
32 	foreach (e; r)
33 	{
34 		if (e < 0)
35 			return typeof(return).nan;
36 		int lexp = void;
37 		x *= frexp(e, lexp);
38 		exp += lexp;
39 		if (x < 0.5)
40 		{
41 			x *= 2;
42 			exp--;
43 		}
44 	}
45 	return exp + log2(x);
46 }
47 
48 //Issue 14231
49 package T findRoot(T, DF, DT)(scope DF f, in T a, in T b,
50 	scope DT tolerance) //= (T a, T b) => false)
51 	if(
52 		isFloatingPoint!T &&
53 		is(typeof(tolerance(T.init, T.init)) : bool) &&
54 		is(typeof(f(T.init)) == R, R) && isFloatingPoint!R
55 	)
56 {
57 	import std.numeric: findRoot;
58 	import std.functional;
59 	immutable fa = f(a);
60 	if(fa == 0)
61 		return a;
62 	immutable fb = f(b);
63 	if(fb == 0)
64 		return b;
65 	immutable r = findRoot!(Unqual!T, Unqual!T)(f.toDelegate, a, b, fa, fb, tolerance.toDelegate);
66 	// Return the first value if it is smaller or NaN
67 	return !(fabs(r[2]) > fabs(r[3])) ? r[0] : r[1];
68 }
69 
70 //Issue 14231
71 package T findRoot(T, DF)(scope DF f, in T a, in T b)
72 {
73 	return findRoot(f, a, b, (T a, T b) => false);
74 }
75 
76 /** Inverse of the Log Minus Digamma function
77  * 
78  *   Returns x such $(D log(x) - digamma(x) == y).
79  *
80  * References:
81  *   1. Abramowitz, M., and Stegun, I. A. (1970).
82  *	 Handbook of mathematical functions. Dover, New York,
83  *	 pages 258-259, equation 6.3.18.
84  * 
85  * Authors: Ilya Yaroshenko
86  */
87 T logmdigammaInverse(T)(const T y)
88 {
89 	//Issue 14231
90 	//import std.numeric: findRoot;
91 	enum maxY = 1 / T.min_normal;
92 	static assert(maxY > 0 && maxY <= T.max);
93 	if (y >= maxY)
94 		return 1 / y; //lim x->0 (log(x)-digamma(x))*x == 1
95 	if (y < 0)
96 		return T.nan;
97 	if (y < 2*T.min_normal)
98 		return 0.5 / y; //6.3.18
99 	if (y > 0)
100 		// x/2 <= logmdigamma(1 / x) <= x, x > 0
101 		// calls logmdigamma ~6 times
102 		return 1 / findRoot((T x) => logmdigamma(1 / x) - y, y,  2*y); // ~6 times
103 	return y; //NaN
104 }
105 
106 
107 unittest {
108 	alias T = double;
109 	import std.range : iota;
110 	import std.math : approxEqual, nextDown;
111 	//import std.mathspecial: logmdigamma;
112 	foreach (x; iota(1.3L, 2L, 0.1L))
113 	{
114 		assert(logmdigammaInverse(logmdigamma(x)).approxEqual(x));
115 		assert(logmdigammaInverse(logmdigamma(1/x)).approxEqual(1/x));
116 	}
117 	//WolframAlpha, 22.02.2015
118 	immutable T[2][5] testData = [
119 		[1.0L, 0.615556766479594378978099158335549201923L],
120 		[1.0L/8, 4.15937801516894947161054974029150730555L],
121 		[1.0L/1024, 512.166612384991507850643277924243523243L],
122 		[0.000500083333325000003968249801594877323784632117L, 1000.0L],
123 		[1017.644138623741168814449776695062817947092468536L, 1.0L/1024],
124 	];
125 	foreach(test; testData)
126 	{
127 		assert(approxEqual(logmdigammaInverse(test[0]), test[1], 1e-10, 0));
128 	}
129 	assert(approxEqual(logmdigamma(logmdigammaInverse(1.0)), 1, 1e-15, 0));
130 	assert(approxEqual(logmdigamma(logmdigammaInverse(T.min_normal)), T.min_normal, 1e-15, 0));
131 	assert(approxEqual(logmdigamma(logmdigammaInverse(T.max/2)), T.max/2, 1e-15, 0));
132 	assert(approxEqual(logmdigammaInverse(logmdigamma(1.0)), 1, 1e-10, 0));
133 	assert(approxEqual(logmdigammaInverse(logmdigamma(T.min_normal)), T.min_normal, 1e-15, 0));
134 	assert(approxEqual(logmdigammaInverse(logmdigamma(T.max/2)), T.max/2, 1e-15, 0));
135 }
136 
137 T logmdigamma(T)(const T x)
138 {
139 	static immutable T [7] Bn_n  = [
140 	1.0L/(6*2), -1.0L/(30*4), 1.0L/(42*6), -1.0L/(30*8),
141 	5.0L/(66*10), -691.0L/(2730*12), 7.0L/(6*14) ];
142 
143 	if (x <= 0.0)
144 	{
145 		if (x == 0.0)
146 		{
147 		   return T.infinity;
148 	}
149 		return T.nan;
150 	}
151 
152 	T s = x;
153 	T w = 0f;
154 	while ( s < 10f ) {
155 		w += 1f/s;
156 		s += 1f;
157 	}
158 	T y;
159 	if ( s < 1.0e17 ) {
160 		immutable T z = 1.0/(s * s);
161 		version(LDC)
162 		{
163 			y = z * 
164 				llvm_fmuladd(z,
165 				llvm_fmuladd(z,
166 				llvm_fmuladd(z,
167 				llvm_fmuladd(z,
168 				llvm_fmuladd(z,
169 				llvm_fmuladd(z,
170 				Bn_n[6] ,
171 				Bn_n[5]),
172 				Bn_n[4]),
173 				Bn_n[3]),
174 				Bn_n[2]),
175 				Bn_n[1]),
176 				Bn_n[0]);
177 		}
178 		else
179 		{
180 			y =   z * (Bn_n[0]
181 				+ z * (Bn_n[1]
182 				+ z * (Bn_n[2]
183 				+ z * (Bn_n[3]
184 				+ z * (Bn_n[4]
185 				+ z * (Bn_n[5]
186 				+ z *  Bn_n[6]))))));
187 		}
188 	} else
189 		y = 0f;
190 
191 	return x == s ? y + 0.5f/s : (log(x/s) + 0.5f/s + y + w);
192 }
193 
194 unittest {
195 	import std.typetuple;
196 	import std.math: isNaN, isIdentical, NaN, approxEqual;
197 	import std.mathspecial: digamma;
198 	foreach(T; TypeTuple!(real, double, float))
199 	{
200 		alias lmd = logmdigamma!T;
201 		assert(lmd(-5.0).isNaN());
202 		assert(isIdentical(lmd(NaN(0xABC)), NaN(0xABC)));
203 		assert(lmd(0.0) == T.infinity);
204 		for(auto x = 0.01; x < 1.0; x += 0.1)
205 			assert(approxEqual(digamma(x), log(x) - lmd(x)));
206 		for(auto x = 1.0; x < 15.0; x += 1.0)
207 			assert(approxEqual(digamma(x), log(x) - lmd(x)));		
208 	}
209 }
210 
211 
212 /++
213 Find a real minimum of a real function $(D f(x)) via bracketing. 
214 Given a function $(D f) and a range $(D (ax..bx)), 
215 returns the value of $(D x) in the range which is closest to a minimum of $(D f(x)).
216 $(D f) is never evaluted at the endpoints of $(D ax) and $(D bx).
217 If $(D f(x)) has more than one minimum in the range, one will be chosen arbitrarily. 
218 If $(D f(x)) returns NaN or -Infinity, $(D (x, f(x), NaN)) will be returned;
219 otherwise, this algorithm is guaranteed to succeed.
220 
221 Params:
222 	f = Function to be analyzed
223 	ax = Left bound of initial range of f known to contain the minimum.
224 	bx = Right bound of initial range of f known to contain the minimum.
225 	relTolerance = Relative tolerance.
226 	absTolerance = Absolute tolerance.
227 
228 Preconditions:
229 	$(D ax) and $(D bx) shall be finite reals. $(BR)
230 	$(D relTolerance) shall be normal positive real. $(BR)
231 	$(D absTolerance) shall be normal positive real no less then $(D T.epsilon*2).
232 
233 Returns:
234 	A tuple consisting of $(D x), $(D y = f(x)) and $(D error = 3 * (absTolerance * fabs(x) + relTolerance)).
235 
236 	The method used is a combination of golden section search and
237 successive parabolic interpolation. Convergence is never much slower
238 than that for a Fibonacci search.
239 
240 References:
241 	"Algorithms for Minimization without Derivatives", Richard Brent, Prentice-Hall, Inc. (1973)
242 
243 See_Also: $(LREF findRoot), $(XREF math, isNormal)
244 +/
245 
246 Tuple!(T, "x", Unqual!(ReturnType!DF), "y", T, "error") 
247 findLocalMin(T, DF)(
248 		scope DF f,
249 		in T ax,
250 		in T bx,
251 		in T relTolerance = T.epsilon^^0.25,
252 		in T absTolerance = sqrt(T.epsilon),
253 		)
254 	if(isFloatingPoint!T)
255 in
256 {
257 	assert(isFinite(ax) && isFinite(bx), "ax and bx shall be finite reals");
258 	assert(isNormal(absTolerance) && absTolerance >= T.epsilon*2, 
259 		"absTolerance shall be normal positive real no less then $(D T.epsilon*2)");
260 	assert(isNormal(relTolerance) && relTolerance > 0, 
261 		"relTolerance shall be normal positive real");
262 }
263 out(result)
264 {
265 	assert(isFinite(result.x));
266 }
267 body
268 {
269 	alias R = Unqual!(CommonType!(ReturnType!DF, T));
270 
271 	// c is the squared inverse of the golden ratio
272 	// (3 - sqrt(5))/2
273 	// Value obtained from Wolfram Alpha.
274 	immutable T c = 0x0.61c8864680b583ea0c633f9fa31237p+0L;
275 	immutable T cm1 = 0x0.9e3779b97f4a7c15f39cc0605cedc8p+0L;
276 
277 	R tolerance;
278 
279 	T a = ax > bx ? bx : ax;
280 	T b = ax > bx ? ax : bx;
281 
282 	//sequence of declarations suitable for SIMD instructions
283 
284 	T  v = a * cm1 + b * c;
285 	assert(isFinite(v));
286 
287 	R fv = f(v);
288 
289 	//R fv = f(v);
290 	if(isNaN(fv) || fv == -T.infinity)
291 		return typeof(return)(v, fv, T.init);
292 
293 	T  w = v;
294 	R fw = fv;
295 
296 	T  x = v;
297 	R fx = fv;
298 
299 	for(R d = 0, e = 0;;)
300 	{
301 		T m = (a + b) / 2;
302 
303 		// This fix is not part of original algorithm
304 		if(!isFinite(m)) // fix infinity loop. Issue can be reproduced in R.
305 		{
306 			m = a / 2 + b / 2;
307 			if(!isFinite(m)) // fast-math compiler switch is enabled
308 			{
309 				//SIMD instructions can be used by compiler, do not reduce declarations
310 				int a_exp = void;
311 				int b_exp = void;
312 				immutable an = frexp(a, a_exp);
313 				immutable bn = frexp(b, b_exp);
314 				immutable am = ldexp(an, a_exp-1);
315 				immutable bm = ldexp(bn, b_exp-1);
316 				m = am + bm;
317 				if(!isFinite(m)) // wrong input: constraints is disabled in release mode
318 				{
319 					return typeof(return).init;
320 				}
321 			}
322 		}
323 		assert(isFinite(m));
324 		tolerance = absTolerance * fabs(x) + relTolerance;
325 		immutable t2 = tolerance * 2;
326 		//assert(x + tolerance < b);
327 		//assert(x - tolerance > a);
328 
329 
330 		// check stopping criterion
331 		if (!(fabs(x - m) > t2 - (b - a) / 2))
332 			break;
333 
334 		R p = 0;
335 		R q = 0;
336 		R r = 0;
337 
338 		// fit parabola
339 		if (fabs(e) > tolerance)
340 		{
341 			immutable  xw =  x -  w;
342 			immutable fxw = fx - fw;
343 			immutable  xv =  x -  v;
344 			immutable fxv = fx - fv;
345 			immutable xwfxv = xw * fxv;
346 			immutable xvfxw = xv * fxw;
347 			p = xv * xvfxw - xw * xwfxv;
348 			q = (xvfxw - xwfxv) * 2;
349 			if (q > 0)
350 				p = -p; 
351 			else
352 				q = -q;
353 			r = e;
354 			e = d;
355 		}
356 
357 		T u;
358 		// a parabolic-interpolation step
359 		if (fabs(p) < fabs(q * r / 2) && p > q * (a - x) && p < q * (b - x))
360 		{
361 			d = p / q;
362 			u = x + d;
363 			// f must not be evaluated too close to a or b
364 			if (u - a < t2 || b - u < t2)
365 				d = x < m ? tolerance : -tolerance;
366 		}
367 		// a golden-section step
368 		else
369 		{
370 			e = (x < m ? b : a) - x;
371 			d = c * e;
372 		}
373 
374 		// f must not be evaluated too close to x
375 		u = x + (fabs(d) >= tolerance ? d : d > 0 ? tolerance : -tolerance);
376 		immutable fu = f(u);
377 		if(isNaN(fu) || fu == -T.infinity)
378 			return typeof(return)(u, fu, T.init);
379 
380 		//  update  a, b, v, w, and x
381 		if (fu <= fx)
382 		{
383 			u < x ? b : a = x;
384 			v = w; fv = fw;
385 			w = x; fw = fx;
386 			x = u; fx = fu;
387 		}
388 		else
389 		{
390 			u < x ? a : b = u;
391 			if (fu <= fw || w == x) 
392 			{
393 				v = w; fv = fw;
394 				w = u; fw = fu;
395 			} 
396 			else if (fu <= fv || v == x || v == w) 
397 			{ // do not remove this braces
398 				v = u; fv = fu;
399 			}
400 		}
401 	}
402 	return typeof(return)(x, fx, tolerance * 3);
403 }
404 
405 ///
406 unittest
407 {
408 	int i;
409 	double f(double x)
410 	{
411 		i++;
412 		return fabs(x-1);
413 	}
414 
415 	//slow
416 	auto minD = findLocalMin(&f, -double.max/2, double.max/2, double.min_normal, 2*double.epsilon);
417 	with(minD)
418 	{
419 		assert(approxEqual(x, 1));
420 		assert(approxEqual(y, 0));
421 		assert(error <= 10 * double.epsilon);
422 		//assert(minD.error == 0);
423 	}
424 }
425 
426 unittest
427 {
428 	auto ret = findLocalMin((double x) => double.init, 0.0, 1.0, double.min_normal, 2*double.epsilon);
429 	assert(!ret.x.isNaN);
430 	assert(ret.y.isNaN);
431 	assert(ret.error.isNaN);
432 }
433 
434 unittest
435 {
436 	auto ret = findLocalMin((double x) => log(x), 0.0, 1.0, double.min_normal, 2*double.epsilon);
437 	assert(ret.error < 3.00001 * ((2*double.epsilon)*fabs(ret.x)+ double.min_normal));
438 	assert(ret.x >= 0 && ret.x <= ret.error);
439 }
440 
441 
442 unittest
443 {
444 	size_t i;
445 	auto ret = findLocalMin((double x) {i++; return log(x);}, 0.0, double.max, double.min_normal, 2*double.epsilon);
446 	assert(ret.y < -18);
447 	assert(ret.error < 5e-08);
448 	assert(ret.x >= 0 && ret.x <= ret.error);
449 }
450 
451 
452 unittest
453 {
454 	size_t i;
455 	auto ret = findLocalMin((double x) {i++; return -fabs(x);}, -1.0, 1.0, double.min_normal, 2*double.epsilon);
456 	assert(ret.x.fabs.approxEqual(1));
457 	assert(ret.y.fabs.approxEqual(1));
458 	assert(ret.error.approxEqual(0));
459 }
460 
461 unittest
462 {
463 	size_t i;
464 	auto ret = findLocalMin((double x) {i++; return -fabs(x);}, -1.0, 1.0, double.min_normal, 2*double.epsilon);
465 	assert(ret.x.fabs.approxEqual(1));
466 	assert(ret.y.fabs.approxEqual(1));
467 	assert(ret.error.approxEqual(0));
468 }
469 
470 
471 version(none)
472 // check speed regressions and infinity loops
473 unittest
474 {
475 	import std.typetuple;
476 	import std.math;
477 	size_t i = 0;
478 	R f00(T, R)(T x) { i++; return 0; }
479 	R f01(T, R)(T x) { i++; return 1; }
480 	R f02(T, R)(T x) { i++; return R.min_normal/2; } //subnormal
481 	R f03(T, R)(T x) { i++; return R(PI); }
482 	R f04(T, R)(T x) { i++; return log2(cast(R)x); }
483 	R f05(T, R)(T x) { i++; return log(cast(R)x); }
484 	R f06(T, R)(T x) { i++; return exp2(cast(R)x); }
485 	R f07(T, R)(T x) { i++; return exp(cast(R)x); }
486 	R f08(T, R)(T x) { i++; return sqrt(cast(R)x); }
487 	R f09(T, R)(T x) { i++; return cbrt(cast(R)x); }
488 	R f10(T, R)(T x) { i++; return x; }
489 	R f11(T, R)(T x) { i++; return cast(R)(x)^^2; }
490 	R f12(T, R)(T x) { i++; return cast(R)(x)^^PI; }
491 	R f13(T, R)(T x) { i++; return cast(R)(x)^^(1/PI); }
492 	R f14(T, R)(T x) { i++; return sin(cast(R)x); }
493 	R f15(T, R)(T x) { i++; return cos(cast(R)x); }
494 	R f16(T, R)(T x) { i++; return sqrt(abs(cast(R)(x)^^2 - 1)); }
495 	R f17(T, R)(T x) { i++; return sqrt(abs(cast(R)(x)^^2 - 1)); }
496 	R f18(T, R)(T x) { i++; return floor(exp(cast(R)x)); } //multiminimum
497 	R f19(T, R)(T x) { i++; return floor(log(cast(R)x)); } //multiminimum
498 	R f20(T, R)(T x) { i++; return floor(cast(R)x); }      //multiminimum
499 	// vars for global checks
500 	int s1, s2;
501 	int c1, c2, c;
502 	foreach(T; TypeTuple!(
503 		float,
504 		double,
505 		real,
506 		)) // 1
507 	foreach(R; TypeTuple!(
508 		float,
509 		double,
510 		real,
511 		)) // 2
512 	{
513 		immutable ar1 = [ 
514 			&f00!(T, R),
515 			&f01!(T, R),
516 			&f02!(T, R),
517 			&f03!(T, R),
518 			&f04!(T, R),
519 			&f05!(T, R),
520 			&f06!(T, R),
521 			&f07!(T, R),
522 			&f08!(T, R),
523 			&f09!(T, R),
524 			&f10!(T, R),
525 			&f11!(T, R),
526 			&f12!(T, R),
527 			&f13!(T, R),
528 			&f14!(T, R),
529 			&f15!(T, R),
530 			&f16!(T, R),
531 			&f17!(T, R),
532 			&f18!(T, R),
533 			&f19!(T, R),
534 			&f20!(T, R),
535 		];
536 		
537 		foreach(relTol; [
538 			T.min_normal, 
539 			T.epsilon, 
540 			sqrt(T.epsilon), 
541 			T.epsilon^^0.25,
542 			]) // 3
543 		foreach(absTol; [
544 			2*T.epsilon, 
545 			sqrt(T.epsilon),
546 			]) // 4
547 		{
548 			foreach(sign; [-1, 1]) // 5
549 			foreach(rBound; [1, T.max]) // 6
550 			foreach(shift; [0, -1, 1]) // 7
551 			foreach(j, f; ar1) // 8
552 			{
553 				auto m2 = findLocalMin!T((T x) => sign * f(x-shift), shift, rBound+shift, relTol, absTol);
554 			}
555 		}
556 	}
557 }
558 
559 
560 Unqual!(CommonType!(T1, T2)) 
561 chebevReversed(T1, T2)(in T1[] c, in T2 x) 
562 {
563 	typeof(return) d = 0;
564 	typeof(return) dd = 0;
565 	foreach(e; c[0..$-1])
566 	{
567 		immutable sv = d;
568 		d = 2 * x * d - dd + e;
569 		dd = sv;
570 	}
571     return x * d - dd + c[$-1] / 2;
572 }
573 
574 
575 
576 T modifiedBesselCF2(T)(in T nu, in T x) @nogc @safe pure nothrow
577 	if(isFloatingPoint!T)
578 in {
579 	assert(fabs(nu) <= 0.5f);
580 	assert(x >= 2);
581 	assert(isFinite(x));
582 }
583 body {
584 	T bc = 2 * (1 + x);
585 	if(isInfinity(bc))
586 		return 1;
587 	T d = 1 / bc;
588 	T h = d;
589 	T delh = d;
590 	T ac = nu^^2 - 0.25f;
591 	int i = 1;
592 	do
593 	{
594 		immutable ip1 = i + 1;
595 		immutable a = ac - ip1 * i;
596 		immutable b = bc + i * 2;
597 		i = ip1;
598 		d = 1 / (b + a * d);
599 		delh = (b * d - 1) * delh;
600 		h += delh;
601 		debug assert(!isNaN(delh / h));
602 	}
603 	while(fabs(delh / h) > T.epsilon);
604 	return (nu + 0.5f + x + ac * h) / x;
605 }
606 
607 
608 
609 T[2] modifiedBesselCF2Full(T)(in T nu, in T x) @nogc @safe pure nothrow
610 	if(isFloatingPoint!T)
611 in {
612 	assert(fabs(nu) <= 0.5f);
613 	assert(x >= 2);
614 	assert(isFinite(x));
615 }
616 body {
617 	T bc = 2 * (1 + x);
618 	if(isInfinity(bc))
619 		return [nu < 0.5f ? 0 : 1.2533141373155003, 1];
620 	T d = 1 / bc;
621 	T h = d;
622 	T delh = d;
623 	T ac = nu^^2 - 0.25f;
624 	T q1 = 0;
625 	T q2 = 1;
626 	T q = -ac;
627 	T c = -ac;
628 	T s = 1 + q*delh;
629 	T dels = void;
630 	uint i = 1;
631 	T b = bc;
632 	do
633 	{
634 		immutable ip1 = i + 1;
635 		immutable a = ac - ip1 * i;
636 		c = -a * c / ip1;
637 		immutable qnew = (q1 - b * q2) / a;
638 		q1 = q2;
639 		q2 = qnew;
640 		q += c * qnew;
641 		b = bc + i * 2;
642 		d = 1 / (b + a * d);
643 		delh = (b * d - 1) * delh;
644 		dels = q * delh;
645 		h += delh;
646 		s += dels;
647 		i = ip1;
648 	}
649 	//Need only test convergence of sum since CF2 itself converges more quickly.
650 	while(fabs(dels / s) > T.epsilon);
651 
652 	enum T SQRTPI_2 = sqrt(PI / 2);
653 	return [SQRTPI_2 / s, (nu + 0.5 + x + ac * h) / x];
654 }
655 
656 
657 unittest
658 {
659 	assert(approxEqual(modifiedBesselCF2(0.4, 2.00001), 1.44212, 0.0, 1e-4));
660 	assert(approxEqual(modifiedBesselCF2(0.5, 2.00001), 1.5, 0.0, 1e-4));
661 	assert(approxEqual(modifiedBesselCF2(0.0, 2.00001), 1.22804, 0.0, 1e-4));
662 	assert(approxEqual(modifiedBesselCF2(0.4, 1000.0), 1.00100, 0.0, 1e-3));
663 	assert(approxEqual(modifiedBesselCF2(0.499, 1000.0), 1.00090, 0.0, 1e-4));
664 	assert(approxEqual(modifiedBesselCF2(0.0, 1000), 1.000499875124805092705355767307116656100795175108335495396004, 0.0, 1e-14));
665 }
666 
667 /++
668 Returns:
669 	[K(x, nu), 2 / x * K(x, nu+1)]
670 +/
671 T[2] modifiedBesselTemmeSeriesImpl(T)(in T nu, in T x) @nogc @safe pure nothrow
672 in {
673 	assert(fabs(nu) <= 0.5f);
674 	assert(x <= 2);
675 }
676 body {
677 	//TODO: recalculate c1 and c2 for different FP formats
678 	static if(is(T == float))
679 	{
680 		static immutable float[4] c1 = [
681 			-3.4706269649e-6,
682 			3.087090173086e-4,
683 			6.5165112670737e-3,
684 			-1.142022680371168e0,
685 			];
686 		static immutable float[8] c2 = [
687 			-4.9717367042e-6,
688 			1.2719271366546e-3,
689 			-7.68528408447867e-2,
690 			1.843740587300905e0,
691 			];
692 	}
693 	else
694 	{
695 		static immutable double[7] c1 = [
696 			-1.356e-13,
697 			3.67795e-11,
698 			6.9437664e-9,
699 			-3.4706269649e-6,
700 			3.087090173086e-4,
701 			6.5165112670737e-3,
702 			-1.142022680371168e0,
703 			];
704 		static immutable double[8] c2 = [
705 			-1.49e-15,
706 			-1.702e-13,
707 			2.423096e-10,
708 			-3.31261198e-8,
709 			-4.9717367042e-6,
710 			1.2719271366546e-3,
711 			-7.68528408447867e-2,
712 			1.843740587300905e0,
713 			];
714 	}
715 
716 	immutable T x2 = x / 2;
717 	immutable T pimu = cast(T) PI * nu;
718 	immutable T nu2 = nu^^2;
719 	immutable T fact = abs(pimu) < T.epsilon ? 1 : pimu / sin(pimu);
720 	T d = -log(x2);
721 	T e = nu * d;
722 	immutable T fact2 = abs(e) < T.epsilon ? 1 : sinh(e) / e;
723 	immutable T xx = 8 * nu^^2 - 1;
724 	immutable T gam1 = chebevReversed(c1, xx);
725 	immutable T gam2 = chebevReversed(c2, xx);
726 	immutable T gampl = gam2 - nu * gam1;
727 	immutable T gammi = gam2 + nu * gam1;
728 	T ff = fact * (gam1 * cosh(e) + gam2 * fact2 * d);
729 	T sum = ff;
730 	e = exp(e);
731 	T p = 0.5f * e / gampl;
732 	T q = 0.5f / (e * gammi);
733 	T c = 1;
734 	d = x2^^2;
735 	T sum1 = p;
736 	int i;
737 	T del = void;
738 	do {
739 		i++;
740 		ff = (i * ff + p + q) / (i * i - nu2);
741 		c *= d / i;
742 		p /= i - nu;
743 		q /= i + nu;
744 		del = c * ff;
745 		sum += del;
746 		immutable del1 = c * (p - i * ff);
747 		sum1 += del1;
748 	}
749 	while(abs(del) >= abs(sum) * T.epsilon);
750 	return [sum, sum1];
751 }
752 
753 /++
754 Returns:
755 	K(x, nu+1) / K(x, nu)
756 +/
757 T modifiedBesselTemmeSeries(T)(in T nu, in T x)
758 in {
759 	assert(fabs(nu) <= 0.5f);
760 	assert(x <= 2);
761 }
762 body {
763 	immutable sums = modifiedBesselTemmeSeriesImpl(nu, x);
764 	return sums[1] / sums[0] / x * 2;
765 }
766 
767 unittest
768 {
769 	assert(approxEqual(modifiedBesselTemmeSeries(0.4, 1.0), 1.87491, 0.0, 1e-4));
770 	assert(approxEqual(modifiedBesselTemmeSeries(0.499, 1.0), 1.9987, 0.0, 1e-4));
771 	assert(approxEqual(modifiedBesselTemmeSeries(0.0, 1.0), 1.429625398260401758028108023450365630080017018192662983459034, 0.0, 1e-14));
772 }
773 
774 
775 T besselKD(T)(in T nu, in T x)
776 	if(isFloatingPoint!T)
777 out(r) {
778 	import std.conv;
779 	assert(r.isNaN || r >= 1, text("x = ", x, " nu = ", nu, " r = ", r));
780 }
781 in {
782 	assert(x >= 0);
783 	assert(x < T.infinity);
784 }
785 body {
786 	version(LDC)
787 	{
788 		import ldc.intrinsics: log = llvm_log, log2 = llvm_log2, fabs = llvm_fabs;
789 	}
790 	immutable anu = fabs(nu);
791 	int nl = cast(int)floor(anu+0.5);
792 	T mu=anu-nl;
793 	//import std.stdio;
794 	////writeln(nu);
795 	assert(fabs(mu) <= 0.5f);
796 	T ret;
797 	if(x >= 2)
798 	{
799 		T r = modifiedBesselCF2(mu, x);
800 		mu *= 2;
801 		if(nl)
802 		{
803 			T d;
804 			do
805 			{
806 				d = r;
807 				mu += 2;
808 				r = mu / x + 1 / r;
809 			}
810 			while(--nl);
811 			ret = r / d;
812 		}
813 		else
814 		{
815 			ret = r * (r - mu / x);
816 		}
817 	}
818 	else
819 	{
820 		immutable sums = modifiedBesselTemmeSeriesImpl(mu, x);
821 		T r = sums[1] / sums[0];
822 		if(nl == 0)
823 		{
824 			if(mu < 0)
825 			{
826 				if(r >= mu)
827 					r = mu.nextDown;
828 			}
829 			else if(mu > 0)
830 			{
831 				if(r <= mu)
832 					r = mu.nextUp;
833 			}
834 			else
835 			{
836 				if(r == 0)
837 					return x ? 1 / (x * log(x))^^2 : T.infinity;
838 			}
839 		}
840 		//import std.stdio;
841 		//writeln("r = ", r);
842 		//writeln("sums[1] = ", sums[1]);
843 		//writeln("sums[0] = ", sums[0]);
844 		if(nl)
845 		{
846 			immutable x2_4 = x * x / 4;
847 			T d;
848 			do
849 			{
850 				d = r;
851 				mu += 1;
852 				r = mu + x2_4 / r;
853 			}
854 			while(--nl);
855 			ret = r / d;
856 		}
857 		else
858 		{
859 			//
860 			//writeln("r - mu = ", r - mu);
861 			ret = r / x * (r - mu) / x * 4;
862 		}
863 	}
864 	//import std.stdio;
865 	//writeln("ret = ", ret);
866 	//writeln("x = ", x);
867 	return fmax(ret, cast(T)1);
868 }
869 
870 unittest {
871 	assert(approxEqual(besselKD(0.46, 1.0),  2.006492004938732508413453526510952827555303123690945926246942, 0.0, 1e-14));
872 	assert(approxEqual(besselKD(0.46, 1e10),  1.000000000100000000000000000000019199999996160000000869529599, 0.0, 1e-14));
873 	assert(approxEqual(besselKD(0.46, 1e5),  1.000010000000000019199616008695062658208936100866055206637995, 0.0, 1e-14));
874 	//import std.stdio;
875 	//writeln(besselKD(0.23, 5.20964e-116 ));
876 	assert(approxEqual(besselKD(0.46, 1e-10), 5.2419685330917511351588283276691731294601340736654433005e+10, 1, 1e-14));
877 	assert(approxEqual(besselKD(0.0, 1.0),  2.043828779351212337989476332008573915738881135574432645409779, 0.0, 1e-14));
878 	assert(approxEqual(besselKD(0.0, 2.0), 1.508074700999049512999886217349628893603326842760291910336296, 0.0, 1e-14));
879 	assert(approxEqual(besselKD(0.0, 0.5), 3.210807086475177172355017867637452321623564307416114645664507, 0.0, 1e-14));
880 	assert(approxEqual(besselKD(1.0, 0.5), 2.543749846614157209231745521424755087195088446583780182048739, 0.0, 1e-14));
881 	assert(approxEqual(besselKD(1.0, 1.0), 1.888245647341297344338366806469818100073176922119421727713106, 0.0, 1e-14));
882 	assert(approxEqual(besselKD(1.0, 2.0), 1.477404884746695468820498957141015915645967793158828983150281, 0.0, 1e-14));
883 	assert(approxEqual(besselKD(0.4, 2.0), 1.502873827552600466534737445302356963995715395265386806359790, 0.0, 1e-14));
884 	assert(approxEqual(besselKD(0.4, 1.0), 2.015349430323277001160289680464116945013807398639704169522157, 0.0, 1e-14));
885 	assert(approxEqual(besselKD(0.4, 0.5), 3.071599175777718550825656123800662591905836277372864541044359, 0.0, 1e-13));
886 	assert(approxEqual(besselKD(11.1, 1.11e+10), 1.000000000090090090090090090045136443975807419926316735329998, 0.0, 1e-14));
887 	assert(approxEqual(besselKD(11.1, 1.11e-10), 1.099009900990099009900983462621096186432918126639008518272442, 0.0, 1e-14));
888 	assert(approxEqual(besselKD(2.0, 3.0), 1.296650971433360224728795947829976056477719397636727742896, 0.0, 1e-14));
889 	assert(approxEqual(besselKD(2.2, 0.8), 1.624595391806645609233071414803368115353081130470326304255669, 0.0, 1e-14));
890 	assert(approxEqual(besselKD(0.4, 3.0), 1.334349384832101337822320699631685431560403480505548447388101, 0.0, 1e-14));
891 	assert(approxEqual(besselKD(0.4, 0.8), 2.275575715445329347201695021084846610619371526255383391028726, 0.0, 1e-14));
892 	assert(approxEqual(besselKD(1.0, 1.0), 1.888245647341297344338366806469818100073176922119421727713106268163595832389436074069065151380128808, 0.0, 1e-14));
893 	assert(approxEqual(besselKD(1.0, 10.0), 1.099687904173359294358694759872440909233436542663077290833713959244496776538436835904856529604568407, 0.0, 1e-14));
894 	assert(approxEqual(besselKD(10.0, 1.0), 1.110348556190446111957216138204031855721452559868300859853180425692157659153049491662221677392988991, 0.0, 1e-14));
895 	assert(approxEqual(besselKD(10.0, 1.49011e-08), 1.11111, 0.0, 1e-4));
896 	assert(approxEqual(besselKD(1.0, 1.49011e-08), 36.2755, 0.0, 1e-4));
897 	assert(approxEqual(besselKD(1.0, 2.22044e-16), 72.3192, 0.0, 1e-4));
898 	assert(approxEqual(besselKD(1.0, 1.49166e-154), 708.628, 0.0, 1e-3));
899 	assert(approxEqual(besselKD(10.0, 1.49166e-154), 1.111111111111111, 0.0, 1e-4));
900 	assert(approxEqual(besselKD(1.1, double.min_normal), 11.0, 0.0, 1e-4));
901 	assert(isFinite(besselKD(0.1, double.epsilon)));
902 	assert(isFinite(besselKD(0, double.epsilon)));
903 }
904 
905 
906 T besselKRM(T)(in T nu, in T x)
907 	if(isFloatingPoint!T)
908 out(r){
909 	//import std.stdio;
910 	//writefln("KRM(%s, %s) = %s", nu, x, r);
911 }
912 in {
913 
914 }
915 body {
916 	version(LDC)
917 	{
918 		import ldc.intrinsics: log = llvm_log, log2 = llvm_log2, fabs = llvm_fabs;
919 	}
920 	if(nu < 0)
921 		return 1 / besselKRM(-nu, x);
922 	immutable anu = fabs(nu);
923 	int nl = cast(int)floor(anu+0.5f);
924 	T mu=anu-nl;
925 	assert(fabs(mu) <= 0.5f);
926 
927 	if(x >= 2)
928 	{
929 		T r = modifiedBesselCF2(mu, x);
930 		mu *= 2;
931 		if(nl)
932 		{
933 			T d;
934 			do
935 			{
936 				d = r;
937 				mu += 2;
938 				r = mu / x + 1 / r;
939 			}
940 			while(--nl);
941 			return sqrt(r) * sqrt(d);
942 		}
943 		else
944 		{
945 			return sqrt(r / (r - mu / x));
946 		}
947 	}
948 	else
949 	{
950 		immutable sums = modifiedBesselTemmeSeriesImpl(mu, x);
951 		T r = sums[1] / sums[0];
952 		//import std.stdio;
953 		//writeln(sums, " ", r);
954 		if(nl)
955 		{
956 			immutable x2_4 = x * x / 4;
957 			T d;
958 			do
959 			{
960 				d = r;
961 				mu += 1;
962 				r = mu + x2_4 / r;
963 			}
964 			while(--nl);
965 			//import std.stdio;
966 			//writeln("sqrt(r) = ", sqrt(r), " sqrt(d) = ", sqrt(d));
967 			return sqrt(r) * sqrt(d) * 2 / x;
968 		}
969 		else
970 		{
971 			//writeln("r = ", r, " mu = ", mu);
972 			T ret = sums[1] / (sums[1] - mu * sums[0]);
973 			if(ret < 0)
974 			{
975 				return T.infinity;
976 			}
977 			//import std.stdio;
978 			//writeln("sums[1] - mu * sums[0] = %s, ", sums[1], sums[1] - mu * sums[0]);
979 			if(ret == T.infinity)
980 			{
981 				//writeln(ret);
982 				ret = T.max;
983 				//return T.max;
984 			}
985 			return sqrt(ret);
986 		}
987 	}
988 }
989 
990 unittest {
991 	assert(approxEqual(besselKRM(0.0, 1.0),  1, 0.0, 1e-14));
992 	assert(approxEqual(besselKRM(0.0, 2.0), 1, 0.0, 1e-14));
993 	assert(approxEqual(besselKRM(0.0, 0.5), 1, 0.0, 1e-14));
994 	assert(approxEqual(besselKRM(1.0, 0.5), 2.857882088842869132027932428611809106473984497664375438969650, 0.0, 1e-14));
995 	assert(approxEqual(besselKRM(1.0, 1.0), 1.964497593920848638120029967522901757996791347548236796086390, 0.0, 1e-14));
996 	assert(approxEqual(besselKRM(1.0, 2.0), 1.492661023078886446121280337304042151124577136818374559084502, 0.0, 1e-14));
997 	assert(approxEqual(besselKRM(0.4, 2.0), 1.176363556186439775048077295541564293759652878052851708370510, 0.0, 1e-14));
998 	assert(approxEqual(besselKRM(0.4, 1.0), 1.320700844681798447461890099116285783758321865242462619205560, 0.0, 1e-14));
999 	assert(approxEqual(besselKRM(0.4, 0.5), 1.555719773577105697258998484956087203635813355802430411799783, 0.0, 1e-14));
1000 	assert(approxEqual(besselKRM(11.1, 1.11e+10), 1.000000001000000000454954954912953493935881553614516153308770, 0.0, 1e-14));
1001 	assert(approxEqual(besselKRM(11.1, 1.11e-10), 1.9077839604210010339594792869174419072661582323995475082e+11, 0.0, 1e-14));
1002 }
1003 
1004 
1005 T logBesselK(T)(in T nu, in T x)
1006 	if(isFloatingPoint!T)
1007 in {
1008 	assert(x.isFinite);
1009 	assert(x >= T.min_normal);
1010 }
1011 body {
1012 	version(LDC)
1013 	{
1014 		import ldc.intrinsics: log = llvm_log, log2 = llvm_log2, fabs = llvm_fabs;
1015 	}
1016 	immutable anu = fabs(nu);
1017 	int nl = cast(int)floor(anu+0.5f);
1018 	T mu = anu - nl;
1019 	assert(fabs(mu) <= 0.5f);
1020 	if(x >= 2)
1021 	{
1022 		immutable r2 = modifiedBesselCF2Full(mu, x);
1023 		T r = r2[1];
1024 		T ret = log(r2[0]) - log(x) / 2 - x;
1025 		if(nl)
1026 		{
1027 			mu *= 2;
1028 			T l = 1;
1029 			long exs;
1030 			do
1031 			{
1032 				int ex = void;
1033 				l *= frexp(r, ex);
1034 				exs += ex;
1035 				mu += 2;
1036 				r = mu / x + 1 / r;
1037 			}
1038 			while(--nl);
1039 			ret += cast(T)LN2 * (exs + log2(l));
1040 		}
1041 		return ret;
1042 	}
1043 	else
1044 	{
1045 		immutable sums = modifiedBesselTemmeSeriesImpl(mu, x);
1046 		T r = sums[1] / sums[0];
1047 		T ret = log(sums[0]);
1048 		if(nl)
1049 		{
1050 			ret += nl * (cast(T)LN2 - log(x));
1051 			immutable x2_4 = x * x / 4;
1052 			T l = 1;
1053 			long exs;
1054 			do
1055 			{
1056 				int ex = void;
1057 				l *= frexp(r, ex);
1058 				exs += ex;
1059 				mu += 1;
1060 				r = mu + x2_4 / r;
1061 			}
1062 			while(--nl);
1063 			ret += cast(T)LN2 * (exs + log2(l));
1064 		}
1065 		return ret;
1066 	}
1067 }
1068 
1069 unittest {
1070 	assert(approxEqual(logBesselK(0.0, 1.0),  -0.86506439890678809679875790803368568022489315035161867839839, 0.0, 1e-14));
1071 	assert(approxEqual(logBesselK(0.0, 2.0), -2.17248820497570993473841333643717923143973636448830725037508, 0.0, 1e-14));
1072 	assert(approxEqual(logBesselK(0.0, 0.5), -0.07858976986908141689523697453802973224104044591707028228710, 0.0, 1e-14));
1073 	assert(approxEqual(logBesselK(1.0, 0.5), 0.504671397304651177308416839874408827783443947120148152746119, 0.0, 1e-14));
1074 	assert(approxEqual(logBesselK(1.0, 1.0), -0.50765194821075233094791485120634298590875979858568077818450, 0.0, 1e-14));
1075 	assert(approxEqual(logBesselK(1.0, 2.0), -1.96707130256051389147686464265533209478058062247688850653003, 0.0, 1e-14));
1076 	assert(approxEqual(logBesselK(0.4, 2.0), -2.13936877477972262972321591624176676086808535490162854194273, 0.0, 1e-14));
1077 	assert(approxEqual(logBesselK(0.4, 1.0), -0.80679541168661951923202239125477303379665660825595791745329, 0.0, 1e-14));
1078 	assert(approxEqual(logBesselK(0.4, 0.5), 0.018456437585950072585426399714417863872587115447191398524780, 0.0, 1e-14));
1079 	assert(approxEqual(logBesselK(11.1, 1.11e+10), -1.110000001133931411444888363310129265544563412394720435e10, 0.0, 1e-14));
1080 	assert(approxEqual(logBesselK(11.1, 1.11e-10), 276.7693978383758755547170249282452519578463074349871817713218, 0.0, 1e-11));
1081 }
1082 
1083 
1084 T besselK(Flag!"ExponentiallyScaled" expFlag = Flag!"ExponentiallyScaled".no, T)(in T nu, in T x)
1085 	if(isFloatingPoint!T)
1086 in {
1087 	assert(x.isFinite);
1088 	assert(x >= T.min_normal);
1089 }
1090 body {
1091 	version(LDC)
1092 	{
1093 		import ldc.intrinsics: log = llvm_log, log2 = llvm_log2, fabs = llvm_fabs;
1094 	}
1095 	immutable anu = fabs(nu);
1096 	int nl = cast(int)floor(anu+0.5f);
1097 	T mu = anu - nl;
1098 	assert(fabs(mu) <= 0.5f);
1099 	T r = void, ret = void;
1100 	if(x >= 2)
1101 	{
1102 		immutable r2 = modifiedBesselCF2Full(mu, x);
1103 		r = r2[1];
1104 		static if(expFlag)
1105 			ret = r2[0] / sqrt(x);
1106 		else
1107 			ret = r2[0] / sqrt(x) * exp(-x);
1108 	}
1109 	else
1110 	{
1111 		immutable sums = modifiedBesselTemmeSeriesImpl(mu, x);
1112 		r = sums[1] / sums[0] / x * 2;
1113 		static if(expFlag)
1114 			ret = sums[0] * exp(x);
1115 		else
1116 			ret = sums[0];
1117 	}
1118 	if(nl)
1119 	{
1120 		mu *= 2;
1121 		do
1122 		{
1123 			ret *= r;
1124 			mu += 2;
1125 			r = mu / x + 1 / r;
1126 		}
1127 		while(--nl);
1128 	}
1129 	return ret;
1130 
1131 }
1132 
1133 unittest {
1134 	assert(approxEqual(besselK(0.0, 1.0),  0.421024438240708333335627379212609036136219748226660472298969, 0.0, 1e-14));
1135 	assert(approxEqual(besselK(0.0, 2.0), 0.113893872749533435652719574932481832998326624388808882892529, 0.0, 1e-14));
1136 	assert(approxEqual(besselK(0.0, 0.5), 0.924419071227665861781924167530216989538768311953529684815019, 0.0, 1e-14));
1137 	assert(approxEqual(besselK(1.0, 0.5), 1.656441120003300893696445403174091511534100759464077446055427, 0.0, 1e-14));
1138 	assert(approxEqual(besselK(1.0, 1.0), 0.601907230197234574737540001535617339261586889968106456017767, 0.0, 1e-14));
1139 	assert(approxEqual(besselK(1.0, 2.0), 0.139865881816522427284598807035411023887234584841515530384442, 0.0, 1e-14));
1140 	assert(approxEqual(besselK(0.4, 2.0), 0.117729133170423325690699234439848483526261145336868148793547, 0.0, 1e-14));
1141 	assert(approxEqual(besselK(0.4, 1.0), 0.446285939834668179310023409179745077844437039396299727961180, 0.0, 1e-14));
1142 	assert(approxEqual(besselK(0.4, 0.5), 1.018627810316608462220290727117637366662549451305627759999544, 0.0, 1e-14));
1143 	assert(approxEqual(besselK(11.1, 100000.0), 0.0, 0.0, 1e-14));
1144 	assert(approxEqual(besselK(11.1, 1/100000.0), 1.5940696949048155233993419471665743544335615887236248959e+65, 1e51, 1e-14));
1145 
1146 	assert(approxEqual(besselK!(Flag!"ExponentiallyScaled".yes)(0.4, 2.0), 0.869907169474735192472996963053995791191543506954884340734219, 0.0, 1e-14));
1147 	assert(approxEqual(besselK!(Flag!"ExponentiallyScaled".yes)(0.4, 1.0), 1.213130960549345270517674559709580335203213288805317162444177, 0.0, 1e-14));
1148 	assert(approxEqual(besselK!(Flag!"ExponentiallyScaled".yes)(0.4, 0.5), 1.679433337795687807090050796759423855788542163267174953125487, 0.0, 1e-14));
1149 	assert(approxEqual(besselK!(Flag!"ExponentiallyScaled".yes)(11.1, 100000.0), 0.003965764688216290045701642597190265433950245246337093558273, 0.0, 1e-14));
1150 
1151 	assert(approxEqual(besselK(1.0, 2.0), 0.139865881816522427284, 0.0, 1e-14));
1152 	assert(approxEqual(besselK(1.0, 20.0), 5.88305796955703817765028e-10, 0.0, 1e-14));
1153 	assert(approxEqual(besselK(1.2, 1.0), 0.701080));
1154 	assert(approxEqual(besselK(10.0, 400.0), 1.359308280937876101049800424530298700140591995078599604e-175, 0.0, 1e-14));
1155 }
1156 
1157 
1158 T besselKRS(T)(in T nu, in T x)
1159 	if(isFloatingPoint!T)
1160 in {
1161 	assert(x.isFinite);
1162 	assert(x >= T.min_normal);
1163 }
1164 body {
1165 	version(LDC)
1166 	{
1167 		import ldc.intrinsics: log = llvm_log, log2 = llvm_log2, fabs = llvm_fabs;
1168 	}
1169 	immutable anu = fabs(nu);
1170 	int nl = cast(int)floor(anu+0.5f);
1171 	T mu=anu-nl;
1172 	assert(fabs(mu) <= 0.5f);
1173 	if(x >= 2)
1174 	{
1175 		T r = modifiedBesselCF2(mu, x);
1176 		mu *= 2;
1177 		if(nl)
1178 		{
1179 			T d = void;
1180 			do
1181 			{
1182 				d = r;
1183 				mu += 2;
1184 				r = mu / x + 1 / r;
1185 			}
1186 			while(--nl);
1187 			return r + 1 / d;
1188 		}
1189 		else
1190 		{
1191 			return r + (r - mu / x);
1192 		}
1193 	}
1194 	else
1195 	{
1196 		immutable sums = modifiedBesselTemmeSeriesImpl(mu, x);
1197 		T r = sums[1] / sums[0];
1198 		immutable x_2 = x / 2;
1199 		if(nl)
1200 		{
1201 			immutable x2_4 = x_2^^2;
1202 			T d = void;
1203 			do
1204 			{
1205 				d = r;
1206 				mu += 1;
1207 				r = mu + x2_4 / r;
1208 			}
1209 			while(--nl);
1210 			return r / x_2 + x_2 / d;
1211 		}
1212 		else
1213 		{
1214 			if(fabs(r) < fabs(mu))
1215 				r = mu;
1216 			return r / x_2 + (r - mu) / x_2;
1217 		}
1218 	}
1219 }
1220 
1221 unittest {
1222 	assert(approxEqual(besselKRS(0.0, 1.0), 2.859250796520803516056216046900731260160034036385325966918068, 0.0, 1e-14));
1223 	assert(approxEqual(besselKRS(0.0, 2.0), 2.456073859637815951485344904163437808478733905321719388934076, 0.0, 1e-14));
1224 	assert(approxEqual(besselKRS(0.0, 0.5), 3.583745016864440467305949390266788044526362750672196202869812, 0.0, 1e-14));
1225 	assert(approxEqual(besselKRS(1.0, 0.5), 5.116150836953170679741316342708831083392598534819729276449587, 0.0, 1e-14));
1226 	assert(approxEqual(besselKRS(1.0, 1.0), 3.398967871187544687785354799542729509747041034806318935543498, 0.0, 1e-14));
1227 	assert(approxEqual(besselKRS(1.0, 2.0), 2.628615517527578979897586948721927750995112315346619061302174, 0.0, 1e-14));
1228 	assert(approxEqual(besselKRS(0.4, 2.0), 2.484249446052147531028619260526756105681146308342088119522102, 0.0, 1e-14));
1229 	assert(approxEqual(besselKRS(0.4, 1.0), 2.949813167184170666766713209833464015196615131065026837642303, 0.0, 1e-14));
1230 	assert(approxEqual(besselKRS(0.4, 0.5), 3.853102218097889263846807474862866521371874509444807669438352, 0.0, 1e-14));
1231 	assert(approxEqual(besselKRS(11.1, 1.11e+10), 2.000000000090090091088061033917072660444297152286161364522101, 0.0, 1e-14));
1232 	assert(approxEqual(besselKRS(11.1, 1.11e-10), 2.0000000000000000000001099009900990099009900953267052034e+11, 0.0, 1e-14));
1233 }
1234 
1235 
1236 T besselKRX(T)(in T nu, in T x)
1237 	if(isFloatingPoint!T)
1238 in {
1239 	assert(nu >= 0);
1240 	assert(x.isFinite);
1241 	assert(x >= T.min_normal);
1242 }
1243 body {
1244 	version(LDC)
1245 	{
1246 		import ldc.intrinsics: log = llvm_log, log2 = llvm_log2, fabs = llvm_fabs;
1247 	}
1248 	immutable anu = fabs(nu);
1249 	int nl = cast(int)floor(anu+0.5f);
1250 	T mu = anu - nl;
1251 	assert(fabs(mu) <= 0.5f);
1252 	if(x >= 2)
1253 	{
1254 		T r = modifiedBesselCF2(mu, x);
1255 		if(nl)
1256 		{
1257 			mu *= 2;
1258 			do
1259 			{
1260 				mu += 2;
1261 				r = mu / x + 1 / r;
1262 			}
1263 			while(--nl);
1264 		}
1265 		return r * x;
1266 	}
1267 	else
1268 	{
1269 		immutable sums = modifiedBesselTemmeSeriesImpl(mu, x);
1270 		T r = sums[1] / sums[0];
1271 		if(nl)
1272 		{
1273 			immutable x2_4 = x * x / 4;
1274 			do
1275 			{
1276 				mu += 1;
1277 				r = mu + x2_4 / r;
1278 			}
1279 			while(--nl);
1280 		}
1281 		else
1282 		{
1283 			if(fabs(r) < fabs(mu))
1284 				r = mu;
1285 		}
1286 		return r * 2;			
1287 	}
1288 }
1289 
1290 unittest {
1291 	assert(approxEqual(besselKRX(10.0, double.min_normal), 20.0, 0.0, 1e-14));
1292 	assert(approxEqual(besselKRX(0.0, 1.0), 1.429625398260401758028108023450365630080017018192662983459034, 0.0, 1e-14));
1293 	assert(approxEqual(besselKRX(0.0, 2.0), 2.456073859637815951485344904163437808478733905321719388934076, 0.0, 1e-14));
1294 	assert(approxEqual(besselKRX(0.0, 0.5), 0.895936254216110116826487347566697011131590687668049050717453, 0.0, 1e-14));
1295 	assert(approxEqual(besselKRX(1.0, 0.5), 2.279037709238292669935329085677207770848149633704932319112396, 0.0, 1e-14));
1296 	assert(approxEqual(besselKRX(1.0, 1.0), 2.699483935593772343892677399771364754873520517403159467771749, 0.0, 1e-14));
1297 	assert(approxEqual(besselKRX(1.0, 2.0), 3.628615517527578979897586948721927750995112315346619061302174, 0.0, 1e-14));
1298 	assert(approxEqual(besselKRX(0.4, 2.0), 2.884249446052147531028619260526756105681146308342088119522102, 0.0, 1e-14));
1299 	assert(approxEqual(besselKRX(0.4, 1.0), 1.874906583592085333383356604916732007598307565532513418821151, 0.0, 1e-14));
1300 	assert(approxEqual(besselKRX(0.4, 0.5), 1.363275554524472315961701868715716630342968627361201917359588, 0.0, 1e-14));
1301 	assert(approxEqual(besselKRX(11.1, 11.1), 27.05342065662651512004991741552637606461741839973809374665713, 0.0, 1e-14));
1302 	assert(approxEqual(besselKRX(11, 2.0^^30), 1.000000010710209660444967811966826255158285934025032904639974*2.0^^30, 0.0, 1e-14));
1303 	assert(approxEqual(besselKRX(11, 2.0^^30), 1.000000010710209660444967811966826255158285934025032904639974*2.0^^30, 0.0, 1e-14));
1304 	assert(approxEqual(besselKRX(11, 2.0^^40), 1.000000000010459189070438615765505792843518644341506580233109*2.0^^40, 0.0, 1e-14));
1305 	assert(approxEqual(besselKRX(11, 1e+10), 1.0000000011500000006037499999396249998267992188210915625e+10, 1, 1e-14));
1306 	assert(approxEqual(besselKRX(11.1, 1.11e+10), 1.1100000011600000005538738738239753265465849195188195573e+10, 1, 1e-14));
1307 	assert(approxEqual(besselKRX(11.1, 1.11e-10), 22.20000000000000000000060995049504950495049502906321387905301, 0.0, 1e-14));
1308 }
1309 
1310 
1311 T besselKR(T)(in T nu, in T x)
1312 	if(isFloatingPoint!T)
1313 in {
1314 }
1315 body {
1316 	version(LDC)
1317 	{
1318 		import ldc.intrinsics: log = llvm_log, log2 = llvm_log2, fabs = llvm_fabs;
1319 	}
1320 	if(nu < 0)
1321 		return 1 / besselKR(-nu-1, x);
1322 	if(x.isNaN() || nu.isNaN() || x < 0)
1323 		return T.init;
1324 	if(x < T.min_normal)
1325 		return T.infinity;
1326 	immutable anu = fabs(nu);
1327 	int nl = cast(int)floor(anu+0.5f);
1328 	T mu = anu - nl;
1329 	assert(fabs(mu) <= 0.5f);
1330 	if(x >= 2)
1331 	{
1332 		T r = modifiedBesselCF2(mu, x);
1333 		if(nl)
1334 		{
1335 			mu *= 2;
1336 			do
1337 			{
1338 				mu += 2;
1339 				r = mu / x + 1 / r;
1340 			}
1341 			while(--nl);
1342 		}
1343 		return r;
1344 	}
1345 	else
1346 	{
1347 		immutable sums = modifiedBesselTemmeSeriesImpl(mu, x);
1348 		T r = sums[1] / sums[0];
1349 		if(nl)
1350 		{
1351 			immutable x2_4 = x * x / 4;
1352 			do
1353 			{
1354 				mu += 1;
1355 				r = mu + x2_4 / r;
1356 			}
1357 			while(--nl);
1358 		}
1359 		return r * 2 / x;			
1360 	}
1361 }
1362 
1363 unittest {
1364 	assert(approxEqual(besselKR(0.0, 1.0)    , 1.429625398260401758028108023450365630080017018192662983459034, 0.0, 1e-14));
1365 	assert(approxEqual(besselKR(0.0, 2.0) * 2, 2.456073859637815951485344904163437808478733905321719388934076, 0.0, 1e-14));
1366 	assert(approxEqual(besselKR(0.0, 0.5) / 2, 0.895936254216110116826487347566697011131590687668049050717453, 0.0, 1e-14));
1367 	assert(approxEqual(besselKR(1.0, 0.5) / 2, 2.279037709238292669935329085677207770848149633704932319112396, 0.0, 1e-14));
1368 	assert(approxEqual(besselKR(1.0, 1.0)    , 2.699483935593772343892677399771364754873520517403159467771749, 0.0, 1e-14));
1369 	assert(approxEqual(besselKR(1.0, 2.0) * 2, 3.628615517527578979897586948721927750995112315346619061302174, 0.0, 1e-14));
1370 	assert(approxEqual(besselKR(0.4, 2.0) * 2, 2.884249446052147531028619260526756105681146308342088119522102, 0.0, 1e-14));
1371 	assert(approxEqual(besselKR(0.4, 1.0)    , 1.874906583592085333383356604916732007598307565532513418821151, 0.0, 1e-14));
1372 	assert(approxEqual(besselKR(0.4, 0.5) / 2, 1.363275554524472315961701868715716630342968627361201917359588, 0.0, 1e-14));
1373 	assert(approxEqual(besselKR(11.1, 1.11e+10), 1.1100000011600000005538738738239753265465849195188195573e+10 / 1.11e+10, 1, 1e-14));
1374 	assert(approxEqual(besselKR(11.1, 1.11e-10) * 1.11e-10, 22.20000000000000000000060995049504950495049502906321387905301, 0.0, 1e-14));
1375 
1376 	assert(approxEqual(besselKR(-1.0, 1.0), 1 / 1.429625398260401758028108023450365630080017018192662983459034, 0.0, 1e-14));
1377 }
1378 
1379 
1380 T besselKR(T)(in T nu, in T x, uint k)
1381 {
1382 	T l = besselKR(nu, x);
1383 	T r = l;
1384 	T mu = nu * 2;
1385 	while(k--)
1386 	{
1387 		mu += 2;
1388 		r = mu / x + 1 / r;
1389 		l *= r;
1390 	}
1391 	return l;
1392 }
1393 
1394 unittest {
1395 	assert(approxEqual(besselKR(0.0, 1.0, 0)    , 1.429625398260401758028108023450365630080017018192662983459034, 0.0, 1e-14));
1396 	assert(approxEqual(besselKR(0.0, 2.0, 0) * 2, 2.456073859637815951485344904163437808478733905321719388934076, 0.0, 1e-14));
1397 	assert(approxEqual(besselKR(0.0, 1.0, 3), 105.0590223025824984495740493132204752844809530187891270737059, 1e-10, 1e-14));
1398 	assert(approxEqual(besselKR(0.0, 2.0, 3), 19.28036929818907975742672452081718904239366952660859694467038, 1e-10, 1e-14));
1399 	assert(approxEqual(besselKR(0.0, 0.5, 3), 813.7490033728880934611898780533576089052725501344392405739625, 1e-10, 1e-14));
1400 	assert(approxEqual(besselKR(1.0, 0.5, 3), 7303.597652823473130198226747312888245046226857159388835630678, 1e-10, 1e-14));
1401 	assert(approxEqual(besselKR(1.0, 1.0, 3), 599.6947228611295581541061895533584099941981855502445314254368, 1e-10, 1e-14));
1402 	assert(approxEqual(besselKR(1.0, 2.0, 3), 67.42923276291368469846380423082891626492668473019928591953262, 1e-10, 1e-14));
1403 	assert(approxEqual(besselKR(0.4, 2.0, 3), 32.55703150637502077170415944139304552928545885327101882556329, 1e-10, 1e-14));
1404 	assert(approxEqual(besselKR(0.4, 1.0, 3), 222.9905656901318819890519502437505989113682776582595951935857, 1e-10, 1e-14));
1405 	assert(approxEqual(besselKR(0.4, 0.5, 3), 2177.389452959348919338879066729351907090043415959389603727847, 1e-10, 1e-14));
1406 }