// File: /workspace/github_c_makefile_star2_O2/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 $0x78, %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, %ebp
cmovll %r14d, %ebp
movq 0xb0(%rsp), %rcx
leal (%r14,%r13), %eax
subl %ebx, %eax
xorl %r12d, %r12d
testl %eax, %eax
cmovgl %eax, %r12d
movabsq $0x3ff0000000000000, %rax # imm = 0x3FF0000000000000
movq %rax, (%r9)
movq %rax, (%r8)
movq %rax, (%rcx)
cmpl %ebp, %r12d
jne 0x1dfa
movsd 0x1233(%rip), %xmm0     # 0x3028
jmp 0x203f
movq %r8, 0x8(%rsp)
movq %r9, 0x10(%rsp)
leaq 0x60(%rsp), %r8
movl %r15d, %edi
movl %r13d, %esi
movl %r14d, %edx
movl %ebx, %ecx
callq 0x204e
xorpd %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0x1e6c
jp 0x1e6c
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 0x1ff8
movq 0x8(%rsp), %rax
andq $0x0, (%rax)
movq 0x10(%rsp), %rax
movabsq $0x3ff0000000000000, %rcx # imm = 0x3FF0000000000000
movq %rcx, (%rax)
jmp 0x2013
movapd %xmm1, 0x20(%rsp)
leaq 0x60(%rsp), %rbx
movl %r12d, %edi
xorl %esi, %esi
xorl %edx, %edx
xorl %ecx, %ecx
movq %rbx, %r8
movsd %xmm0, 0x18(%rsp)
callq 0x204e
movsd 0x18(%rsp), %xmm1
movapd %xmm0, %xmm2
movsd 0x13e8(%rip), %xmm0     # 0x3288
mulsd %xmm1, %xmm0
movsd %xmm0, 0x38(%rsp)
movsd 0x38(%rsp), %xmm0
ucomisd %xmm2, %xmm0
movapd 0x20(%rsp), %xmm3
jbe 0x1eeb
cmpl %ebp, %r12d
jge 0x1eeb
incl %r12d
addsd %xmm2, %xmm3
movapd %xmm3, 0x20(%rsp)
movl %r12d, %edi
xorl %esi, %esi
xorl %edx, %edx
xorl %ecx, %ecx
movq %rbx, %r8
callq 0x204e
movsd 0x18(%rsp), %xmm1
movapd %xmm0, %xmm2
jmp 0x1eaa
movsd 0x139d(%rip), %xmm4     # 0x3290
mulsd %xmm1, %xmm4
movapd %xmm2, %xmm0
addsd %xmm3, %xmm0
movsd %xmm2, 0x48(%rsp)
movsd %xmm4, 0x40(%rsp)
cmpnltsd %xmm4, %xmm2
movapd %xmm2, %xmm1
andnpd %xmm0, %xmm1
andpd %xmm3, %xmm2
orpd %xmm1, %xmm2
movapd %xmm2, 0x50(%rsp)
xorpd %xmm0, %xmm0
movsd %xmm0, 0x20(%rsp)
leaq 0x60(%rsp), %rbx
movl %ebp, %edi
xorl %esi, %esi
xorl %edx, %edx
xorl %ecx, %ecx
movq %rbx, %r8
callq 0x204e
movsd 0x38(%rsp), %xmm1
ucomisd %xmm0, %xmm1
jbe 0x1f69
testl %ebp, %ebp
jle 0x1f69
decl %ebp
movsd 0x20(%rsp), %xmm1
addsd %xmm0, %xmm1
movsd %xmm1, 0x20(%rsp)
jmp 0x1f35
xorl %ecx, %ecx
movsd 0x40(%rsp), %xmm1
ucomisd 0x48(%rsp), %xmm1
setbe %cl
xorl %eax, %eax
ucomisd %xmm0, %xmm1
setbe %dl
movsd 0x20(%rsp), %xmm5
jbe 0x1f8f
addsd %xmm0, %xmm5
movq 0x10(%rsp), %rsi
movq 0x8(%rsp), %rdi
movapd 0x50(%rsp), %xmm4
movb %dl, %al
movapd %xmm4, %xmm1
addsd %xmm5, %xmm1
movsd 0x1077(%rip), %xmm3     # 0x3028
movapd %xmm3, %xmm2
minsd %xmm1, %xmm2
addl %r15d, %ecx
subl %ecx, %r12d
movl %r12d, %ecx
negl %ecx
cmovsl %r12d, %ecx
movq 0xb0(%rsp), %rdx
movsd %xmm2, (%rdx)
subl %r15d, %eax
addl %ebp, %eax
movl %eax, %edx
negl %edx
cmovsl %eax, %edx
cmpl %edx, %ecx
jb 0x2025
subsd %xmm5, %xmm3
movsd 0x18(%rsp), %xmm0
movapd %xmm0, %xmm4
addsd %xmm3, %xmm4
jmp 0x2037
movq 0x8(%rsp), %rax
movabsq $0x3ff0000000000000, %rcx # imm = 0x3FF0000000000000
movq %rcx, (%rax)
movq 0x10(%rsp), %rax
andq $0x0, (%rax)
movq 0xb0(%rsp), %rax
andq $0x0, (%rax)
xorpd %xmm0, %xmm0
jmp 0x203f
subsd %xmm4, %xmm3
movsd 0x18(%rsp), %xmm0
movapd %xmm0, %xmm5
addsd %xmm3, %xmm5
movsd %xmm4, (%rdi)
movsd %xmm5, (%rsi)
addq $0x78, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq