// File: /workspace/github_c_makefile_star2_O1/samtools[P]htslib/kfunc.c
// Function: kt_fisher_exact
double kt_fisher_exact(int n11, int n12, int n21, int n22, double *_left, double *_right, double *two)
{
    int i, j, max, min;
    double p, q, left, right;
    hgacc_t aux;
    int n1_, n_1, n;

    n1_ = n11 + n12; n_1 = n11 + n21; n = n11 + n12 + n21 + n22; // calculate n1_, n_1 and n
    max = (n_1 < n1_) ? n_1 : n1_; // max n11, for right tail
    min = n1_ + n_1 - n;    // not sure why n11-n22 is used instead of min(n_1,n1_)
    if (min < 0) min = 0; // min n11, for left tail
    *two = *_left = *_right = 1.;
    if (min == max) return 1.; // no need to do test
    q = hypergeo_acc(n11, n1_, n_1, n, &aux); // the probability of the current table

    if (q == 0.0) {
        /*
          If here, the calculated probablility is so small it can't be stored
          in a double, which is possible when the table contains fairly large
          numbers.  If this happens, most of the calculation can be skipped
          as 'left', 'right' and '*two' will be (to a good approximation) 0.0.
          The returned values '*_left' and '*_right' depend on which side
          of the hypergeometric PDF 'n11' sits.  This can be found by
          comparing with the mode of the distribution, the formula for which
          can be found at:
          https://en.wikipedia.org/wiki/Hypergeometric_distribution
          Note that in the comparison we multiply through by the denominator
          of the mode (n + 2) to avoid a division.
        */
        if ((int64_t) n11 * ((int64_t) n + 2) < ((int64_t) n_1 + 1) * ((int64_t) n1_ + 1)) {
            // Peak to right of n11, so probability will be lower for all
            // of the region from min to n11 and higher for at least some
            // of the region from n11 to max; hence abs(i-n11) will be 0,
            // abs(j-n11) will be > 0 and:
            *_left = 0.0; *_right = 1.0; *two = 0.0;
            return 0.0;
        } else {
            // Peak to left of n11, so probability will be lower for all
            // of the region from n11 to max and higher for at least some
            // of the region from min to n11; hence abs(i-n11) will be > 0,
            // abs(j-n11) will be 0 and:
            *_left = 1.0; *_right = 0.0; *two = 0.0;
            return 0.0;
        }
    }

    // left tail
    p = hypergeo_acc(min, 0, 0, 0, &aux);
    for (left = 0., i = min + 1; p < 0.99999999 * q && i<=max; ++i) // loop until underflow
        left += p, p = hypergeo_acc(i, 0, 0, 0, &aux);
    --i;
    if (p < 1.00000001 * q) left += p;
    else --i;
    // right tail
    p = hypergeo_acc(max, 0, 0, 0, &aux);
    for (right = 0., j = max - 1; p < 0.99999999 * q && j>=0; --j) // loop until underflow
        right += p, p = hypergeo_acc(j, 0, 0, 0, &aux);
    ++j;
    if (p < 1.00000001 * q) right += p;
    else ++j;
    // two-tail
    *two = left + right;
    if (*two > 1.) *two = 1.;
    // adjust left and right
    if (abs(i - n11) < abs(j - n11)) right = 1. - left + q;
    else left = 1.0 - right + q;
    *_left = left; *_right = right;
    return q;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x58, %rsp
movl %ecx, %ebx
movl %esi, %r13d
movl %edi, %r15d
addl %edi, %r13d
leal (%rdx,%r15), %r14d
addl %edx, %ebx
addl %r13d, %ebx
cmpl %r13d, %r14d
movl %r13d, %r12d
cmovll %r14d, %r12d
movq 0x90(%rsp), %rcx
leal (%r14,%r13), %eax
subl %ebx, %eax
xorl %ebp, %ebp
testl %eax, %eax
cmovgl %eax, %ebp
movabsq $0x3ff0000000000000, %rax # imm = 0x3FF0000000000000
movq %rax, (%r9)
movq %rax, (%r8)
movq %rax, (%rcx)
cmpl %r12d, %ebp
jne 0x1f1c
movsd 0x1111(%rip), %xmm0     # 0x3028
jmp 0x2184
movq %r8, 0x18(%rsp)
movq %r9, 0x20(%rsp)
leaq 0x40(%rsp), %r8
movl %r15d, %edi
movl %r13d, %esi
movl %r14d, %edx
movl %ebx, %ecx
callq 0x2193
xorpd %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0x1f8f
jp 0x1f8f
movslq %r15d, %rax
movslq %ebx, %rcx
addq $0x2, %rcx
imulq %rax, %rcx
movslq %r14d, %rax
incq %rax
movslq %r13d, %rdx
incq %rdx
imulq %rax, %rdx
cmpq %rdx, %rcx
jge 0x200a
xorl %eax, %eax
movq 0x18(%rsp), %rcx
movq %rax, (%rcx)
movq 0x20(%rsp), %rcx
movabsq $0x3ff0000000000000, %rdx # imm = 0x3FF0000000000000
movq %rdx, (%rcx)
jmp 0x2026
leaq 0x40(%rsp), %r8
movl %ebp, %edi
xorl %esi, %esi
xorl %edx, %edx
xorl %ecx, %ecx
movsd %xmm0, 0x10(%rsp)
callq 0x2193
movsd 0x1291(%rip), %xmm1     # 0x3240
mulsd 0x10(%rsp), %xmm1
movsd %xmm1, 0x28(%rsp)
ucomisd %xmm0, %xmm1
setbe %al
cmpl %r12d, %ebp
setge %cl
xorpd %xmm1, %xmm1
orb %al, %cl
jne 0x2040
leaq 0x40(%rsp), %rbx
addsd %xmm0, %xmm1
movsd %xmm1, 0x8(%rsp)
incl %ebp
movl %ebp, %edi
xorl %esi, %esi
xorl %edx, %edx
xorl %ecx, %ecx
movq %rbx, %r8
callq 0x2193
movsd 0x28(%rsp), %xmm1
ucomisd %xmm0, %xmm1
jbe 0x203a
cmpl %r12d, %ebp
movsd 0x8(%rsp), %xmm1
jl 0x1fd5
jmp 0x2040
movq 0x18(%rsp), %rax
movabsq $0x3ff0000000000000, %rcx # imm = 0x3FF0000000000000
movq %rcx, (%rax)
xorl %eax, %eax
movq 0x20(%rsp), %rcx
movq %rax, (%rcx)
movq 0x90(%rsp), %rcx
movq %rax, (%rcx)
xorpd %xmm0, %xmm0
jmp 0x2184
movsd 0x8(%rsp), %xmm1
movsd 0x1200(%rip), %xmm2     # 0x3248
mulsd 0x10(%rsp), %xmm2
xorl %r14d, %r14d
movsd %xmm2, 0x38(%rsp)
ucomisd %xmm0, %xmm2
setbe %al
jbe 0x2064
addsd %xmm0, %xmm1
movsd %xmm1, 0x8(%rsp)
movb %al, %r14b
leaq 0x40(%rsp), %r8
movl %r12d, %edi
xorl %esi, %esi
xorl %edx, %edx
xorl %ecx, %ecx
callq 0x2193
movsd 0x28(%rsp), %xmm1
ucomisd %xmm0, %xmm1
setbe %al
testl %r12d, %r12d
setle %cl
xorpd %xmm5, %xmm5
orb %al, %cl
jne 0x20dd
leaq 0x40(%rsp), %rbx
addsd %xmm0, %xmm5
movsd %xmm5, 0x30(%rsp)
leal -0x1(%r12), %r13d
movl %r13d, %edi
xorl %esi, %esi
xorl %edx, %edx
xorl %ecx, %ecx
movq %rbx, %r8
callq 0x2193
movsd 0x28(%rsp), %xmm1
ucomisd %xmm0, %xmm1
jbe 0x20e2
cmpl $0x1, %r12d
movl %r13d, %r12d
movsd 0x30(%rsp), %xmm5
jg 0x20a0
jmp 0x20e8
movl %r12d, %r13d
jmp 0x20e8
movsd 0x30(%rsp), %xmm5
negl %r14d
xorl %eax, %eax
movsd 0x38(%rsp), %xmm1
ucomisd %xmm0, %xmm1
setbe %cl
jbe 0x2100
addsd %xmm0, %xmm5
movq 0x20(%rsp), %rsi
movq 0x18(%rsp), %rdi
movsd 0x8(%rsp), %xmm4
movb %cl, %al
movapd %xmm4, %xmm1
addsd %xmm5, %xmm1
movsd 0xf06(%rip), %xmm3      # 0x3028
movapd %xmm3, %xmm2
minsd %xmm1, %xmm2
subl %r15d, %r14d
addl %ebp, %r14d
movl %r14d, %ecx
negl %ecx
cmovsl %r14d, %ecx
movq 0x90(%rsp), %rdx
movsd %xmm2, (%rdx)
subl %r15d, %eax
addl %r13d, %eax
movl %eax, %edx
negl %edx
cmovsl %eax, %edx
cmpl %edx, %ecx
jb 0x216a
subsd %xmm5, %xmm3
movsd 0x10(%rsp), %xmm0
addsd %xmm0, %xmm3
movapd %xmm3, %xmm4
jmp 0x217c
subsd %xmm4, %xmm3
movsd 0x10(%rsp), %xmm0
addsd %xmm0, %xmm3
movapd %xmm3, %xmm5
movsd %xmm4, (%rdi)
movsd %xmm5, (%rsi)
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq