// File: bobverity[P]MavericK/misc.cpp
// Function: approx_lgamma(double)
double approx_lgamma(double x) {

	if (x <= 0.0)
	{
		std::stringstream os;
        os << "Invalid input argument " << x <<  ". Argument must be positive.";
        throw std::invalid_argument( os.str() );
	}
    
    if (x < 12.0)
    {
        return log(fabs(approx_gamma(x)));
    }
    
	// Abramowitz and Stegun 6.1.41
    // Asymptotic series should be good to at least 11 or 12 figures
    // For error analysis, see Whittiker and Watson
    // A Course in Modern Analysis (1927), page 252
    
    static const double c[8] =
    {
        1.0/12.0,
		-1.0/360.0,
		1.0/1260.0,
		-1.0/1680.0,
		1.0/1188.0,
		-691.0/360360.0,
		1.0/156.0,
		-3617.0/122400.0
    };
    double z = 1.0/(x*x);
    double sum = c[7];
    for (int i=6; i >= 0; i--)
    {
        sum *= z;
        sum += c[i];
    }
    double series = sum/x;
    
    static const double halfLogTwoPi = 0.91893853320467274178032973640562;
    double loggamma = (x - 0.5)*log(x) - x + halfLogTwoPi + series;
	return loggamma;
}

// Assembly:
subq $0x218, %rsp            # imm = 0x218
movsd %xmm0, 0x208(%rsp)
xorps %xmm0, %xmm0
ucomisd 0x208(%rsp), %xmm0
jb 0x36cf1
leaq 0x80(%rsp), %rdi
callq 0x42f0
leaq 0x90(%rsp), %rdi
leaq 0x260a5(%rip), %rsi     # 0x5cca3
callq 0x4430
movq %rax, 0x18(%rsp)
jmp 0x36c0a
movq 0x18(%rsp), %rdi
movsd 0x208(%rsp), %xmm0
callq 0x4790
movq %rax, 0x10(%rsp)
jmp 0x36c24
movq 0x10(%rsp), %rdi
leaq 0x2608b(%rip), %rsi     # 0x5ccbb
callq 0x4430
jmp 0x36c37
movb $0x1, 0x4f(%rsp)
movl $0x10, %edi
callq 0x41d0
movq %rax, 0x8(%rsp)
leaq 0x50(%rsp), %rdi
leaq 0x80(%rsp), %rsi
callq 0x4420
jmp 0x36c5f
movq 0x8(%rsp), %rdi
leaq 0x50(%rsp), %rsi
callq 0x4710
jmp 0x36c70
movq 0x8(%rsp), %rdi
movb $0x0, 0x4f(%rsp)
movq 0x3634f(%rip), %rsi     # 0x6cfd0
movq 0x36338(%rip), %rdx     # 0x6cfc0
callq 0x46e0
jmp 0x36e5c
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x78(%rsp)
movl %eax, 0x74(%rsp)
jmp 0x36cdf
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x78(%rsp)
movl %eax, 0x74(%rsp)
jmp 0x36cca
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x78(%rsp)
movl %eax, 0x74(%rsp)
leaq 0x50(%rsp), %rdi
callq 0x4270
testb $0x1, 0x4f(%rsp)
jne 0x36cd3
jmp 0x36cdd
movq 0x8(%rsp), %rdi
callq 0x4310
jmp 0x36cdf
leaq 0x80(%rsp), %rdi
callq 0x4330
jmp 0x36e52
movsd 0x25e3f(%rip), %xmm0    # 0x5cb38
ucomisd 0x208(%rsp), %xmm0
jbe 0x36d30
movsd 0x208(%rsp), %xmm0
callq 0x367d0
movaps 0x25db7(%rip), %xmm1    # 0x5cad0
pand %xmm1, %xmm0
callq 0x4390
movsd %xmm0, 0x210(%rsp)
jmp 0x36e41
movsd 0x208(%rsp), %xmm1
mulsd 0x208(%rsp), %xmm1
movsd 0x254b6(%rip), %xmm0    # 0x5c200
divsd %xmm1, %xmm0
movsd %xmm0, 0x40(%rsp)
movsd 0x2606c(%rip), %xmm0    # 0x5cdc8
movsd %xmm0, 0x38(%rsp)
movl $0x6, 0x34(%rsp)
cmpl $0x0, 0x34(%rsp)
jl 0x36dad
movsd 0x40(%rsp), %xmm0
mulsd 0x38(%rsp), %xmm0
movsd %xmm0, 0x38(%rsp)
movslq 0x34(%rsp), %rcx
leaq 0x26001(%rip), %rax     # 0x5cd90
movsd (%rax,%rcx,8), %xmm0
addsd 0x38(%rsp), %xmm0
movsd %xmm0, 0x38(%rsp)
movl 0x34(%rsp), %eax
addl $-0x1, %eax
movl %eax, 0x34(%rsp)
jmp 0x36d6a
movsd 0x38(%rsp), %xmm0
divsd 0x208(%rsp), %xmm0
movsd %xmm0, 0x28(%rsp)
movsd 0x208(%rsp), %xmm0
movsd 0x25465(%rip), %xmm1    # 0x5c238
subsd %xmm1, %xmm0
movsd %xmm0, (%rsp)
movsd 0x208(%rsp), %xmm0
callq 0x4390
movaps %xmm0, %xmm2
movsd (%rsp), %xmm0
movsd 0x208(%rsp), %xmm1
movq %xmm1, %rax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
xorq %rcx, %rax
movq %rax, %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd 0x25d2e(%rip), %xmm1    # 0x5cb50
addsd %xmm1, %xmm0
addsd 0x28(%rsp), %xmm0
movsd %xmm0, 0x20(%rsp)
movsd 0x20(%rsp), %xmm0
movsd %xmm0, 0x210(%rsp)
movsd 0x210(%rsp), %xmm0
addq $0x218, %rsp            # imm = 0x218
retq
movq 0x78(%rsp), %rdi
callq 0x4730
nopl (%rax)