// File: /workspace/github_cpp_makefile_star2_O1/tonymugen[P]sampleSNPs/random.cpp
// Function: sampFiles::RanDraw::vitter(double const&, double const&)
volatile uint64_t RanDraw::vitter(const double &n, const double &N){
	// The notation follows Vitter's (1987) as closely as possible
	// Note that my runif() is on [0,1] (Vitter assumes (0,1)), so I have to sometimes adjust accordingly
	uint64_t S = 0;
	double alphaInv = 13.0;
	if (n >= N/alphaInv) { // if the threshold is not satisfied, use Vitter's A algorithm
		return this->vitterA(n, N);
	} else if (n == 1){ // trivial case
		do {
			S = static_cast<uint64_t>(floor(N * this->runif()));
			
		} while (S == static_cast<uint64_t>(N)); // s == N would be a problem because it would overshoot the end of the array/file (in base-0 space); effectively sampling [0,1) uniform to prevent this
		return S;

	}
	
	// if we pass all thresholds, we use Vitter's rejection scheme
	double nInv     = 1.0/n;
	double nMin1inv = 1.0/(n - 1.0);
	double qu1db    = 1.0 + N - n;
	uint64_t qu1    = static_cast<uint64_t>(qu1db);
	double Vprime;
	double X;
	double Sdb;
	double U;
	double y1;
	
	// outer loop in Vitter (1987) A2
	while (1) {
		
		unsigned int d2tst = 0;
		do {  // step D2; generate U and X
			Vprime = pow(this->runif(), nInv);
			X      = N * (1.0 - Vprime);
			S      = floor(X);
			d2tst++;
		} while (S >= qu1);
		
		U      = this->runif();
		Sdb    = static_cast<double>(S);
		y1     = pow(U*N/qu1db, nMin1inv);
		Vprime = y1 * (1.0 - X/N) * (qu1db/(qu1db - Sdb));
		if (Vprime < 1.0) { // Step D3: accept test 2.8 (Vitter 1987)
			break;
		}
		// moving on to Step D4
		double y2  = 1.0;
		double top = N - 1.0;
		double bottom;
		double limit;
		if (Sdb < n - 1.0) {
			bottom = N - n;
			limit  = N - Sdb;
		} else {
			bottom = N - Sdb - 1.0;
			limit  = qu1db;
		}
		
		// calculate f(|_X_|)
		for (double t = N - 1.0; t >= limit; t--) {
			y2 = y2 * top/bottom;
			top--;
			bottom--;
		}
		if (N/(N - X) >= y1 * pow(y2, nMin1inv)) { // Accept D4 condition
			break;
		}
		// reject everything, go back to the start
	}
	return S;
}

