2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




На страницу Пред.  1, 2
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение03.11.2015, 15:50 
Аватара пользователя
Dmitriy40 в сообщении #1069837 писал(а):
Пока не нужны огромные (миллиарды элементов) массивы булевых переменных, в таком случае расходы памяти становятся неприемлимыми.

А они не нужны практически никогда. Практика показывает, что большие массивы нужны либо чисел (в расчётных задачах), либо нечисловых типов (в базах данных), и булевые там если и встречаются, то как сбоку припёка к чему-нибудь основному, и накладных расходов дают приемлемые проценты.

-- 03.11.2015 15:53:10 --

GAA в сообщении #1069866 писал(а):
К слову, где могут возникать проблемы.
При чтении двоичных файлов (записан в программе, написанной на одном компиляторе, а читается во второй программе, написанной на другом).

Ужас какой. В таких случаях надо тщательно прописывать формат файла, вплоть до битового уровня.

 
 
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение04.11.2015, 20:52 
В общем, в очередной раз, чтобы темы не плодить, напишу здесь. Следуя совету товарища Pphantom, отошёл от использования составных типов и перешёл к двумерным массивам. То, что написано на данный момент, по логике должно создавать некоторое (определяемое из характеристик системы) число пор, расположенных хаотично и имеющих некоторое дискретное распределение по радиусам. Это работает вроде как нормально. Дальше должны определяться кластеры этих самых пор, за это отвечает подпрограмма findclusters. И вот тут уже всё не очень хорошо. Программа упорно выдаёт ошибку stack overflow (как я понимаю, это типичная ошибка в программах новичков, поскольку так назван крупнейший ресурс типа вопросы-ответы). Я, было дело, грешил на переполнение памяти из-за массива indx1, но его подчистка в конце итерации не помогла. В чём моя ошибка?

Код под катом или по ссылке.

(Оффтоп)

