// File: /workspace/github_c_makefile_star2_O3/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 $0x38, %rsp
movq %rdx, 0x8(%rsp)
movq 0x10(%rdi), %r8
movq 0x18(%rdi), %r14
movq %r14, %rbp
notq %rbp
movq %r14, %rax
leaq -0x1(%rax), %r12
incq %rbp
cmpq $0x1, %rax
je 0x32f3
cmpb $0x0, -0x1(%r8,%rax)
movq %r12, %rax
je 0x32db
movq 0x10(%rsi), %r9
movq 0x18(%rsi), %rbx
movq $-0x2, %r13
subq %rbx, %r13
movq %rbx, %rax
leaq -0x1(%rax), %r15
incq %r13
cmpq $0x1, %rax
je 0x3320
cmpb $0x0, -0x1(%r9,%rax)
movq %r15, %rax
je 0x3308
movzbl 0x6db8(%rip), %r10d     # 0xa0e0
cmpq %r10, %r12
setae %al
cmpq %r10, %r15
setae %dl
orb %al, %dl
jne 0x33d4
leaq -0x1(%r14), %rdi
cmpq $0x1, %r14
je 0x3351
cmpb $0x0, -0x1(%r8,%r14)
movq %rdi, %r14
je 0x333c
xorl %eax, %eax
movq %rdi, %rdx
leaq (%rax,%rax,4), %rax
movsbq (%r8,%rdx), %rsi
leaq (%rsi,%rax,2), %rax
decq %rdx
cmpq %rdi, %rdx
jbe 0x3356
jmp 0x3378
cmpb $0x0, -0x1(%r9,%rbx)
movq %r8, %rbx
jne 0x3382
leaq -0x1(%rbx), %r8
cmpq $0x1, %rbx
jne 0x336d
xorl %esi, %esi
movq %r8, %rdx
leaq (%rsi,%rsi,4), %rsi
movsbq (%r9,%rdx), %rdi
leaq (%rdi,%rsi,2), %rsi
decq %rdx
cmpq %r8, %rdx
jbe 0x3387
cqto
idivq %rsi
testb %cl, %cl
je 0x3429
movq %rax, %rdi
callq 0x24a0
movq %rax, %rbx
movq 0x8(%rsp), %rdi
movq %rax, %rsi
callq 0x2930
movq %rax, %r14
movq %rbx, %rdi
callq 0x528a
movq %r14, %rax
jmp 0x35fa
movq %r10, 0x28(%rsp)
movq %r9, 0x20(%rsp)
movq %r8, 0x18(%rsp)
movl %ecx, 0x4(%rsp)
movq %rdi, 0x10(%rsp)
movq %rsi, 0x30(%rsp)
callq 0x2b97
testb %al, %al
je 0x343f
movzbl %al, %eax
cmpl $0xff, %eax
movl 0x4(%rsp), %eax
jne 0x3467
testb %al, %al
movq 0x10(%rsp), %rdi
je 0x3416
movq 0x8(%rsp), %rdi
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2886
movq %rdx, %rdi
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x24a0
cmpb $0x0, 0x4(%rsp)
je 0x35e9
movl $0x1, %esi
movq 0x8(%rsp), %rdi
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2cb4
movq 0x28(%rsp), %r8
leaq -0x1(%r8), %rax
addq %r8, %r13
negq %r13
xorl %edi, %edi
cmpq %rax, %r15
cmovbeq %rdi, %r13
cmpq %r13, %r15
setae %al
cmpq %rbx, %r15
setb %cl
andb %al, %cl
cmpb $0x1, %cl
jne 0x34ba
xorl %edi, %edi
movq 0x18(%rsp), %rdx
movq 0x20(%rsp), %rsi
leaq (%rdi,%rdi,4), %rax
movsbq (%rsi,%r15), %rcx
leaq (%rcx,%rax,2), %rdi
decq %r15
cmpq %r13, %r15
jb 0x34bf
cmpq %rbx, %r15
jb 0x349e
jmp 0x34bf
movq 0x18(%rsp), %rdx
addq %r8, %rbp
negq %rbp
xorl %ebx, %ebx
cmpq %r8, %r12
cmovbeq %rbx, %rbp
cmpq %r13, %rbp
cmovbeq %r13, %rbp
cmpq %rbp, %r12
setae %al
cmpq %r14, %r12
setb %cl
andb %al, %cl
cmpb $0x1, %cl
jne 0x3504
xorl %ebx, %ebx
leaq (%rbx,%rbx,4), %rax
movsbq (%rdx,%r12), %rcx
leaq (%rcx,%rax,2), %rbx
decq %r12
cmpq %rbp, %r12
jb 0x3504
cmpq %r14, %r12
jb 0x34ea
movq %rbx, %rax
cqto
idivq %rdi
movq %rdi, %r13
movq %rax, %rdi
callq 0x24a0
movq %rax, %r14
subq %r15, %r12
movq %rax, %rdi
movq %r12, %rsi
callq 0x3b50
movq %r14, %rdi
movq 0x30(%rsp), %r15
movq %r15, %rsi
callq 0x2ea3
movq %rax, %rbp
movq %rax, %rdi
movq 0x10(%rsp), %rsi
callq 0x2b97
cmpb $0x1, %al
jne 0x358b
movq %r14, %rdi
callq 0x528a
movq %rbp, %rdi
callq 0x528a
incq %r13
movq %rbx, %rax
cqto
idivq %r13
movq %rax, %rdi
callq 0x24a0
movq %rax, %r14
movq %rax, %rdi
movq %r12, %rsi
callq 0x3b50
movq %r14, %rdi
movq %r15, %rsi
callq 0x2ea3
movq %rax, %rbp
movq %r15, %rbx
movq 0x10(%rsp), %rdi
movq %rbp, %rsi
callq 0x2bf8
movq %rax, %r15
movq %rbp, %rdi
callq 0x528a
movq 0x8(%rsp), %rdi
movq %r14, %rsi
callq 0x29f6
movq %rax, %r12
movq %r14, %rdi
callq 0x528a
movzbl 0x4(%rsp), %ecx
movq %r15, %rdi
movq %rbx, %rsi
movq %r12, %rdx
callq 0x32b7
movq %rax, %rbx
movq %r12, %rdi
callq 0x528a
movq %r15, %rdi
callq 0x528a
movq %rbx, %rax
jmp 0x35fa
movl $0x1, %edi
callq 0x2541
movq 0x10(%rax), %rcx
movb $0x0, (%rcx)
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq