// File: /workspace/github_cpp_makefile_star2_O2/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), %xmm1
movapd %xmm1, (%rsp)
divsd 0x2239(%rip), %xmm1     # 0x15140
ucomisd %xmm1, %xmm0
jae 0x12fba
ucomisd 0x15c7(%rip), %xmm0     # 0x144e0
jne 0x12fd5
jp 0x12fd5
movq (%r14), %rdi
movq (%rdi), %rax
callq *0x10(%rax)
movq %rax, %xmm1
punpckldq 0x1565(%rip), %xmm1 # xmm1 = xmm1[0],mem[0],xmm1[1],mem[1]
subpd 0x156d(%rip), %xmm1     # 0x144b0
movapd %xmm1, %xmm0
unpckhpd %xmm1, %xmm0            # xmm0 = xmm0[1],xmm1[1]
addsd %xmm1, %xmm0
mulsd 0x21d1(%rip), %xmm0     # 0x15128
mulsd (%rsp), %xmm0
callq 0x4490
cvttsd2si %xmm0, %rax
movq %rax, %rcx
sarq $0x3f, %rcx
movsd 0x21c3(%rip), %xmm2     # 0x15138
subsd %xmm2, %xmm0
cvttsd2si %xmm0, %r12
andq %rcx, %r12
movsd (%rbx), %xmm1
movapd %xmm1, %xmm0
subsd %xmm2, %xmm0
cvttsd2si %xmm0, %rcx
orq %rax, %r12
movapd %xmm1, (%rsp)
cvttsd2si %xmm1, %rax
movq %rax, %rdx
sarq $0x3f, %rdx
andq %rcx, %rdx
orq %rax, %rdx
cmpq %rdx, %r12
je 0x12f25
jmp 0x13237
movq %r14, %rdi
movq %r15, %rsi
movq %rbx, %rdx
addq $0x40, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
jmp 0x12d76
movsd 0x1503(%rip), %xmm4     # 0x144e0
movapd %xmm4, %xmm1
divsd %xmm0, %xmm1
movsd %xmm1, 0x28(%rsp)
movsd 0x213d(%rip), %xmm1     # 0x15130
addsd %xmm0, %xmm1
movapd %xmm4, %xmm3
movapd (%rsp), %xmm2
addsd %xmm4, %xmm2
subsd %xmm0, %xmm2
cvttsd2si %xmm2, %rax
divsd %xmm1, %xmm3
movsd %xmm3, 0x18(%rsp)
movq %rax, %rcx
sarq $0x3f, %rcx
movapd %xmm2, (%rsp)
movapd %xmm2, %xmm0
subsd 0x2109(%rip), %xmm0     # 0x15138
cvttsd2si %xmm0, %r13
andq %rcx, %r13
orq %rax, %r13
movq (%r14), %rdi
movq (%rdi), %rax
callq *0x10(%rax)
movq %rax, %xmm1
punpckldq 0x1450(%rip), %xmm1 # xmm1 = xmm1[0],mem[0],xmm1[1],mem[1]
subpd 0x1458(%rip), %xmm1     # 0x144b0
movapd %xmm1, %xmm0
unpckhpd %xmm1, %xmm0            # xmm0 = xmm0[1],xmm1[1]
addsd %xmm1, %xmm0
mulsd 0x20bc(%rip), %xmm0     # 0x15128
movsd 0x28(%rsp), %xmm1
callq 0x44c0
movsd 0x1461(%rip), %xmm1     # 0x144e0
subsd %xmm0, %xmm1
mulsd (%rbx), %xmm1
movsd %xmm1, 0x10(%rsp)
movapd %xmm1, %xmm0
callq 0x4490
cvttsd2si %xmm0, %rax
movq %rax, %rcx
subsd 0x2092(%rip), %xmm0     # 0x15138
cvttsd2si %xmm0, %r12
sarq $0x3f, %rcx
andq %rcx, %r12
orq %rax, %r12
cmpq %r13, %r12
jae 0x1303a
movq (%r14), %rdi
movq (%rdi), %rax
callq *0x10(%rax)
movq %rax, %xmm1
movq 0x13d0(%rip), %xmm3     # 0x144a0
punpckldq %xmm3, %xmm1    # xmm1 = xmm1[0],xmm3[0],xmm1[1],xmm3[1]
movapd 0x13d4(%rip), %xmm2     # 0x144b0
subpd %xmm2, %xmm1
movapd %xmm1, %xmm0
unpckhpd %xmm1, %xmm0            # xmm0 = xmm0[1],xmm1[1]
addsd %xmm1, %xmm0
mulsd 0x2034(%rip), %xmm0     # 0x15128
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 (%rsp), %xmm0
movsd 0x18(%rsp), %xmm1
callq 0x44c0
movapd 0x30(%rsp), %xmm8
movsd (%rbx), %xmm9
movsd 0x10(%rsp), %xmm7
movapd %xmm7, %xmm2
divsd %xmm9, %xmm2
movsd 0x1396(%rip), %xmm3     # 0x144e0
movapd %xmm3, %xmm1
subsd %xmm2, %xmm1
mulsd %xmm0, %xmm1
movapd (%rsp), %xmm2
movapd %xmm2, %xmm4
subsd %xmm8, %xmm4
divsd %xmm4, %xmm2
mulsd %xmm1, %xmm2
ucomisd %xmm2, %xmm3
ja 0x13237
movapd %xmm3, %xmm5
movsd %xmm0, 0x20(%rsp)
movsd (%r15), %xmm3
movapd %xmm3, %xmm2
movsd 0x1f9f(%rip), %xmm6     # 0x15130
addsd %xmm6, %xmm2
ucomisd %xmm8, %xmm2
movapd %xmm9, %xmm0
subsd %xmm8, %xmm0
movapd %xmm0, %xmm1
ja 0x131af
movapd (%rsp), %xmm1
movapd %xmm9, %xmm4
subsd %xmm3, %xmm4
addsd %xmm6, %xmm0
cmpltsd %xmm2, %xmm8
andpd %xmm8, %xmm4
andnpd %xmm0, %xmm8
orpd %xmm4, %xmm8
movapd %xmm5, %xmm0
movapd %xmm9, %xmm2
movapd %xmm9, %xmm3
addsd %xmm6, %xmm3
ucomisd %xmm1, %xmm3
jb 0x131fd
addsd %xmm6, %xmm2
mulsd %xmm2, %xmm0
divsd %xmm8, %xmm0
addsd %xmm6, %xmm8
jmp 0x131df
movapd %xmm9, %xmm1
subsd %xmm7, %xmm1
divsd %xmm1, %xmm9
movsd %xmm9, 0x10(%rsp)
movsd 0x18(%rsp), %xmm1
callq 0x44c0
movsd 0x20(%rsp), %xmm1
mulsd %xmm0, %xmm1
movsd 0x10(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jb 0x1303a
movq %r12, %rax
addq $0x40, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
retq