код: [ скачать ] [ спрятать ]
Используется синтаксис Fortran
   
    subroutine geometry_definition(lattice,prob_distr,M,N,L)
    implicit none
    integer(8) N
    integer s, p, M
    real, parameter :: Pi = 3.141593
    real L
    real(8) phi, Q
    real, dimension(4,N) :: lattice
    real, dimension(M,2) :: prob_distr
    call random_seed()
    call random_number(lattice(1:3,:))          
    lattice(1:3,:)=L*lattice(1:3,:)                                                         ! "Разбрасывание" координат пор                                              

    do s = 1,N                                                                              ! "Разбрасывание" радиусов пор
        call random_number(Q)        
        if &#40;Q < prob_distr&#40;1,2&#41;&#41; then
            lattice&#40;4,s&#41; = prob_distr&#40;1,1&#41;
        else
                do p = 2, M
                if &#40;&#40;Q < sum&#40;prob_distr&#40;1:p,2&#41;&#41;&#41; .and. &#40;Q > sum&#40;prob_distr&#40;1:&#40;p-1&#41;,2&#41;&#41;&#41;&#41; then
                lattice&#40;4,s&#41; = prob_distr&#40;p,1&#41;
                end if
            end do
        end if
    end do
   
    end subroutine geometry_definition
   
    subroutine findclusters&#40;N,R_max,lattice&#41;
    implicit none
    integer&#40;8&#41; N
    integer i, p, j, l, q
    integer :: k = 1
    real R_max, R
    real, dimension&#40;5,N&#41;::lattice&#40;5,N&#41;, locations&#40;N,3&#41;, distances&#40;N&#41;, indx&#40;N&#41;, radius_vectors&#40;N,3&#41;
    integer, dimension&#40;:&#41;,allocatable::indx1
   
    indx = &#40;/&#40;q,q=1,N&#41;/&#41;
    lattice&#40;5,:&#41; = 0
    do l = 1, N  
        do p = 1, 3
            locations&#40;l,p&#41; = lattice&#40;p,l&#41;                                                                  ! Задание матрицы координат пор              
        end do                                                                            
    end do

    do i=1, N-1                                                                                                                            
            do p = 1, 3                                                                                    
                radius_vectors&#40;:,p&#41; = locations&#40;:,p&#41; - locations&#40;i,p&#41;                                      ! Определение матрицы радиус-векторов для текущей поры
            end do
        distances = sqrt&#40;sum&#40;&#40;radius_vectors&#41;**2, dim = 1&#41;&#41;                               ! Определение матрицы расстояний от текущей поры до всех остальных &#40;включая "текущую"&#41;                                                              ! Массив индексов всех пор
        allocate&#40;indx1&#40;count&#40;distances < 2*R_max&#41; - 1&#41;&#41;                                   ! Выделение памяти для массива индексов потенциальных соседей текущей поры indx1
        indx1 = pack&#40;indx, distances < 2*R_max .and. distances /= 0&#41;
        do p = 1,size&#40;indx1,1&#41;
                j = indx1&#40;p&#41;
                R = sqrt&#40;sum&#40;&#40;lattice&#40;1:3,i&#41; - lattice&#40;1:3,j&#41;&#41;**2&#41;&#41;
            if &#40;R < &#40;lattice&#40;4,i&#41; + lattice&#40;4,j&#41;&#41;&#41; then
                if &#40;&#40;lattice&#40;5,i&#41; == 0&#41; .and. &#40;lattice&#40;5,j&#41; == 0&#41;&#41; then                   ! Если поры соединены и не принадлежат ни одному из кластеров, они образуют новый кластер
                    lattice&#40;5,i&#41; = k                                                  
                    lattice&#40;5,j&#41; = k
                    k = k + 1
                else if &#40;&#40;lattice&#40;5,i&#41; /= 0&#41; .and. &#40;lattice&#40;5,j&#41; == 0&#41;&#41; then              ! Если одна из пор уже принадлежит какому-либо кластеру, а другая - нет, то
                    lattice&#40;5,j&#41; = lattice&#40;5,i&#41;                                           ! пора без кластера присоединяется к кластеру другой
                else if &#40;&#40;lattice&#40;5,i&#41; == 0&#41; .and. &#40;lattice&#40;5,j&#41; /= 0&#41;&#41; then
                    lattice&#40;5,i&#41; = lattice&#40;5,j&#41;
                else if &#40;&#40;lattice&#40;5,j&#41; /= 0&#41; .and. &#40;lattice&#40;5,i&#41; /= 0&#41; .and. &#40;lattice&#40;5,j&#41; /= lattice&#40;5,i&#41;&#41;&#41; then                       ! Если же обе поры являются частью кластеров &#40;разных&#41;,
                     where&#40;lattice&#40;5,:&#41; == max&#40;lattice&#40;5,i&#41;,lattice&#40;5,j&#41;&#41;&#41; lattice&#40;5,:&#41; = min&#40;lattice&#40;5,i&#41;,lattice&#40;5,j&#41;&#41;                ! то происходит объединение кластеров в тот, что имел меньший индекс                                                                                                            ! то происходит объединение кластеров в тот, что имел меньший индекс
                end if  
             end if
        end do
        deallocate&#40;indx1&#41;
    end do
   
    end subroutine findclusters
   

   
    program experiment
    implicit none
    integer&#40;8&#41; N                                                                            ! Число пор
    integer k                                                                                                                                                
    real, parameter :: Pi = 3.141593
    real L, phi, V_avg, R_max
    real, dimension&#40;:,:&#41;, allocatable :: lattice
    real, dimension&#40;:,:&#41;, allocatable :: prob_distr                                         ! Распределение пор по радиусам
    print*, &#39;Enter the parameters of your system&#39;
    print*, &#39;L =&#39;                                                                           ! Размер системы    
    read*, L    
    print*, &#39;phi =&#39;                                                                         ! Пористость системы
    read*, phi
    print*, &#39;How many points will be in your distribution?&#39;
    read*, k
    allocate&#40;prob_distr&#40;k,2&#41;&#41;
    print*, &#39;Enter the points of your distribution. First row is for radiuses, second is for probabilities&#39;
    1 read*, prob_distr
        if &#40;sum&#40;prob_distr&#40;:,2&#41;&#41; /= 1&#41; then
            print*, &#39;The probabilities of all possible events must total to 1. Try again&#39;
            goto 1
        end if
    R_max = maxval&#40;prob_distr&#40;:,1&#41;&#41;                                                         ! Максимально возможный радиус поры
    V_avg = &#40;sum&#40;&#40;&#40;prob_distr&#40;:,1&#41;&#41;**3&#41;*prob_distr&#40;:,2&#41;&#41;&#41;*4*Pi/3                            ! Средне значение объёма поры
    N = nint&#40;&#40;L**3*log&#40;1/&#40;1-phi&#41;&#41;&#41;/V_avg&#41;
    allocate&#40;lattice&#40;4,N&#41;&#41;
    call geometry_definition&#40;lattice,prob_distr,size&#40;prob_distr&#40;:,1&#41;&#41;,N,L&#41;
    call findclusters&#40;N,R_max,lattice&#41;
    pause
    end      
 

