// File: aisthesis[P]realnumber/src/array_arithmetic.cpp
// Function: array_arithmetic::divide(unsigned char const*, unsigned char const*, unsigned char*, unsigned long const&, unsigned long const&)
void divide(const unsigned char* dividend, const unsigned char* divisor, unsigned char* result,
			const std::size_t& len, const std::size_t& int_digits) {
		// throw exception if client tries to divide by 0
		if (helpers::is_zero(divisor, len)) {
			throw std::invalid_argument("Division by 0 is not allowed!");
    }
		// initialize result to 0
		helpers::set_to_zero(result, len);
		// we are done if dividend is 0, so return
		if (helpers::is_zero(dividend, len)) { return; }
		// we will need copies of double size for manipulation
		const std::size_t WORKING_LEN = len * 2;
		// this is the bit length of the original values (not the expanded copies)
		const std::size_t BIT_LENGTH = len * 8;
		// 2 dividend arrays are needed because we need to subtract, then use result as new dividend
		unsigned char* dividend_copy1 = new unsigned char[WORKING_LEN];
		unsigned char* dividend_copy2 = new unsigned char[WORKING_LEN];
		unsigned char* divisor_copy = new unsigned char[WORKING_LEN];
		// copy dividend into copy1 (we don't yet need to do anything with dividend_copy2)
		helpers::copy_into(dividend, dividend_copy1, len, WORKING_LEN);
		helpers::copy_into(divisor, divisor_copy, len, WORKING_LEN);
		int starting_bit = int_digits * 8 - 1;
		starting_bit += helpers::division::align(dividend_copy1, divisor_copy, WORKING_LEN);
		bool throw_overflow_exception = (starting_bit < 0);
		std::size_t nonnegative_starting_bit = starting_bit;
		if (!throw_overflow_exception) {
			while (nonnegative_starting_bit < BIT_LENGTH) {
				bits::set(result, nonnegative_starting_bit);
				subtract(dividend_copy1, divisor_copy, dividend_copy2, WORKING_LEN);
				nonnegative_starting_bit += helpers::division::readjust(dividend_copy2, divisor_copy, WORKING_LEN);
				// check the condition of the while loop since we are using double storage
				if (nonnegative_starting_bit >= BIT_LENGTH) { break; }
				bits::set(result, nonnegative_starting_bit);
				subtract(dividend_copy2, divisor_copy, dividend_copy1, WORKING_LEN);
				nonnegative_starting_bit += helpers::division::readjust(dividend_copy1, divisor_copy, WORKING_LEN);
			}
		}
		delete[] dividend_copy1;
		delete[] dividend_copy2;
		delete[] divisor_copy;
		if (throw_overflow_exception) {
			throw std::overflow_error("Result of division is too large to compute!");
		}
	}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xa0, %rsp
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movq %r8, -0x28(%rbp)
movq -0x10(%rbp), %rdi
movq -0x20(%rbp), %rsi
callq 0x5200
testb $0x1, %al
jne 0x5c52
jmp 0x5ca5
movl $0x10, %edi
callq 0x2090
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x78(%rbp)
leaq 0x49d(%rip), %rsi       # 0x610a
callq 0x22c0
jmp 0x5c74
movq -0x78(%rbp), %rdi
movq 0x2361(%rip), %rsi      # 0x7fe0
movq 0x234a(%rip), %rdx      # 0x7fd0
callq 0x2270
movq -0x78(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
callq 0x20f0
jmp 0x5ed5
movq -0x18(%rbp), %rdi
movq -0x20(%rbp), %rsi
callq 0x5260
movq -0x8(%rbp), %rdi
movq -0x20(%rbp), %rsi
callq 0x5200
testb $0x1, %al
jne 0x5cc5
jmp 0x5cca
jmp 0x5ecc
movq -0x20(%rbp), %rax
movq (%rax), %rax
shlq %rax
movq %rax, -0x40(%rbp)
movq -0x20(%rbp), %rax
movq (%rax), %rax
shlq $0x3, %rax
movq %rax, -0x48(%rbp)
movq -0x40(%rbp), %rdi
callq 0x2030
movq %rax, -0x50(%rbp)
movq -0x40(%rbp), %rdi
callq 0x2030
movq %rax, -0x58(%rbp)
movq -0x40(%rbp), %rdi
callq 0x2030
movq %rax, -0x60(%rbp)
movq -0x8(%rbp), %rdi
movq -0x50(%rbp), %rsi
movq -0x20(%rbp), %rdx
leaq -0x40(%rbp), %rcx
callq 0x5060
movq -0x10(%rbp), %rdi
movq -0x60(%rbp), %rsi
movq -0x20(%rbp), %rdx
leaq -0x40(%rbp), %rcx
callq 0x5060
movq -0x28(%rbp), %rax
movq (%rax), %rax
shlq $0x3, %rax
subq $0x1, %rax
movl %eax, -0x64(%rbp)
movq -0x50(%rbp), %rdi
movq -0x60(%rbp), %rsi
leaq -0x40(%rbp), %rdx
callq 0x5480
addl -0x64(%rbp), %eax
movl %eax, -0x64(%rbp)
cmpl $0x0, -0x64(%rbp)
setl %al
andb $0x1, %al
movb %al, -0x65(%rbp)
movslq -0x64(%rbp), %rax
movq %rax, -0x70(%rbp)
testb $0x1, -0x65(%rbp)
jne 0x5e1c
jmp 0x5d81
movq -0x70(%rbp), %rax
cmpq -0x48(%rbp), %rax
jae 0x5e1a
movq -0x18(%rbp), %rdi
leaq -0x70(%rbp), %rsi
callq 0x5580
movq -0x50(%rbp), %rdi
movq -0x60(%rbp), %rsi
movq -0x58(%rbp), %rdx
leaq -0x40(%rbp), %rcx
callq 0x58c0
movq -0x58(%rbp), %rdi
movq -0x60(%rbp), %rsi
leaq -0x40(%rbp), %rdx
callq 0x54d0
cltq
addq -0x70(%rbp), %rax
movq %rax, -0x70(%rbp)
movq -0x70(%rbp), %rax
cmpq -0x48(%rbp), %rax
jb 0x5dd8
jmp 0x5e1a
movq -0x18(%rbp), %rdi
leaq -0x70(%rbp), %rsi
callq 0x5580
movq -0x58(%rbp), %rdi
movq -0x60(%rbp), %rsi
movq -0x50(%rbp), %rdx
leaq -0x40(%rbp), %rcx
callq 0x58c0
movq -0x50(%rbp), %rdi
movq -0x60(%rbp), %rsi
leaq -0x40(%rbp), %rdx
callq 0x54d0
cltq
addq -0x70(%rbp), %rax
movq %rax, -0x70(%rbp)
jmp 0x5d81
jmp 0x5e1c
movq -0x50(%rbp), %rax
movq %rax, -0x80(%rbp)
cmpq $0x0, %rax
je 0x5e33
movq -0x80(%rbp), %rdi
callq 0x2200
movq -0x58(%rbp), %rax
movq %rax, -0x88(%rbp)
cmpq $0x0, %rax
je 0x5e50
movq -0x88(%rbp), %rdi
callq 0x2200
movq -0x60(%rbp), %rax
movq %rax, -0x90(%rbp)
cmpq $0x0, %rax
je 0x5e6d
movq -0x90(%rbp), %rdi
callq 0x2200
testb $0x1, -0x65(%rbp)
je 0x5ecc
movl $0x10, %edi
callq 0x2090
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x98(%rbp)
leaq 0x297(%rip), %rsi       # 0x6128
callq 0x2040
jmp 0x5e98
movq -0x98(%rbp), %rdi
movq 0x2112(%rip), %rsi      # 0x7fb8
movq 0x2103(%rip), %rdx      # 0x7fb0
callq 0x2270
movq -0x98(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
callq 0x20f0
jmp 0x5ed5
addq $0xa0, %rsp
popq %rbp
retq
movq -0x30(%rbp), %rdi
callq 0x2290