// File: /workspace/github_c_makefile_star2_O0/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
movq %rsp, %rbp
subq $0xb0, %rsp
movb %cl, %al
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq %rdx, -0x20(%rbp)
movb %al, -0x21(%rbp)
movq -0x10(%rbp), %rdi
callq 0x2690
movq %rax, -0x48(%rbp)
movq -0x18(%rbp), %rdi
callq 0x2690
movq %rax, -0x50(%rbp)
movq -0x48(%rbp), %rax
movzbl 0x7977(%rip), %ecx      # 0xb0c8
cmpq %rcx, %rax
jae 0x37f6
movq -0x50(%rbp), %rax
movzbl 0x7963(%rip), %ecx      # 0xb0c8
cmpq %rcx, %rax
jae 0x37f6
movq -0x10(%rbp), %rdi
callq 0x4140
movq %rax, -0x30(%rbp)
movq -0x18(%rbp), %rdi
callq 0x4140
movq %rax, -0x38(%rbp)
cmpb $0x0, -0x21(%rbp)
je 0x37c8
movq -0x30(%rbp), %rax
cqto
idivq -0x38(%rbp)
movq %rax, -0x40(%rbp)
movq -0x40(%rbp), %rdi
callq 0x2400
movq %rax, -0x78(%rbp)
movq -0x20(%rbp), %rdi
movq -0x78(%rbp), %rsi
callq 0x2ac0
movq %rax, -0x98(%rbp)
movq -0x78(%rbp), %rdi
callq 0x6480
jmp 0x37e6
movq -0x30(%rbp), %rax
cqto
idivq -0x38(%rbp)
movq %rdx, -0x40(%rbp)
movq -0x40(%rbp), %rdi
callq 0x2400
movq %rax, -0x98(%rbp)
movq -0x98(%rbp), %rax
movq %rax, -0x8(%rbp)
jmp 0x3b0e
movq -0x10(%rbp), %rdi
movq -0x18(%rbp), %rsi
callq 0x2e00
movb %al, -0x22(%rbp)
movsbl -0x22(%rbp), %eax
cmpl $-0x1, %eax
jne 0x3839
cmpb $0x0, -0x21(%rbp)
je 0x3827
movq -0x20(%rbp), %rdi
callq 0x29c0
movq %rax, -0x8(%rbp)
jmp 0x3b0e
movq -0x10(%rbp), %rdi
callq 0x29c0
movq %rax, -0x8(%rbp)
jmp 0x3b0e
movsbl -0x22(%rbp), %eax
cmpl $0x0, %eax
jne 0x3871
cmpb $0x0, -0x21(%rbp)
je 0x385f
movq -0x20(%rbp), %rdi
movl $0x1, %esi
callq 0x3020
movq %rax, -0x8(%rbp)
jmp 0x3b0e
xorl %eax, %eax
movl %eax, %edi
callq 0x2400
movq %rax, -0x8(%rbp)
jmp 0x3b0e
jmp 0x3873
movq -0x50(%rbp), %rax
movzbl 0x784a(%rip), %ecx      # 0xb0c8
subl $0x1, %ecx
movslq %ecx, %rcx
cmpq %rcx, %rax
jbe 0x38a7
movq -0x50(%rbp), %rax
movzbl 0x7834(%rip), %ecx      # 0xb0c8
subl $0x1, %ecx
movslq %ecx, %rcx
subq %rcx, %rax
addq $0x1, %rax
movq %rax, -0x60(%rbp)
jmp 0x38af
movq $0x0, -0x60(%rbp)
movq $0x0, -0x38(%rbp)
movq -0x50(%rbp), %rax
movq %rax, -0x70(%rbp)
movq -0x70(%rbp), %rcx
xorl %eax, %eax
cmpq -0x60(%rbp), %rcx
movb %al, -0x99(%rbp)
jb 0x38e6
movq -0x70(%rbp), %rax
movq -0x18(%rbp), %rcx
cmpq 0x18(%rcx), %rax
setb %al
movb %al, -0x99(%rbp)
movb -0x99(%rbp), %al
testb $0x1, %al
jne 0x38f2
jmp 0x3922
imulq $0xa, -0x38(%rbp), %rax
movq %rax, -0x38(%rbp)
movq -0x18(%rbp), %rax
movq 0x10(%rax), %rax
movq -0x70(%rbp), %rcx
movsbq (%rax,%rcx), %rax
addq -0x38(%rbp), %rax
movq %rax, -0x38(%rbp)
movq -0x70(%rbp), %rax
addq $-0x1, %rax
movq %rax, -0x70(%rbp)
jmp 0x38bf
movq $0x0, -0x30(%rbp)
movq -0x48(%rbp), %rax
movzbl 0x7793(%rip), %ecx      # 0xb0c8
cmpq %rcx, %rax
jbe 0x3955
movq -0x48(%rbp), %rax
movzbl 0x7783(%rip), %ecx      # 0xb0c8
subq %rcx, %rax
addq $0x1, %rax
movq %rax, -0xa8(%rbp)
jmp 0x3960
xorl %eax, %eax
movq %rax, -0xa8(%rbp)
jmp 0x3960
movq -0xa8(%rbp), %rax
movq %rax, -0x58(%rbp)
movq -0x58(%rbp), %rax
cmpq -0x60(%rbp), %rax
jae 0x397d
movq -0x60(%rbp), %rax
movq %rax, -0x58(%rbp)
movq -0x48(%rbp), %rax
movq %rax, -0x68(%rbp)
movq -0x68(%rbp), %rcx
xorl %eax, %eax
cmpq -0x58(%rbp), %rcx
movb %al, -0xa9(%rbp)
jb 0x39ac
movq -0x68(%rbp), %rax
movq -0x10(%rbp), %rcx
cmpq 0x18(%rcx), %rax
setb %al
movb %al, -0xa9(%rbp)
movb -0xa9(%rbp), %al
testb $0x1, %al
jne 0x39b8
jmp 0x39e8
imulq $0xa, -0x30(%rbp), %rax
movq %rax, -0x30(%rbp)
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rax
movq -0x68(%rbp), %rcx
movsbq (%rax,%rcx), %rax
addq -0x30(%rbp), %rax
movq %rax, -0x30(%rbp)
movq -0x68(%rbp), %rax
addq $-0x1, %rax
movq %rax, -0x68(%rbp)
jmp 0x3985
movq -0x30(%rbp), %rax
cqto
idivq -0x38(%rbp)
movq %rax, %rdi
callq 0x2400
movq %rax, -0x78(%rbp)
movq -0x78(%rbp), %rdi
movq -0x68(%rbp), %rsi
subq -0x70(%rbp), %rsi
callq 0x42a0
movq -0x78(%rbp), %rdi
movq -0x18(%rbp), %rsi
callq 0x3300
movq %rax, -0x80(%rbp)
movq -0x80(%rbp), %rdi
movq -0x10(%rbp), %rsi
callq 0x2e00
movb %al, -0x22(%rbp)
movsbl -0x22(%rbp), %eax
cmpl $0x1, %eax
jne 0x3a8f
movq -0x78(%rbp), %rdi
callq 0x6480
movq -0x80(%rbp), %rdi
callq 0x6480
movq -0x38(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x38(%rbp)
movq -0x30(%rbp), %rax
cqto
idivq -0x38(%rbp)
movq %rax, %rdi
callq 0x2400
movq %rax, -0x78(%rbp)
movq -0x78(%rbp), %rdi
movq -0x68(%rbp), %rsi
subq -0x70(%rbp), %rsi
callq 0x42a0
movq -0x78(%rbp), %rdi
movq -0x18(%rbp), %rsi
callq 0x3300
movq %rax, -0x80(%rbp)
movq -0x10(%rbp), %rdi
movq -0x80(%rbp), %rsi
callq 0x2ed0
movq %rax, -0x90(%rbp)
movq -0x80(%rbp), %rdi
callq 0x6480
movq -0x20(%rbp), %rdi
movq -0x78(%rbp), %rsi
callq 0x2c20
movq %rax, -0x88(%rbp)
movq -0x78(%rbp), %rdi
callq 0x6480
movq -0x90(%rbp), %rdi
movq -0x18(%rbp), %rsi
movq -0x88(%rbp), %rdx
movzbl -0x21(%rbp), %ecx
callq 0x3710
movq %rax, -0x98(%rbp)
movq -0x88(%rbp), %rdi
callq 0x6480
movq -0x90(%rbp), %rdi
callq 0x6480
movq -0x98(%rbp), %rax
movq %rax, -0x8(%rbp)
movq -0x8(%rbp), %rax
addq $0xb0, %rsp
popq %rbp
retq
nopl (%rax,%rax)