P.S. Ну и вообще, может, какие-нибудь замечания по коду есть, я бы с радостью послушал. :-)
(в частности, есть ощущение, что многие операции с массивами можно сделать значительно проще и элегантнее, чем у меня, но у меня при любых попытках что-нибудь подсократить начинал жаловаться компилятор)

 
 
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение04.11.2015, 21:35 
То, что "под катом", малочитаемо (но скачать код можно). Для поиска ошибок (и вообще удобства работы) сначала стоит записать вводимые параметры в текстовый файл и читать оттуда, а не вводить каждый раз вручную. Вообще это некое общее правило хорошего стиля - программа не должна требовать ввода чего-либо с клавиатуры во время работы и не должна выводить на экран ничего, кроме кратких диагностических сообщений, все содержательное - тоже только в файл. Сейчас же понять, что происходит, сложно хотя бы потому, что неизвестно, что именно нужно вводить.

А так... беглый просмотр кода позволяет разве что сократить некоторые участки. А именно:
Вместо
Используется синтаксис Fortran
                do p = 2, M
                if ((Q < sum(prob_distr(1:p,2))) .and. (Q > sum(prob_distr(1:(p-1),2)))) then
                lattice(4,s) = prob_distr(p,1)
                end if

явно стоит сделать что-то такое:
Используется синтаксис Fortran
                tempsum1=0.0
                tempsum2=prob_distr(1,2)
                do p = 2, M
                        tempsum1=tempsum1+prob_distr(p-1,2)
                        tempsum2=tempsum2+prob_distr(p,2)
                        if (Q < tempsum2 .and. Q > tempsum1) then lattice(4,s) = prob_distr(p,1)
                end do

Компилятор, конечно, может многое, но все же заставлять его постоянно считать суммы массивов в громадном количестве не стоит, если без этого можно обойтись (переменные tempsum1 и tempsum2, конечно, нужно определить).

Далее, вот это
Используется синтаксис Fortran
    do l = 1, N  
        do p = 1, 3
            locations(l,p) = lattice(p,l)                                                                  ! Задание матрицы координат пор              
        end do                                                                            
    end do

куда проще записать как
Используется синтаксис Fortran
locations=transpose(lattice(1:3,1:N))
Это, конечно, если подобное вообще зачем-то надо (по моим впечатлениям, массив locations на самом деле совершенно никому не нужен). Ну и т.д. и т.п.

 
 
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение05.11.2015, 01:20 
Pphantom
ещё раз спасибо за советы. Причесал, где чего смог, вроде как отловил всё, из-за чего ничего не работало, теперь программа заводится.
Цитата:
Вообще это некое общее правило хорошего стиля - программа не должна требовать ввода чего-либо с клавиатуры во время работы и не должна выводить на экран ничего, кроме кратких диагностических сообщений, все содержательное - тоже только в файл.

Извиняюсь, впредь буду знать.

 
 
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение05.11.2015, 01:26 
Gickle в сообщении #1070357 писал(а):
Извиняюсь, впредь буду знать.
Извиняться не обязательно, это не норма вежливости, а просто естественное следствие процесса написания кода. При отладке неработающей программы Вы же первый замучаетесь постоянно вручную вводить ей одни и те же данные.

 
 
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение05.11.2015, 14:33 
Gickle в сообщении #1069500 писал(а):
Чтобы не засорять форум лишними темами, спрошу ещё несколько вопросов здесь, если никто не против:


В FORTRANе есть функция FORALL, если не ошибаюсь она должна позволить получить нужный результат в одну строку.
Что то типа:
FORALL(I = 1:N, A(I) > 5) A(I) = I

 
 
 [ Сообщений: 21 ]  На страницу Пред.  1, 2


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group