// File: /workspace/github_c_makefile_star2_O2/theck01[P]offbrand_lib/src/classes/obint.c
// Function: obint_reduce
obint * obint_reduce(const obint *a, const obint *b, const obint *approx,
                           uint8_t quotient){

  int8_t comp_val;
  int64_t a_val, b_val, result_val;
  uint64_t a_most_sig, b_most_sig, a_min, b_min, i, j;
  obint *partial; /* partial results */
  obint *product; /* quotient approximation multiplied by b */
  obint *new_approx; /* improved approximation */
  obint *new_dividend; /* reduced dividend */
  obint *result; /* approximation */

  a_most_sig = obint_most_sig(a);
  b_most_sig = obint_most_sig(b);

  /* if operation can be computed using integer arithmetic do so */
  if(a_most_sig < int64_max_digits && b_most_sig < int64_max_digits){

    a_val = obint_magnitude(a);
    b_val = obint_magnitude(b);

    if(quotient){
      result_val = a_val/b_val;
      partial = obint_new(result_val);
      result = obint_add(approx, partial);
      ob_release((obj *)partial);
    }
    else{
      result_val = a_val%b_val;
      result = obint_new(result_val);
    }

    return result;
  }

  /* if a < b (so a/b = 0, a%b = a) */
  comp_val = obint_compare_magnitudes(a, b);
  if(comp_val == OB_LESS_THAN){
    if(quotient) return obint_copy(approx);
    else return obint_copy(a);
  }
  /* if a == b (so a/b = 1, a%b = 0) */
  else if(comp_val == OB_EQUAL_TO){
    if(quotient) return obint_add_primitive(approx,1);
    else return obint_new(0);
  }

  /* else recursive division approximation */

  /* generate machine integers for approximation */

  /* generate b_val to have one less digit than int64_max_digits, to ensure
   * b_val < a_val */
  if(b_most_sig > (uint64_t)(int64_max_digits - 1)){
    b_min = b_most_sig - (int64_max_digits - 1) + 1;
  }
  else{
    b_min = 0;
  }
  b_val = 0;
  for(j=b_most_sig; j>=b_min && j<b->num_digits; j--){
    b_val *= 10;
    b_val += b->digits[j];
  }

  a_val = 0;
  a_min = a_most_sig > int64_max_digits ? a_most_sig-int64_max_digits+1 : 0;

  /* a_val approximation must be cutoff at the same point as b_val
   * approximation, to protect against overflow */
  if(a_min < b_min) a_min = b_min;
  for(i=a_most_sig; i>=a_min && i<a->num_digits; i--){
    a_val *= 10;
    a_val += a->digits[i];
  }

  /* perform approximation division, shift into proper decimal place, and add
   * to approximation */
  partial = obint_new(a_val/b_val);
  obint_shift(partial, i-j);
  product = obint_multiply_unsigned(partial, b);

  comp_val = obint_compare_magnitudes(product, a);

  /* if approximation is too great then increment b_val to account for remaining
   * portion of b that is causing over approximation */
  if(comp_val == OB_GREATER_THAN){
    ob_release((obj *)partial);
    ob_release((obj *)product);

    b_val++;
    partial = obint_new(a_val/b_val);
    obint_shift(partial, i-j);
    product = obint_multiply_unsigned(partial, b);
  }

  new_dividend = obint_subtract_unsigned(a, product);
  ob_release((obj *)product);
  new_approx = obint_add_unsigned(approx, partial);
  ob_release((obj *)partial);

  result = obint_reduce(new_dividend, b, new_approx, quotient);

  ob_release((obj *)new_approx);
  ob_release((obj *)new_dividend);

  return result;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x28, %rsp
movl %ecx, %ebx
movq %rdx, 0x8(%rsp)
movq %rsi, %r14
movq %rdi, %r15
callq 0x2455
movq %rax, %r12
movq %r14, %rdi
callq 0x2455
movq %rax, %rbp
movzbl 0x6226(%rip), %edx      # 0x90e0
cmpq %rdx, %r12
setb %al
movq %rbp, %r13
subq %rdx, %r13
setb %cl
andb %al, %cl
cmpb $0x1, %cl
jne 0x2f15
movq %r15, %rdi
callq 0x359d
movl %ebx, %ebp
movq %rax, %rbx
movq %r14, %rdi
callq 0x359d
movq %rax, %rcx
movq %rbx, %rax
cqto
idivq %rcx
testb %bpl, %bpl
je 0x2f4a
movq %rax, %rdi
callq 0x22e0
movq %rax, %rbx
movq 0x8(%rsp), %rdi
movq %rax, %rsi
callq 0x26e4
movq %rax, %r14
jmp 0x30ca
movq %rdx, 0x20(%rsp)
movq %r15, %rdi
movq %r14, 0x10(%rsp)
movq %r14, %rsi
callq 0x289f
testb %al, %al
je 0x2f52
movzbl %al, %eax
cmpl $0xff, %eax
jne 0x2f75
testb %bl, %bl
je 0x30e4
movq 0x8(%rsp), %rdi
jmp 0x30e7
movq %rdx, %rdi
jmp 0x30fc
testb %bl, %bl
je 0x30fa
pushq $0x1
popq %rsi
movq 0x8(%rsp), %rdi
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x298c
movq 0x20(%rsp), %rdx
leaq -0x1(%rdx), %rax
addq $0x2, %r13
xorl %r14d, %r14d
cmpq %rax, %rbp
cmovbeq %r14, %r13
movq 0x10(%rsp), %rsi
cmpq %r13, %rbp
jb 0x2fb1
cmpq 0x18(%rsi), %rbp
jae 0x2fb1
imulq $0xa, %r14, %rax
movq 0x10(%rsi), %rcx
movsbq (%rcx,%rbp), %r14
addq %rax, %r14
decq %rbp
jmp 0x2f91
movl %ebx, 0x1c(%rsp)
xorl %ebx, %ebx
movq %r12, %rax
subq %rdx, %rax
leaq 0x1(%rax), %rax
cmovbeq %rbx, %rax
cmpq %r13, %rax
cmovbeq %r13, %rax
movq %r12, %r13
subq %rbp, %r13
cmpq %rax, %r12
jb 0x2ff5
cmpq 0x18(%r15), %r12
jae 0x2ff5
imulq $0xa, %rbx, %rcx
movq 0x10(%r15), %rdx
movsbq (%rdx,%r12), %rbx
addq %rcx, %rbx
decq %r12
decq %r13
jmp 0x2fd2
movq %rbx, %rax
cqto
idivq %r14
movq %rax, %rdi
movq %rsi, %rbp
callq 0x22e0
movq %rax, %r12
movq %rax, %rdi
movq %r13, %rsi
callq 0x3653
movq %r12, %rdi
movq %rbp, %rsi
callq 0x2b72
movq %rax, %rbp
movq %rax, %rdi
movq %r15, %rsi
callq 0x289f
cmpb $0x1, %al
jne 0x3079
movq %r12, %rdi
callq 0x4c7e
movq %rbp, %rdi
callq 0x4c7e
incq %r14
movq %rbx, %rax
cqto
idivq %r14
movq %rax, %rdi
callq 0x22e0
movq %rax, %r12
movq %rax, %rdi
movq %r13, %rsi
callq 0x3653
movq %r12, %rdi
movq 0x10(%rsp), %r14
movq %r14, %rsi
callq 0x2b72
movq %rax, %rbp
jmp 0x307e
movq 0x10(%rsp), %r14
movq %r15, %rdi
movq %rbp, %rsi
callq 0x28f8
movq %rax, %rbx
movq %rbp, %rdi
callq 0x4c7e
movq 0x8(%rsp), %rdi
movq %r12, %rsi
callq 0x27a5
movq %rax, %r15
movq %r12, %rdi
callq 0x4c7e
movzbl 0x1c(%rsp), %ecx
movq %rbx, %rdi
movq %r14, %rsi
movq %r15, %rdx
callq 0x2e85
movq %rax, %r14
movq %r15, %rdi
callq 0x4c7e
movq %rbx, %rdi
callq 0x4c7e
movq %r14, %rax
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %r15, %rdi
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2651
xorl %edi, %edi
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x22e0