// File: DavidLBruce[P]sim3dof/Matrix/build/../../Matrix/src/Matrix.cpp
// Function: Matrix::Inv()
Matrix Matrix::Inv()
{
  //
  // Check to make sure the matrix is square.
  //
  if (rows != cols)
  {
    throw(DIMERR());
  }

  int    col(0);
  double factor(0.0);        // xmult
  int    identElem(0);       //
  int    pivotRow(0);        // lSubk
  int    pivotRowTrial(0);   //
  double *pRhs(NULL);        //
  double *pRowMaxes(NULL);   // sSubi
  int    *pRowOrder(NULL);   // l
  double ratio(0.0);         // r
  double ratioMax(0.0);      // rmax
  int    row(0);             // i1
  double rowMax(0.0);        //
  double sum(0.0);           //
  int    temp(0);            //
  Matrix result(rows, cols); //
  int    rowIdx;             //
  int    rowRatioMax;        // 
  int    rowMaxIdx;          //
  int    scaleRow;           // lSubi
  int    zeroColIdx(0);      // k

  #ifdef debugEn
  FILE*fp = fopen("Debug.txt", "w");
  #endif
  //
  // Forward elimination with scaled pivoting.  This algorithm calculates an
  // upper triangular matrix of coefficients called upTriang.  The resulting
  // system is:
  //
  //   upTriang * x = b'
  //
  // The upper triangular system is easily solved for x by back substitution,
  // starting at the last row.
  //
  // The solution to the upper triangular system x also solves the original 
  // linear system:
  //
  //   Ax = b
  //
  // Later, sucessive columns of the identity matrix will be substituted for
  // b, resulting in successive columns of the inv(A) matrix.
  //
  //   A*inv(A) = I
  //
  // Gaussian elimination takes one equation of a system of linear equations
  // as a pivot row.  For each of the remaining rows a scaled version of the 
  // pivot row is subtracted, such that one element of the selected row is 
  // zeroed.
  //
  // Then a new pivot row is selected and the process is repeated eliminating
  // a new element from the remaining rows.
  //
  // In order to reduce the chance for errors due to finite arithmetic, the
  // sequence of pivot rows is selected such that the initial scale ratio is
  // largest.  Successive pivot rows are selected in order of decreasing 
  // scale ratio.  Rather than reorder the system of equitions, a vector is 
  // created to maintain the order in which the pivot rows are selected. 
  // The order in which the pivot rows are selected is stored in the rowOrder
  // vector.
  //
  pRowOrder = new int[rows];

  //
  // The abs(maximum) of each row is stored in pRowMaxws vector.
  //
  pRowMaxes = new double[rows];

  //
  // Create a copy of the matrix.  The algorithm will convert the new matrix
  // into upper triangular form as it proceeds.
  //
  Matrix upTriang(*this);

  //
  // Find the largest coefficient in each row.
  //
  for (row = 0; row < rows; ++row)
  {
    //
    // Initialize the pivot row order as the initial matrix row order.  This
    // order will be modified as the algorithm progresses.
    //
    pRowOrder[row] = row;

    rowMax = 0.0;
    for (col = 0; col < cols; ++col)
    {
      rowMax = Max(rowMax, fabs(upTriang[row][col]));
    }
    pRowMaxes[row] = rowMax;
  }

  #ifdef debugEn
  fprintf(fp, "p05 pRowMaxes = %7.2f %7.2f %7.2f %7.2f \n", 
               pRowMaxes[0], pRowMaxes[1], pRowMaxes[2], pRowMaxes[3]);
  fprintf(fp, "pRowOrder = %d %d %d %d \n", pRowOrder[0], pRowOrder[1],
                                    pRowOrder[2], pRowOrder[3]);
  #endif

  //
  // Step through the system along the diagonal, selecting the appropriate pivot
  // element for each column.
  //
  for (zeroColIdx = 0; zeroColIdx < cols - 1; ++zeroColIdx)
  {
    #ifdef debugEn
    fprintf(fp, "p10 zeroColIdx (k) = %d \n", zeroColIdx);
    #endif

    //
    // Find the row with the largest scale ratio for each column.  This will be
    // the pivot row for that column.
    //
    ratioMax = 0.0;

    for (rowIdx = zeroColIdx; rowIdx < rows; ++rowIdx)
    {
      //
      // See if the next row should be the pivot row for this pivot index by
      // selecting the highest scale ratio.
      //
      pivotRowTrial = pRowOrder[rowIdx];

      //
      // The denomiator in the ratio calculation below should never be zero
      // since it was chosen to be the max relative to the row.
      //
      if (pRowMaxes[pivotRowTrial] == 0.0)
      {
        throw(SINGERR());
      }

      ratio = fabs(upTriang[pivotRowTrial][zeroColIdx] / 
                                                  pRowMaxes[pivotRowTrial]);

      if (ratio > ratioMax)
      {
        ratioMax = ratio;

        rowRatioMax = rowIdx;
      }
    } // end for (rowIdx = zeroColIdx; rowIdx < rows; ++rowIdx)

    #ifdef debugEn
    fprintf(fp, "p20 ratioMax = %7.2f \n", ratioMax);
    fprintf(fp, "p30 rowRatioMax (j) = %d \n", rowRatioMax); 
    #endif

    //
    // Sort the pivot row list by interchanging the newly found pivot row with
    // the current row pointed to by the pivot index.
    //
    temp = pRowOrder[zeroColIdx];
    pRowOrder[zeroColIdx] = pRowOrder[rowRatioMax];
    pRowOrder[rowRatioMax] = temp;
    
    #ifdef debugEn
    fprintf(fp, "p40: lSubj <--> lSubk \n");
    fprintf(fp, "p50: pRowOrder = %d %d %d %d \n", pRowOrder[0], pRowOrder[1],
                                    pRowOrder[2], pRowOrder[3]);
    #endif

    pivotRow = pRowOrder[zeroColIdx];
    
    #ifdef debugEn
    fprintf(fp, "p30 pivotRow (j) = %d \n", pivotRow); 
    #endif

    for (rowIdx = zeroColIdx + 1; rowIdx < rows; ++rowIdx)
    {
      scaleRow = pRowOrder[rowIdx];
      
      #ifdef debugEn
      fprintf(fp, "p70 scaleRow = row being scaled %d \n", scaleRow);
      #endif
  
      //
      // The denomenator in the factor calculation should never be zero since it
      // was chosen to be the max relative to the row max.
      //
      if (upTriang[pivotRow][zeroColIdx] == 0.0)
      {
        throw(SINGERR());
      }
      factor = upTriang[scaleRow][zeroColIdx] / upTriang[pivotRow][zeroColIdx];
    
      //
      // Store the scaling factor in the upper triangular matrix for use later.
      // This makes the book keeping easy since it can be accessed using the 
      // row and zeroColIdx indeces.  Of course the matrix is no linger strictly 
      // upper traingular.
      //
      upTriang[scaleRow][zeroColIdx] = factor;
    
      //
      // Zero the elements in the pivot column in the remaining rows to create
      // the upper triangular matrix.
      //
      for (col = zeroColIdx + 1; col < cols; ++col)
      {
        upTriang[scaleRow][col] -= factor * upTriang[pivotRow][col];
    
      }

      #ifdef debugEn
      fprintf(fp, "p80 row = %d; factor = %7.2f;", scaleRow, factor);
      fprintf(fp, " upTriang(%d,:) = %7.2f %7.2f %7.2f %7.2f \n", row,
                  upTriang[scaleRow][0], upTriang[scaleRow][1], 
                  upTriang[scaleRow][2], upTriang[scaleRow][3]);
      #endif
    
    } // end for (rowIdx = zeroColIdx + 1; rowIdx < rows; ++rowIdx)
  }  // for (zeroColIdx = 0; zeroColIdx < cols - 1; ++zeroColIdx)

  #ifdef debugEn
  fprintf(fp, "p90 upTriang = \n");
  for (int dbRow = 0; dbRow < 4; ++dbRow)
  {
    for (int dbCol = 0; dbCol < 4; ++dbCol)
    {
      fprintf(fp, "%7.2f ", upTriang[dbRow][dbCol]); 
    }
    fprintf(fp, "\n");
  }
  #endif

  //
  // We now have an upper triangular representation of A in 
  //  A * X = b
  // But we have not operated on b.  Furthermore, what we want is inv(A) as in
  //  A * inv(A) = I
  // We'll brek this problem up into columns of inv(A) and I
  //  A * inv(A)(i) = I(i)
  // So we need to apply forward elimination processing to the columns of I.
  // Then proceed to back substitution
  //
  // The modified right hand side system of equations is stored in pRhs.
  //
  //   A * X = b (rhs)
  //
  pRhs = new double[rows];

  for (identElem = 0; identElem < rows; ++identElem)
  {
    //
    // Extract the appropriate column of the identify matrix for use as 
    // the right hand side of the system of equations.
    //
    for (row = 0; row < rows; ++row)
    {
      pRhs[row] = 0.0;
    }
    pRhs[identElem] = 1.0;

    //
    // Apply the same scaling used on the left hand side of the system
    // to the right hand side.
    //
    for (zeroColIdx = 0; zeroColIdx < rows-1; ++zeroColIdx)
    {
      pivotRow = pRowOrder[zeroColIdx];
      
      for (rowIdx = zeroColIdx + 1; rowIdx < rows; ++rowIdx)
      {
        row = pRowOrder[rowIdx];

        factor = upTriang[row][zeroColIdx];

        pRhs[row] -= factor * pRhs[pivotRow];
      }
    }

    //
    // Back substitution starting a the bottome of the triangular matrix.
    //
    row = pRowOrder[rows - 1];

    if (upTriang[row][rows-1] == 0.0)
    {
      throw(SINGERR());
    }

    result[rows-1][identElem] = pRhs[row] / upTriang[row][rows-1];

    for (rowIdx = rows-2; rowIdx >= 0; --rowIdx)
    {
      row = pRowOrder[rowIdx];
      sum = pRhs[row];
      
      for (col = rowIdx + 1; col < cols; ++col)
      {
        sum = sum - upTriang[row][col] * result[col][identElem];
      }
     
      if (upTriang[row][rowIdx] == 0.0)
      {
      throw(SINGERR());
      }
      result[rowIdx][identElem] = sum / upTriang[row][rowIdx];
    }
  }  // end for (identElem = 0; identElem < rows; ++identElem)

  delete [] pRhs;
  delete [] pRowOrder;
  delete [] pRowMaxes;

  #ifdef debugEn
  fclose(fp);
  #endif

  return(result);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x210, %rsp            # imm = 0x210
movq %rdi, -0xd0(%rbp)
movq %rdi, %rax
movq %rax, -0xc8(%rbp)
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq -0x10(%rbp), %rcx
movq %rcx, -0xc0(%rbp)
movl 0x8(%rcx), %eax
cmpl (%rcx), %eax
je 0x20f4c
movl $0x8, %edi
callq 0x3110
movq %rax, %rdi
movq %rdi, -0xd8(%rbp)
xorl %esi, %esi
movl $0x8, %edx
callq 0x3130
movq -0xd8(%rbp), %rdi
callq 0x23470
movq -0xd8(%rbp), %rdi
leaq 0xdd78(%rip), %rsi      # 0x2ecb8
leaq 0x2569(%rip), %rdx      # 0x234b0
callq 0x33b0
movq -0xc0(%rbp), %rax
movq -0xd0(%rbp), %rdi
movl $0x0, -0x14(%rbp)
movq $0x0, -0x20(%rbp)
movl $0x0, -0x24(%rbp)
movl $0x0, -0x28(%rbp)
movl $0x0, -0x2c(%rbp)
movq $0x0, -0x38(%rbp)
movq $0x0, -0x40(%rbp)
movq $0x0, -0x48(%rbp)
movq $0x0, -0x50(%rbp)
movq $0x0, -0x58(%rbp)
movl $0x0, -0x5c(%rbp)
movq $0x0, -0x68(%rbp)
movq $0x0, -0x70(%rbp)
movl $0x0, -0x74(%rbp)
movb $0x0, -0x75(%rbp)
movl (%rax), %edx
movl 0x8(%rax), %esi
xorps %xmm0, %xmm0
callq 0x1f2e0
movq -0xc0(%rbp), %rax
movl $0x0, -0x8c(%rbp)
movslq 0x8(%rax), %rax
movl $0x4, %ecx
mulq %rcx
movq %rax, %rdi
movq $-0x1, %rax
cmovoq %rax, %rdi
callq 0x3030
movq %rax, -0xe0(%rbp)
jmp 0x2100e
movq -0xc0(%rbp), %rax
movq -0xe0(%rbp), %rcx
movq %rcx, -0x48(%rbp)
movslq 0x8(%rax), %rax
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
movq $-0x1, %rax
cmovoq %rax, %rdi
callq 0x3030
movq %rax, -0xe8(%rbp)
jmp 0x21048
movq -0xc0(%rbp), %rsi
movq -0xe8(%rbp), %rax
movq %rax, -0x40(%rbp)
leaq -0xb8(%rbp), %rdi
callq 0x1f3e0
jmp 0x21068
movl $0x0, -0x5c(%rbp)
movq -0xc0(%rbp), %rcx
movl -0x5c(%rbp), %eax
cmpl 0x8(%rcx), %eax
jge 0x21184
movl -0x5c(%rbp), %edx
movq -0x48(%rbp), %rax
movslq -0x5c(%rbp), %rcx
movl %edx, (%rax,%rcx,4)
xorps %xmm0, %xmm0
movsd %xmm0, -0x68(%rbp)
movl $0x0, -0x14(%rbp)
movq -0xc0(%rbp), %rcx
movl -0x14(%rbp), %eax
cmpl (%rcx), %eax
jge 0x21164
movsd -0x68(%rbp), %xmm0
movsd %xmm0, -0xf8(%rbp)
movl -0x5c(%rbp), %esi
leaq -0xb8(%rbp), %rdi
callq 0x1fe60
movq %rax, -0xf0(%rbp)
jmp 0x210d6
movsd -0xf8(%rbp), %xmm0
movq -0xc0(%rbp), %rdi
movq -0xf0(%rbp), %rax
movslq -0x14(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm1
movaps 0x34f4(%rip), %xmm2     # 0x245f0
pand %xmm2, %xmm1
callq 0x21a90
movsd %xmm0, -0x100(%rbp)
jmp 0x2110f
movsd -0x100(%rbp), %xmm0
movsd %xmm0, -0x68(%rbp)
movl -0x14(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14(%rbp)
jmp 0x2109f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x98(%rbp)
movl %eax, -0x9c(%rbp)
jmp 0x21a75
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x98(%rbp)
movl %eax, -0x9c(%rbp)
leaq -0xb8(%rbp), %rdi
callq 0x1f580
jmp 0x21a75
movsd -0x68(%rbp), %xmm0
movq -0x40(%rbp), %rax
movslq -0x5c(%rbp), %rcx
movsd %xmm0, (%rax,%rcx,8)
movl -0x5c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x5c(%rbp)
jmp 0x2106f
movl $0x0, -0x8c(%rbp)
movq -0xc0(%rbp), %rcx
movl -0x8c(%rbp), %eax
movl (%rcx), %ecx
subl $0x1, %ecx
cmpl %ecx, %eax
jge 0x21536
xorps %xmm0, %xmm0
movsd %xmm0, -0x58(%rbp)
movl -0x8c(%rbp), %eax
movl %eax, -0x7c(%rbp)
movq -0xc0(%rbp), %rcx
movl -0x7c(%rbp), %eax
cmpl 0x8(%rcx), %eax
jge 0x212a5
movq -0x48(%rbp), %rax
movslq -0x7c(%rbp), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, -0x2c(%rbp)
movq -0x40(%rbp), %rax
movslq -0x2c(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0x21231
jp 0x21231
movl $0x8, %edi
callq 0x3110
movq %rax, %rdi
movq %rdi, -0x108(%rbp)
movq $0x0, (%rdi)
callq 0x23560
movq -0x108(%rbp), %rdi
leaq 0xdac8(%rip), %rsi      # 0x2ece8
leaq 0x2379(%rip), %rdx      # 0x235a0
callq 0x33b0
jmp 0x21a8d
movl -0x2c(%rbp), %esi
leaq -0xb8(%rbp), %rdi
callq 0x1fe60
movq %rax, -0x110(%rbp)
jmp 0x21249
movq -0x110(%rbp), %rax
movslq -0x8c(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm0
movq -0x40(%rbp), %rax
movslq -0x2c(%rbp), %rcx
divsd (%rax,%rcx,8), %xmm0
movaps 0x3380(%rip), %xmm1     # 0x245f0
pand %xmm1, %xmm0
movsd %xmm0, -0x50(%rbp)
movsd -0x50(%rbp), %xmm0
ucomisd -0x58(%rbp), %xmm0
jbe 0x21295
movsd -0x50(%rbp), %xmm0
movsd %xmm0, -0x58(%rbp)
movl -0x7c(%rbp), %eax
movl %eax, -0x80(%rbp)
jmp 0x21297
movl -0x7c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x7c(%rbp)
jmp 0x211b9
movq -0x48(%rbp), %rax
movslq -0x8c(%rbp), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, -0x74(%rbp)
movq -0x48(%rbp), %rax
movslq -0x80(%rbp), %rcx
movl (%rax,%rcx,4), %edx
movq -0x48(%rbp), %rax
movslq -0x8c(%rbp), %rcx
movl %edx, (%rax,%rcx,4)
movl -0x74(%rbp), %edx
movq -0x48(%rbp), %rax
movslq -0x80(%rbp), %rcx
movl %edx, (%rax,%rcx,4)
movq -0x48(%rbp), %rax
movslq -0x8c(%rbp), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, -0x28(%rbp)
movl -0x8c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x7c(%rbp)
movq -0xc0(%rbp), %rcx
movl -0x7c(%rbp), %eax
cmpl 0x8(%rcx), %eax
jge 0x21520
movq -0x48(%rbp), %rax
movslq -0x7c(%rbp), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, -0x88(%rbp)
movl -0x28(%rbp), %esi
leaq -0xb8(%rbp), %rdi
callq 0x1fe60
movq %rax, -0x118(%rbp)
jmp 0x21336
movq -0x118(%rbp), %rax
movslq -0x8c(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0x21393
jp 0x21393
movl $0x8, %edi
callq 0x3110
movq %rax, %rdi
movq %rdi, -0x120(%rbp)
movq $0x0, (%rdi)
callq 0x23560
movq -0x120(%rbp), %rdi
leaq 0xd966(%rip), %rsi      # 0x2ece8
leaq 0x2217(%rip), %rdx      # 0x235a0
callq 0x33b0
jmp 0x21a8d
movl -0x88(%rbp), %esi
leaq -0xb8(%rbp), %rdi
callq 0x1fe60
movq %rax, -0x128(%rbp)
jmp 0x213ae
movq -0x128(%rbp), %rax
movslq -0x8c(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm0
movsd %xmm0, -0x138(%rbp)
movl -0x28(%rbp), %esi
leaq -0xb8(%rbp), %rdi
callq 0x1fe60
movq %rax, -0x130(%rbp)
jmp 0x213e1
movsd -0x138(%rbp), %xmm0
movq -0x130(%rbp), %rax
movslq -0x8c(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, -0x20(%rbp)
movsd -0x20(%rbp), %xmm0
movsd %xmm0, -0x148(%rbp)
movl -0x88(%rbp), %esi
leaq -0xb8(%rbp), %rdi
callq 0x1fe60
movq %rax, -0x140(%rbp)
jmp 0x2142d
movq -0x140(%rbp), %rax
movsd -0x148(%rbp), %xmm0
movslq -0x8c(%rbp), %rcx
movsd %xmm0, (%rax,%rcx,8)
movl -0x8c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14(%rbp)
movq -0xc0(%rbp), %rcx
movl -0x14(%rbp), %eax
cmpl (%rcx), %eax
jge 0x21510
movsd -0x20(%rbp), %xmm0
movsd %xmm0, -0x158(%rbp)
movl -0x28(%rbp), %esi
leaq -0xb8(%rbp), %rdi
callq 0x1fe60
movq %rax, -0x150(%rbp)
jmp 0x2148b
movq -0x150(%rbp), %rax
movslq -0x14(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm0
movsd %xmm0, -0x168(%rbp)
movl -0x88(%rbp), %esi
leaq -0xb8(%rbp), %rdi
callq 0x1fe60
movq %rax, -0x160(%rbp)
jmp 0x214be
movq -0x160(%rbp), %rax
movsd -0x168(%rbp), %xmm2
movsd -0x158(%rbp), %xmm0
movslq -0x14(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm1
movq %xmm0, %rdx
movabsq $-0x8000000000000000, %rsi # imm = 0x8000000000000000
xorq %rsi, %rdx
movq %rdx, %xmm0
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, (%rax,%rcx,8)
movl -0x14(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14(%rbp)
jmp 0x21454
jmp 0x21512
movl -0x7c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x7c(%rbp)
jmp 0x212fa
jmp 0x21522
movl -0x8c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x8c(%rbp)
jmp 0x2118e
movq -0xc0(%rbp), %rax
movslq 0x8(%rax), %rax
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
movq $-0x1, %rax
cmovoq %rax, %rdi
callq 0x3030
movq %rax, -0x170(%rbp)
jmp 0x21565
movq -0x170(%rbp), %rax
movq %rax, -0x38(%rbp)
movl $0x0, -0x24(%rbp)
movq -0xc0(%rbp), %rcx
movl -0x24(%rbp), %eax
cmpl 0x8(%rcx), %eax
jge 0x219ec
movl $0x0, -0x5c(%rbp)
movq -0xc0(%rbp), %rcx
movl -0x5c(%rbp), %eax
cmpl 0x8(%rcx), %eax
jge 0x215bb
movq -0x38(%rbp), %rax
movslq -0x5c(%rbp), %rcx
xorps %xmm0, %xmm0
movsd %xmm0, (%rax,%rcx,8)
movl -0x5c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x5c(%rbp)
jmp 0x21591
movq -0x38(%rbp), %rax
movslq -0x24(%rbp), %rcx
movsd 0x2a3d(%rip), %xmm0     # 0x24008
movsd %xmm0, (%rax,%rcx,8)
movl $0x0, -0x8c(%rbp)
movq -0xc0(%rbp), %rcx
movl -0x8c(%rbp), %eax
movl 0x8(%rcx), %ecx
subl $0x1, %ecx
cmpl %ecx, %eax
jge 0x216ca
movq -0x48(%rbp), %rax
movslq -0x8c(%rbp), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, -0x28(%rbp)
movl -0x8c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x7c(%rbp)
movq -0xc0(%rbp), %rcx
movl -0x7c(%rbp), %eax
cmpl 0x8(%rcx), %eax
jge 0x216b4
movq -0x48(%rbp), %rax
movslq -0x7c(%rbp), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, -0x5c(%rbp)
movl -0x5c(%rbp), %esi
leaq -0xb8(%rbp), %rdi
callq 0x1fe60
movq %rax, -0x178(%rbp)
jmp 0x2164b
movq -0x178(%rbp), %rax
movslq -0x8c(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm0
movsd %xmm0, -0x20(%rbp)
movsd -0x20(%rbp), %xmm0
movq -0x38(%rbp), %rax
movslq -0x28(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm2
movq -0x38(%rbp), %rax
movslq -0x5c(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm1
movq %xmm0, %rdx
movabsq $-0x8000000000000000, %rsi # imm = 0x8000000000000000
xorq %rsi, %rdx
movq %rdx, %xmm0
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, (%rax,%rcx,8)
movl -0x7c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x7c(%rbp)
jmp 0x21612
jmp 0x216b6
movl -0x8c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x8c(%rbp)
jmp 0x215da
movq -0xc0(%rbp), %rcx
movq -0x48(%rbp), %rax
movl 0x8(%rcx), %ecx
decl %ecx
movslq %ecx, %rcx
movl (%rax,%rcx,4), %eax
movl %eax, -0x5c(%rbp)
movl -0x5c(%rbp), %esi
leaq -0xb8(%rbp), %rdi
callq 0x1fe60
movq %rax, -0x180(%rbp)
jmp 0x216fb
movq -0x180(%rbp), %rax
movq -0xc0(%rbp), %rcx
movl 0x8(%rcx), %ecx
subl $0x1, %ecx
movslq %ecx, %rcx
movsd (%rax,%rcx,8), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0x21761
jp 0x21761
movl $0x8, %edi
callq 0x3110
movq %rax, %rdi
movq %rdi, -0x188(%rbp)
movq $0x0, (%rdi)
callq 0x23560
movq -0x188(%rbp), %rdi
leaq 0xd598(%rip), %rsi      # 0x2ece8
leaq 0x1e49(%rip), %rdx      # 0x235a0
callq 0x33b0
jmp 0x21a8d
movq -0x38(%rbp), %rax
movslq -0x5c(%rbp), %rcx
movl %ecx, %esi
movsd (%rax,%rcx,8), %xmm0
movsd %xmm0, -0x198(%rbp)
leaq -0xb8(%rbp), %rdi
callq 0x1fe60
movq %rax, -0x190(%rbp)
jmp 0x2178d
movq -0xd0(%rbp), %rdi
movsd -0x198(%rbp), %xmm0
movq -0x190(%rbp), %rax
movq -0xc0(%rbp), %rcx
movl 0x8(%rcx), %esi
decl %esi
movslq %esi, %rcx
movsd (%rax,%rcx,8), %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, -0x1a8(%rbp)
callq 0x1fe60
movq %rax, -0x1a0(%rbp)
jmp 0x217d1
movq -0xc0(%rbp), %rax
movq -0x1a0(%rbp), %rcx
movsd -0x1a8(%rbp), %xmm0
movslq -0x24(%rbp), %rdx
movsd %xmm0, (%rcx,%rdx,8)
movl 0x8(%rax), %eax
subl $0x2, %eax
movl %eax, -0x7c(%rbp)
cmpl $0x0, -0x7c(%rbp)
jl 0x219dc
movq -0x48(%rbp), %rax
movslq -0x7c(%rbp), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, -0x5c(%rbp)
movq -0x38(%rbp), %rax
movslq -0x5c(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm0
movsd %xmm0, -0x70(%rbp)
movl -0x7c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14(%rbp)
movq -0xc0(%rbp), %rcx
movl -0x14(%rbp), %eax
cmpl (%rcx), %eax
jge 0x218e4
movsd -0x70(%rbp), %xmm0
movsd %xmm0, -0x1b8(%rbp)
movl -0x5c(%rbp), %esi
leaq -0xb8(%rbp), %rdi
callq 0x1fe60
movq %rax, -0x1b0(%rbp)
jmp 0x21863
movq -0xd0(%rbp), %rdi
movq -0x1b0(%rbp), %rax
movslq -0x14(%rbp), %rcx
movl %ecx, %esi
movsd (%rax,%rcx,8), %xmm0
movsd %xmm0, -0x1c8(%rbp)
callq 0x1fe60
movq %rax, -0x1c0(%rbp)
jmp 0x21892
movsd -0x1b8(%rbp), %xmm1
movsd -0x1c8(%rbp), %xmm0
movq -0x1c0(%rbp), %rax
movslq -0x24(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm2
movq %xmm0, %rax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
xorq %rcx, %rax
movq %rax, %xmm0
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, -0x70(%rbp)
movl -0x14(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14(%rbp)
jmp 0x2182c
movl -0x5c(%rbp), %esi
leaq -0xb8(%rbp), %rdi
callq 0x1fe60
movq %rax, -0x1d0(%rbp)
jmp 0x218fc
movq -0x1d0(%rbp), %rax
movslq -0x7c(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0x21956
jp 0x21956
movl $0x8, %edi
callq 0x3110
movq %rax, %rdi
movq %rdi, -0x1d8(%rbp)
movq $0x0, (%rdi)
callq 0x23560
movq -0x1d8(%rbp), %rdi
leaq 0xd3a3(%rip), %rsi      # 0x2ece8
leaq 0x1c54(%rip), %rdx      # 0x235a0
callq 0x33b0
jmp 0x21a8d
movsd -0x70(%rbp), %xmm0
movsd %xmm0, -0x1e8(%rbp)
movl -0x5c(%rbp), %esi
leaq -0xb8(%rbp), %rdi
callq 0x1fe60
movq %rax, -0x1e0(%rbp)
jmp 0x2197b
movq -0xd0(%rbp), %rdi
movsd -0x1e8(%rbp), %xmm0
movq -0x1e0(%rbp), %rax
movslq -0x7c(%rbp), %rcx
movl %ecx, %esi
movsd (%rax,%rcx,8), %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, -0x1f8(%rbp)
callq 0x1fe60
movq %rax, -0x1f0(%rbp)
jmp 0x219b6
movq -0x1f0(%rbp), %rax
movsd -0x1f8(%rbp), %xmm0
movslq -0x24(%rbp), %rcx
movsd %xmm0, (%rax,%rcx,8)
movl -0x7c(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x7c(%rbp)
jmp 0x217f9
jmp 0x219de
movl -0x24(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x24(%rbp)
jmp 0x21577
movq -0x38(%rbp), %rax
movq %rax, -0x200(%rbp)
cmpq $0x0, %rax
je 0x21a09
movq -0x200(%rbp), %rdi
callq 0x32f0
movq -0x48(%rbp), %rax
movq %rax, -0x208(%rbp)
cmpq $0x0, %rax
je 0x21a26
movq -0x208(%rbp), %rdi
callq 0x32f0
movq -0x40(%rbp), %rax
movq %rax, -0x210(%rbp)
cmpq $0x0, %rax
je 0x21a43
movq -0x210(%rbp), %rdi
callq 0x32f0
movb $0x1, -0x75(%rbp)
leaq -0xb8(%rbp), %rdi
callq 0x1f580
testb $0x1, -0x75(%rbp)
jne 0x21a65
movq -0xd0(%rbp), %rdi
callq 0x1f580
movq -0xc8(%rbp), %rax
addq $0x210, %rsp            # imm = 0x210
popq %rbp
retq
movq -0xd0(%rbp), %rdi
callq 0x1f580
movq -0x98(%rbp), %rdi
callq 0x33d0
nopl (%rax)