am1x icon

lab22b

am1x | PRO | 02/29/24 06:10:14 PM UTC | 0 ⭐ | 514 👁️ | Never ⏰ | []
Fortran |

5.06 KB

|

Fixit

|

0 👍

/

0 👎

module methods
    implicit none
    contains
    
    function f(x) result(y) !Функция исходная(с пограшностями) !ОК
        real(8), intent(in) ::  x
        real(8) :: y
        !y = x**2d0 + 1d0 - (4d0*datan(1d0)/2d0 - x - (x**3d0)/6d0)
        y = x**2d0 + 1d0 - dacos(x)
        !y = x**2d0
    end function
    
    function e(x,n) result(y) !Базисная функция !ОК
        integer, intent(in) :: n
        real(8), intent(in) ::  x
        real(8) :: y
        y = x**real(n-1,8)
        !y = dcos(real(n-1,8)*dacos(x))
    end function
    
    function pf(res,x,n) result(y) !Вычисление приближения в точке !ОК
        integer, intent(in) :: n
        real(8), intent(in) ::  x
        integer :: i
        real(8), dimension(:) :: res(n)
        real(8) :: y
        y=0d0
        do i = 1,n
            y = y + res(i)*e(x,i)
        end do
    end function
    subroutine cholesky1(A,b,n,res) !Разложение Холецкого
        real(8),dimension(:,:) :: A
        real(8),dimension(:) :: b, res
        real(8), allocatable :: y1(:)
        real(8) :: sum
        integer, intent(in) :: n
        integer :: i,j,P
        integer :: info
        allocate(y1(n))
        !L = 0d0
        !L = A
        !do i = 1, n !i столбец 
            !do j = i, n !j строка
                !Вычисление суммы
                !sum = 0d0
                !do p = 1, i-1
                    !sum = sum + A(i,p)*A(j,p)
                !end do
                !Разложение                
                !if (j==i)  then
                    !A(i,i) = dsqrt(A(i,i) - sum)
                !else
                    !A(j,i) = (A(j,i) - sum)/A(i,i)
                !end if
            !end do
        !end do
        call DPOTRF("L", n, A, n,info)
        write(*,*) "info", info
        do i = 1,n-1
            A(i,i+1:) = 0d0
        end do
        !Решаем Ly = b
        y1 = 0d0
        do i = 1,n
            do j = 1, i-1
                b(i) = b(i) - A(i,j)*y1(j)
            end do
            y1(i) = b(i)/A(i,i)
        end do
        !Решаем (L**T)x = y
        A = transpose(A)
        res = 0d0
        do i = n,1,-1
            do j = n, i+1,-1
                y1(i) = y1(i) - A(i,j)*res(j)
            end do
            res(i) = y1(i)/A(i,i)
        end do
        !write(*,*) "RESULT", norm2(MATMUL(A,res) - b)
        deallocate(y1)
    end subroutine
    
    subroutine gengrid(grid,n,a,b) !Генерация равномерной сетки !ОК
        integer, intent(in) :: n
        real(8),intent(in) :: a, b
        real(8), dimension(:,:) :: grid(n,4)
        real(8) :: AA
        integer :: i
        !Генерация сеток
        grid = 0d0
        do i = 1,n
            grid(i,1) = (b-a)*real(i,8)/real(n-1,8) + a - (b-a)/real(n-1,8)
            grid(i,2) = f(grid(i,1))
        end do
        grid(:,3) = grid(:,2)
        
        !Выбросы(промахи)
        !AA = dabs(maxval(grid(:,2)) - minval(grid(:,2))) !Амплитуда
        !grid(1,3) = grid(1,3)*2d0*AA
        !grid(2,3) = grid(2,3)*3d0*AA
        !grid(4,3) = grid(4,3)*4d0*AA
    end subroutine
    
    subroutine MNK(grid,w,n,m,res) !метод наименьших квадратов с конкректным весами.
        integer, intent(in) :: n, m !n - число узлов m - степень строящегося полинома
        integer :: i,j,k
        real(8), dimension(:,:) :: grid(n,4)
        real(8), dimension(:) :: w(n), res(n) !ВЕСА и решение
        real(8), allocatable :: A(:,:), b(:)
        allocate(A(m,m),b(m))
        !Составление матрицы СЛАУ с весами
        b = 0d0
        A = 0d0
        do k = 1, m
            do i = 1,n
                b(k) = b(k) + w(i)*grid(i,3)*e(grid(i,1),k)
            end do
            do j = 1,m
                do i = 1,n
                    A(k,j) = A(k,j) + w(i)*e(grid(i,1),j)*e(grid(i,1),k)
                end do
            end do
        end do
        !write(*,"(3f14.7)") (A(i,:),i=1,m)
        call cholesky1(A,b,m,res) !Решение СЛАУ
        deallocate(A, b)
    end subroutine
    
    subroutine coefget(grid,res,m,n)
        integer, intent(in) :: n, m !n - число узлов m - степень строящегося полинома
        integer :: i,j,k
        real(8), dimension(:,:) :: grid(n,4)
        real(8), dimension(:) :: w(n), res(n) !ВЕСА и решение
        real(8), allocatable :: epsi(:)
        real(8) :: eps
        allocate(epsi(n))
        eps = 1e-14
        
        w = 1d0
        do while(maxval(epsi) > eps)
            res = 0d0
            call MNK(grid,w,n,m,res)
            do i = 1,n
                epsi(i) = dabs(grid(i,3) - pf(res,grid(i,3),n))
                w(i) = 1d0/(epsi(i)*2d0 + eps)
            end do
        end do
        deallocate(epsi)
    end subroutine
end module

Comments