// Assembly:
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x40, %rsp
movq %rdx, %rbx
movq %rsi, %r15
movq %rdi, %r14
movsd (%rsi), %xmm0
movsd (%rdx), %xmm2
movapd %xmm2, %xmm1
divsd 0x1952(%rip), %xmm1     # 0x19140
ucomisd %xmm1, %xmm0
jae 0x178a1
ucomisd 0xce0(%rip), %xmm0      # 0x184e0
jne 0x178bc
jp 0x178bc
movsd (%rbx), %xmm0
movsd %xmm0, (%rsp)
movq (%r14), %rdi
movq (%rdi), %rax
callq *0x10(%rax)
movq %rax, %xmm1
punpckldq 0xc75(%rip), %xmm1 # xmm1 = xmm1[0],mem[0],xmm1[1],mem[1]
subpd 0xc7d(%rip), %xmm1      # 0x184b0
movapd %xmm1, %xmm0
unpckhpd %xmm1, %xmm0            # xmm0 = xmm0[1],xmm1[1]
addsd %xmm1, %xmm0
mulsd 0x18e1(%rip), %xmm0     # 0x19128
mulsd (%rsp), %xmm0
callq 0x4490
cvttsd2si %xmm0, %rax
movq %rax, %rcx
sarq $0x3f, %rcx
movsd 0x18d3(%rip), %xmm1     # 0x19138
subsd %xmm1, %xmm0
cvttsd2si %xmm0, %r12
andq %rcx, %r12
orq %rax, %r12
movsd (%rbx), %xmm0
cvttsd2si %xmm0, %rax
subsd %xmm1, %xmm0
cvttsd2si %xmm0, %rcx
movq %rax, %rdx
sarq $0x3f, %rdx
andq %rcx, %rdx
orq %rax, %rdx
cmpq %rdx, %r12
je 0x1780c
jmp 0x17b31
movq %r14, %rdi
movq %r15, %rsi
movq %rbx, %rdx
addq $0x40, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
jmp 0x1764c
movsd 0xc1c(%rip), %xmm4      # 0x184e0
movapd %xmm4, %xmm1
divsd %xmm0, %xmm1
movsd %xmm1, 0x18(%rsp)
movsd 0x1856(%rip), %xmm1     # 0x19130
addsd %xmm0, %xmm1
movapd %xmm4, %xmm3
addsd %xmm4, %xmm2
subsd %xmm0, %xmm2
cvttsd2si %xmm2, %rax
divsd %xmm1, %xmm3
movsd %xmm3, 0x8(%rsp)
movq %rax, %rcx
sarq $0x3f, %rcx
movapd %xmm2, 0x20(%rsp)
movapd %xmm2, %xmm0
subsd 0x1826(%rip), %xmm0     # 0x19138
cvttsd2si %xmm0, %r13
andq %rcx, %r13
orq %rax, %r13
movq (%r14), %rdi
movq (%rdi), %rax
callq *0x10(%rax)
movq %rax, %xmm1
punpckldq 0xb6d(%rip), %xmm1 # xmm1 = xmm1[0],mem[0],xmm1[1],mem[1]
subpd 0xb75(%rip), %xmm1      # 0x184b0
movapd %xmm1, %xmm0
unpckhpd %xmm1, %xmm0            # xmm0 = xmm0[1],xmm1[1]
addsd %xmm1, %xmm0
mulsd 0x17d9(%rip), %xmm0     # 0x19128
movsd 0x18(%rsp), %xmm1
callq 0x44d0
movsd 0xb7e(%rip), %xmm1      # 0x184e0
subsd %xmm0, %xmm1
mulsd (%rbx), %xmm1
movsd %xmm1, (%rsp)
movapd %xmm1, %xmm0
callq 0x4490
cvttsd2si %xmm0, %rax
movq %rax, %rcx
subsd 0x17b0(%rip), %xmm0     # 0x19138
cvttsd2si %xmm0, %r12
sarq $0x3f, %rcx
andq %rcx, %r12
orq %rax, %r12
cmpq %r13, %r12
jae 0x1791d
movq (%r14), %rdi
movq (%rdi), %rax
callq *0x10(%rax)
movq %rax, %xmm1
movq 0xaee(%rip), %xmm3      # 0x184a0
punpckldq %xmm3, %xmm1    # xmm1 = xmm1[0],xmm3[0],xmm1[1],xmm3[1]
movapd 0xaf2(%rip), %xmm2      # 0x184b0
subpd %xmm2, %xmm1
movapd %xmm1, %xmm0
unpckhpd %xmm1, %xmm0            # xmm0 = xmm0[1],xmm1[1]
addsd %xmm1, %xmm0
mulsd 0x1752(%rip), %xmm0     # 0x19128
movq %r12, %xmm1
punpckldq %xmm3, %xmm1    # xmm1 = xmm1[0],xmm3[0],xmm1[1],xmm3[1]
subpd %xmm2, %xmm1
movapd %xmm1, %xmm2
unpckhpd %xmm1, %xmm2            # xmm2 = xmm2[1],xmm1[1]
addsd %xmm1, %xmm2
movapd %xmm2, 0x30(%rsp)
mulsd (%rbx), %xmm0
divsd 0x20(%rsp), %xmm0
movsd 0x8(%rsp), %xmm1
callq 0x44d0
movapd 0x30(%rsp), %xmm10
movapd 0x20(%rsp), %xmm5
movsd (%rbx), %xmm9
movsd (%rsp), %xmm8
movapd %xmm8, %xmm2
divsd %xmm9, %xmm2
movsd 0xaac(%rip), %xmm3      # 0x184e0
movapd %xmm3, %xmm1
subsd %xmm2, %xmm1
mulsd %xmm0, %xmm1
movapd %xmm5, %xmm4
subsd %xmm10, %xmm4
movapd %xmm5, %xmm2
divsd %xmm4, %xmm2
mulsd %xmm1, %xmm2
ucomisd %xmm2, %xmm3
ja 0x17b31
movapd %xmm3, %xmm6
movsd %xmm0, 0x10(%rsp)
movsd (%r15), %xmm4
movapd %xmm4, %xmm0
movsd 0x16b6(%rip), %xmm7     # 0x19130
addsd %xmm7, %xmm0
movapd %xmm9, %xmm3
subsd %xmm10, %xmm3
cmpltsd %xmm0, %xmm10
movapd %xmm10, %xmm0
andpd %xmm3, %xmm0
movapd %xmm10, %xmm1
andnpd %xmm5, %xmm1
orpd %xmm0, %xmm1
movapd %xmm9, %xmm2
addsd %xmm7, %xmm2
ucomisd %xmm1, %xmm2
movapd %xmm6, %xmm0
jb 0x17af8
movapd %xmm9, %xmm0
subsd %xmm4, %xmm0
addsd %xmm7, %xmm3
andpd %xmm10, %xmm0
andnpd %xmm3, %xmm10
orpd %xmm0, %xmm10
movapd %xmm9, %xmm3
movapd %xmm6, %xmm0
addsd %xmm7, %xmm3
mulsd %xmm3, %xmm0
divsd %xmm10, %xmm0
addsd %xmm7, %xmm10
addsd %xmm7, %xmm2
ucomisd %xmm1, %xmm2
jae 0x17adc
movapd %xmm9, %xmm1
subsd %xmm8, %xmm1
divsd %xmm1, %xmm9
movsd %xmm9, (%rsp)
movsd 0x8(%rsp), %xmm1
callq 0x44d0
movsd 0x10(%rsp), %xmm1
mulsd %xmm0, %xmm1
movsd (%rsp), %xmm0
ucomisd %xmm1, %xmm0
jb 0x1791d
movq %r12, %rax
addq $0x40, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
retq