// File: 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 %rbp
movq %rsp, %rbp
subq $0xd0, %rsp
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq %rdx, -0x20(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0xb0(%rbp)
movq $0x0, -0x28(%rbp)
movsd 0x1956(%rip), %xmm0     # 0x24128
movsd %xmm0, -0x30(%rbp)
movq -0x18(%rbp), %rax
movsd (%rax), %xmm0
movq -0x20(%rbp), %rax
movsd (%rax), %xmm1
divsd -0x30(%rbp), %xmm1
ucomisd %xmm1, %xmm0
jb 0x2280f
movq -0xb0(%rbp), %rdi
movq -0x18(%rbp), %rsi
movq -0x20(%rbp), %rdx
callq 0x225c0
movq %rax, -0x8(%rbp)
jmp 0x22c40
movq -0x18(%rbp), %rax
movsd (%rax), %xmm0
movsd 0xcb9(%rip), %xmm1      # 0x234d8
ucomisd %xmm1, %xmm0
jne 0x228d3
jp 0x228d3
jmp 0x22831
movq -0xb0(%rbp), %rdi
movq -0x20(%rbp), %rax
movsd (%rax), %xmm0
movsd %xmm0, -0xb8(%rbp)
callq 0x22cb0
movaps %xmm0, %xmm1
movsd -0xb8(%rbp), %xmm0
mulsd %xmm1, %xmm0
callq 0x45b0
movaps %xmm0, %xmm1
cvttsd2si %xmm1, %rax
movq %rax, %rdx
sarq $0x3f, %rdx
movsd 0x18a8(%rip), %xmm1     # 0x24120
subsd %xmm1, %xmm0
cvttsd2si %xmm0, %rcx
andq %rdx, %rcx
orq %rcx, %rax
movq %rax, -0x28(%rbp)
movq -0x28(%rbp), %rax
movq -0x20(%rbp), %rcx
movsd (%rcx), %xmm0
movsd 0x1881(%rip), %xmm2     # 0x24120
movaps %xmm0, %xmm1
subsd %xmm2, %xmm1
cvttsd2si %xmm1, %rdx
cvttsd2si %xmm0, %rcx
movq %rcx, %rsi
sarq $0x3f, %rsi
andq %rsi, %rdx
orq %rdx, %rcx
cmpq %rcx, %rax
je 0x22831
movq -0x28(%rbp), %rax
movq %rax, -0x8(%rbp)
jmp 0x22c40
jmp 0x228d5
movq -0x18(%rbp), %rax
movsd (%rax), %xmm2
movsd 0xbf3(%rip), %xmm1      # 0x234d8
movaps %xmm1, %xmm0
divsd %xmm2, %xmm0
movsd %xmm0, -0x38(%rbp)
movq -0x18(%rbp), %rax
movsd (%rax), %xmm2
subsd %xmm1, %xmm2
movaps %xmm1, %xmm0
divsd %xmm2, %xmm0
movsd %xmm0, -0x40(%rbp)
movq -0x20(%rbp), %rax
movsd (%rax), %xmm0
addsd %xmm1, %xmm0
movq -0x18(%rbp), %rax
movsd (%rax), %xmm1
subsd %xmm1, %xmm0
movsd %xmm0, -0x48(%rbp)
movsd -0x48(%rbp), %xmm0
movsd 0x17ed(%rip), %xmm2     # 0x24120
movaps %xmm0, %xmm1
subsd %xmm2, %xmm1
cvttsd2si %xmm1, %rcx
cvttsd2si %xmm0, %rax
movq %rax, %rdx
sarq $0x3f, %rdx
andq %rdx, %rcx
orq %rcx, %rax
movq %rax, -0x50(%rbp)
movl $0x0, -0x7c(%rbp)
movq -0xb0(%rbp), %rdi
callq 0x22cb0
movsd -0x38(%rbp), %xmm1
callq 0x4600
movsd %xmm0, -0x58(%rbp)
movq -0x20(%rbp), %rax
movsd (%rax), %xmm0
movsd -0x58(%rbp), %xmm2
movsd 0xb4c(%rip), %xmm1      # 0x234d8
subsd %xmm2, %xmm1
mulsd %xmm1, %xmm0
movsd %xmm0, -0x60(%rbp)
movsd -0x60(%rbp), %xmm0
callq 0x45b0
movsd 0x1775(%rip), %xmm2     # 0x24120
movaps %xmm0, %xmm1
subsd %xmm2, %xmm1
cvttsd2si %xmm1, %rcx
cvttsd2si %xmm0, %rax
movq %rax, %rdx
sarq $0x3f, %rdx
andq %rdx, %rcx
orq %rcx, %rax
movq %rax, -0x28(%rbp)
movl -0x7c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x7c(%rbp)
movq -0x28(%rbp), %rax
cmpq -0x50(%rbp), %rax
jae 0x2295c
movq -0xb0(%rbp), %rdi
callq 0x22cb0
movsd %xmm0, -0x70(%rbp)
movaps 0xaa4(%rip), %xmm1      # 0x234a0
movq -0x28(%rbp), %xmm0
punpckldq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1]
movapd 0xaa3(%rip), %xmm1      # 0x234b0
subpd %xmm1, %xmm0
movaps %xmm0, %xmm1
unpckhpd %xmm0, %xmm0            # xmm0 = xmm0[1,1]
addsd %xmm1, %xmm0
movsd %xmm0, -0x68(%rbp)
movsd -0x70(%rbp), %xmm0
movq -0x20(%rbp), %rax
mulsd (%rax), %xmm0
divsd -0x48(%rbp), %xmm0
movsd -0x40(%rbp), %xmm1
callq 0x4600
movsd %xmm0, -0x78(%rbp)
movsd -0x78(%rbp), %xmm0
movsd -0x60(%rbp), %xmm2
movq -0x20(%rbp), %rax
divsd (%rax), %xmm2
movsd 0xa7c(%rip), %xmm1      # 0x234d8
subsd %xmm2, %xmm1
mulsd %xmm1, %xmm0
movsd -0x48(%rbp), %xmm1
movsd -0x48(%rbp), %xmm2
subsd -0x68(%rbp), %xmm2
divsd %xmm2, %xmm1
mulsd %xmm1, %xmm0
movsd %xmm0, -0x58(%rbp)
movsd 0xa50(%rip), %xmm0      # 0x234d8
ucomisd -0x58(%rbp), %xmm0
jbe 0x22a94
jmp 0x22c38
movsd 0xa3c(%rip), %xmm0      # 0x234d8
movsd %xmm0, -0x88(%rbp)
movq -0x20(%rbp), %rax
movsd (%rax), %xmm0
movsd 0xa24(%rip), %xmm1      # 0x234d8
subsd %xmm1, %xmm0
movsd %xmm0, -0x90(%rbp)
movsd -0x68(%rbp), %xmm1
movq -0x18(%rbp), %rax
movsd (%rax), %xmm0
movsd 0xa03(%rip), %xmm2      # 0x234d8
subsd %xmm2, %xmm0
ucomisd %xmm1, %xmm0
jbe 0x22b0e
movq -0x20(%rbp), %rax
movsd (%rax), %xmm0
movq -0x18(%rbp), %rax
subsd (%rax), %xmm0
movsd %xmm0, -0x98(%rbp)
movq -0x20(%rbp), %rax
movsd (%rax), %xmm0
subsd -0x68(%rbp), %xmm0
movsd %xmm0, -0xa0(%rbp)
jmp 0x22b3c
movq -0x20(%rbp), %rax
movsd (%rax), %xmm0
subsd -0x68(%rbp), %xmm0
movsd 0x9b5(%rip), %xmm1      # 0x234d8
subsd %xmm1, %xmm0
movsd %xmm0, -0x98(%rbp)
movsd -0x48(%rbp), %xmm0
movsd %xmm0, -0xa0(%rbp)
movq -0x20(%rbp), %rax
movsd (%rax), %xmm0
movsd 0x98c(%rip), %xmm1      # 0x234d8
subsd %xmm1, %xmm0
movsd %xmm0, -0xa8(%rbp)
movsd -0xa8(%rbp), %xmm0
ucomisd -0xa0(%rbp), %xmm0
jb 0x22bd4
movsd -0x88(%rbp), %xmm0
mulsd -0x90(%rbp), %xmm0
divsd -0x98(%rbp), %xmm0
movsd %xmm0, -0x88(%rbp)
movsd 0x1586(%rip), %xmm0     # 0x24118
addsd -0x90(%rbp), %xmm0
movsd %xmm0, -0x90(%rbp)
movsd 0x156e(%rip), %xmm0     # 0x24118
addsd -0x98(%rbp), %xmm0
movsd %xmm0, -0x98(%rbp)
movsd 0x1556(%rip), %xmm0     # 0x24118
addsd -0xa8(%rbp), %xmm0
movsd %xmm0, -0xa8(%rbp)
jmp 0x22b58
movq -0x20(%rbp), %rax
movsd (%rax), %xmm0
movq -0x20(%rbp), %rax
movsd (%rax), %xmm1
subsd -0x60(%rbp), %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, -0xc0(%rbp)
movsd -0x78(%rbp), %xmm0
movsd %xmm0, -0xc8(%rbp)
movsd -0x88(%rbp), %xmm0
movsd -0x40(%rbp), %xmm1
callq 0x4600
movsd -0xc8(%rbp), %xmm1
movaps %xmm0, %xmm2
movsd -0xc0(%rbp), %xmm0
mulsd %xmm2, %xmm1
ucomisd %xmm1, %xmm0
jb 0x22c33
jmp 0x22c38
jmp 0x22955
movq -0x28(%rbp), %rax
movq %rax, -0x8(%rbp)
movq -0x8(%rbp), %rax
addq $0xd0, %rsp
popq %rbp
retq
nopl (%rax)