// File: DavidLBruce[P]sim3dof/Matrix/build/../../Matrix/src/Matrix.cpp
// Function: Matrix::Det()
double Matrix::Det()
{
  if (rows != cols)
  {
    throw(DIMERR());
  }

  double cofactor;
  int    col(0);
  bool   done(false);
  int    maxZeroRow(0);
  double minor(0.0);
  int    prevZeroCnt(0);
  double result(0.0);
  int    row(0);
  double sign(0.0);
  int    zeroCnt(0);

  //
  // Handle trivial cases.
  //
  if (rows == 1)
  {
    result = *pData;
    done = true;
  }

  if (!done)
  {
    if (rows == 2)
    {
      result = (*this)[0][0] * (*this)[1][1] - (*this)[0][1] * (*this)[1][0];
      done = true;
    }
  }

  if (!done)
  {
    //
    // Find the row with the most zero elements.
    //
    for (row = 0; row < rows; ++row)
    {
      zeroCnt = 0.0;
      for (col = 0; col < cols; ++col)
      {
        if (WithinTolerance((*this)[row][col],  0.0))
        {
          ++zeroCnt;
        }
      }
      if (zeroCnt == cols)
      {
        result = 0.0;
        done = true;
        break;  // exit loop for (row = 0; row < rows; ++row)
      }
      else if (zeroCnt > prevZeroCnt)
      {
        maxZeroRow = row;
        prevZeroCnt = zeroCnt;
      }
    }
    
    row = maxZeroRow;

  } // end if (!done)

  //
  // Sum the products of the selected row elements and their cofactors.
  //
  if (!done)
  {  
    for (col = 0; col < cols; ++col)
    {
      if (!WithinTolerance(pData[row*cols+col], 0.0))
      { 
        //
        // Odd powers of -1 are negative 1, even powers are positive 1.
        //
        sign = (row + col) % 2 == 0 ? 1.0 : -1.0;

        minor = Minor(row, col);
    
        cofactor = sign * pData[row*cols+col] * minor;
    
        result += cofactor;
      }
    }
  }  // end if (!done)

  return result;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x90, %rsp
movq %rdi, -0x8(%rbp)
movq -0x8(%rbp), %rcx
movq %rcx, -0x58(%rbp)
movl 0x8(%rcx), %eax
cmpl (%rcx), %eax
je 0x21ecb
movl $0x8, %edi
callq 0x3110
movq %rax, %rdi
movq %rdi, -0x60(%rbp)
xorl %esi, %esi
movl $0x8, %edx
callq 0x3130
movq -0x60(%rbp), %rdi
callq 0x23470
movq -0x60(%rbp), %rdi
leaq 0xcdf9(%rip), %rsi      # 0x2ecb8
leaq 0x15ea(%rip), %rdx      # 0x234b0
callq 0x33b0
movq -0x58(%rbp), %rax
movl $0x0, -0x14(%rbp)
movb $0x0, -0x15(%rbp)
movl $0x0, -0x1c(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0x28(%rbp)
movl $0x0, -0x2c(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0x38(%rbp)
movl $0x0, -0x3c(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0x48(%rbp)
movl $0x0, -0x4c(%rbp)
cmpl $0x1, 0x8(%rax)
jne 0x21f29
movq -0x58(%rbp), %rax
movq 0x10(%rax), %rax
movsd (%rax), %xmm0
movsd %xmm0, -0x38(%rbp)
movb $0x1, -0x15(%rbp)
testb $0x1, -0x15(%rbp)
jne 0x21fcd
movq -0x58(%rbp), %rax
cmpl $0x2, 0x8(%rax)
jne 0x21fcb
movq -0x58(%rbp), %rdi
xorl %esi, %esi
callq 0x1fe60
movq -0x58(%rbp), %rdi
movsd (%rax), %xmm0
movsd %xmm0, -0x70(%rbp)
movl $0x1, %esi
callq 0x1fe60
movq -0x58(%rbp), %rdi
movsd 0x8(%rax), %xmm0
movsd %xmm0, -0x68(%rbp)
xorl %esi, %esi
callq 0x1fe60
movq -0x58(%rbp), %rdi
movsd 0x8(%rax), %xmm0
movsd %xmm0, -0x78(%rbp)
movl $0x1, %esi
callq 0x1fe60
movsd -0x78(%rbp), %xmm1
movsd -0x70(%rbp), %xmm0
movsd -0x68(%rbp), %xmm2
mulsd (%rax), %xmm1
movq %xmm1, %rax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
xorq %rcx, %rax
movq %rax, %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, -0x38(%rbp)
movb $0x1, -0x15(%rbp)
jmp 0x21fcd
testb $0x1, -0x15(%rbp)
jne 0x2208c
movl $0x0, -0x3c(%rbp)
movq -0x58(%rbp), %rcx
movl -0x3c(%rbp), %eax
cmpl 0x8(%rcx), %eax
jge 0x22086
movl $0x0, -0x4c(%rbp)
movl $0x0, -0x14(%rbp)
movq -0x58(%rbp), %rcx
movl -0x14(%rbp), %eax
cmpl (%rcx), %eax
jge 0x22047
movq -0x58(%rbp), %rdi
movl -0x3c(%rbp), %esi
callq 0x1fe60
movq -0x58(%rbp), %rdi
movslq -0x14(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm0
xorps %xmm2, %xmm2
movaps %xmm2, %xmm1
callq 0x21df0
testb $0x1, %al
jne 0x22031
jmp 0x2203a
movl -0x4c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x4c(%rbp)
jmp 0x2203c
movl -0x14(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14(%rbp)
jmp 0x21ffc
movq -0x58(%rbp), %rcx
movl -0x4c(%rbp), %eax
cmpl (%rcx), %eax
jne 0x22060
xorps %xmm0, %xmm0
movsd %xmm0, -0x38(%rbp)
movb $0x1, -0x15(%rbp)
jmp 0x22086
movl -0x4c(%rbp), %eax
cmpl -0x2c(%rbp), %eax
jle 0x22074
movl -0x3c(%rbp), %eax
movl %eax, -0x1c(%rbp)
movl -0x4c(%rbp), %eax
movl %eax, -0x2c(%rbp)
jmp 0x22076
jmp 0x22078
movl -0x3c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x3c(%rbp)
jmp 0x21fde
movl -0x1c(%rbp), %eax
movl %eax, -0x3c(%rbp)
testb $0x1, -0x15(%rbp)
jne 0x22180
movl $0x0, -0x14(%rbp)
movq -0x58(%rbp), %rcx
movl -0x14(%rbp), %eax
cmpl (%rcx), %eax
jge 0x2217e
movq -0x58(%rbp), %rdi
movq 0x10(%rdi), %rax
movl -0x3c(%rbp), %ecx
imull (%rdi), %ecx
addl -0x14(%rbp), %ecx
movslq %ecx, %rcx
movsd (%rax,%rcx,8), %xmm0
xorps %xmm2, %xmm2
movaps %xmm2, %xmm1
callq 0x21df0
testb $0x1, %al
jne 0x2216e
movl -0x3c(%rbp), %eax
addl -0x14(%rbp), %eax
movl $0x2, %ecx
cltd
idivl %ecx
movsd 0x1f1a(%rip), %xmm0     # 0x24008
movsd 0x1f1a(%rip), %xmm1     # 0x24010
movsd %xmm1, -0x88(%rbp)
cmpl $0x0, %edx
movsd %xmm0, -0x80(%rbp)
je 0x22115
movsd -0x88(%rbp), %xmm0
movsd %xmm0, -0x80(%rbp)
movq -0x58(%rbp), %rdi
movsd -0x80(%rbp), %xmm0
movsd %xmm0, -0x48(%rbp)
cvtsi2sdl -0x3c(%rbp), %xmm0
cvtsi2sdl -0x14(%rbp), %xmm1
callq 0x22190
movq -0x58(%rbp), %rdx
movsd %xmm0, -0x28(%rbp)
movsd -0x48(%rbp), %xmm0
movq 0x10(%rdx), %rax
movl -0x3c(%rbp), %ecx
imull (%rdx), %ecx
addl -0x14(%rbp), %ecx
movslq %ecx, %rcx
mulsd (%rax,%rcx,8), %xmm0
mulsd -0x28(%rbp), %xmm0
movsd %xmm0, -0x10(%rbp)
movsd -0x10(%rbp), %xmm0
addsd -0x38(%rbp), %xmm0
movsd %xmm0, -0x38(%rbp)
jmp 0x22170
movl -0x14(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14(%rbp)
jmp 0x2209d
jmp 0x22180
movsd -0x38(%rbp), %xmm0
addq $0x90, %rsp
popq %rbp
retq
nop