- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This function calculates determinant of a matrix:
real*8 function mklDet(A) real*8, intent(in), dimension(:,:) :: A !< input matrix A real*8, dimension(size(A,1)) :: ipiv !! pivot indices integer N, info, i !> dimension, status N = size(A, 1) ! DGETRF computes an LU factorization of a general M-by-N matrix A ! using partial pivoting with row interchanges. call DGETRF(n, n, A, n, ipiv, info) !< This part of code by adopted from intel software forum topic 309460 mklDet = 0.d0 if (info > 0) then return else if (info < 0) then print *, 'Fatal error calculating determinant!' end if mklDet = 1.d0 do i = 1, n if (ipiv(i).ne.i) then mklDet = -mklDet * a(i,i) else mklDet = mklDet * a(i,i) endif end do !> end function mklDet
Now if we try to calculate determinant of a matrix with which should be zero:
!! [[6.d10, 3.d10, 5.d10]; !! [4.d10, 4.d10, 7.d10]; !! [12.d10, 6.d10, 10.d10]];
print *, 'zero determinant' , mklDet(reshape((/ 6.d10, 3.d10, 5.d10, 4.d10, 4.d10, 7.d10, 12.d10, 6.d10, 10.d10 /),(/3, 3/)))
as you can see the outcome is a very large number and not zero:
zero determinant -5.329070518200751E+015
but if we use smaller numbers in the matrix
!! [[6., 3., 5.]; !! [4., 4., 7.]; !! [12., 6., 10.]];
print *, 'zero determinant' , mklDet(reshape((/ 6.d0, 3.d0, 5.d0, 4.d0, 4.d0, 7.d0, 12.d0, 6.d0, 10.d0 /),(/3, 3/)))
The outcome is much closer to zero:
zero determinant 1.065814103640150E-014
How do I improve the accuracy of my calculations?
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Update: When I try same function with quad precision the error is exactly zero:
print *, 'zero determinant double precision' , dblMklDet(reshape((/ 6.d0, 3.d0, 5.d0, 4.d0, 4.d0, 7.d0, 12.d0, 6.d0, 10.d0 /),(/3, 3/))) print *, 'zero determinant quad precision' , qprMklDet(reshape((/ 6.q0, 3.q0, 5.q0, 4.q0, 4.q0, 7.q0, 12.q0, 6.q0, 10.q0 /),(/3, 3/)))
The output is:
zero determinant double precision 1.065814103640150E-014 zero determinant quad precision 0.000000000000000000000000000000000E+0000
I don't understand what has caused the problem in double precision.
Here is the source for quad precision version of my MklDet function:
real(qp) function qprMklDet(A) real(qp), intent(in), dimension(:,:) :: A !< input matrix A real(qp), dimension(size(A,1)) :: ipiv !! pivot indices integer N, info, i !> dimension, status N = size(A, 1) ! DGETRF computes an LU factorization of a general M-by-N matrix A ! using partial pivoting with row interchanges. call DGETRF(n, n, A, n, ipiv, info) !< This part of code by adopted from intel software forum topic 309460 qprMklDet = 0.d0 if (info > 0) then return else if (info < 0) then print *, 'Fatal error calculating determinant!' end if qprMklDet = 1.d0 do i = 1, n if (ipiv(i).ne.i) then qprMklDet = -qprMklDet * a(i,i) else qprMklDet = qprMklDet * a(i,i) endif end do !> end function qprMklDet
And qp is
use, intrinsic :: iso_fortran_env, only: REAL64, REAL128 implicit none !========================================== ! C o n s t a n t s !========================================== !integer, parameter :: sp = REAL32 integer, parameter :: dp = REAL64 integer, parameter :: qp = REAL128 !------------------------------------------
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
Det calculation using LU is not stable numerically. E.g., it's clearly described at matlab page of Det function here:
https://www.mathworks.com/help/matlab/ref/det.html
So, please just avoid calling LU with singular matrices. You can first use other functions like ?gecon in order to estimate condition number of the matrix.
Regards,
Konstantin
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page