2014 dxdy logo

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

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




Начать новую тему Ответить на тему На страницу 1, 2  След.
 
 Сравнение массивов и ещё один вопрос по Fortran
Сообщение31.10.2015, 18:19 
Заслуженный участник


29/12/14
504
День добрый, столкнулся с рядом проблем на Fortran (язык для меня абсолютно новый - до этого немного писал на MATLAB и совсем чуть-чуть на C), заранее прошу прощения за, вероятнее всего, глупые вопросы, просто изучение языков программирования у меня идёт туго, а на тематических ресурсах к новичкам относятся очень не очень. Итак:

1. Возможно ли поэлементное сравнение массивов без обращения к циклам, как в MATLAB? Не знаю, как это работает, но в MATLAB эта операция получается невероятно быстрой для любых размеров массивов (не в пример аналогичной операции, выполненной в рамках циклов). Что-то вроде:

Код:
C = A > B


и получить в результате матрицу из нулей и единиц в соответствующих местах.

Пытался найти ответ в разных книгах и документациях, но так и не нашёл упоминания подобной операции в Fortran. Может, какие пакеты есть для таких вещей. Поиск пакетов по линейной алгебре меня, если честно, совершенно запутал. Если можно, ткните кто-нибудь носом в ссылку в случае существования подобного пакета.

2. Пусть у нас есть некоторый тип S:
Код:
     TYPE S
        REAl*8 A1
        REAL A2
        INTEGER A3
        ...
     END TYPE


И пусть у нас есть некоторый массив такого типа:
Код:
       TYPE(S),DIMENSION(:), ALLOCATABLE::B

И пусть вектор B уже некоторым образом определён, и нужно для всех элементов, имеющих определённое значение (скажем, x) определённого поля (пусть A2), изменить значение этого самого поля на определённую величину (пускай y). В MATLAB это опять же делается довольно просто и, что важно, невероятно быстро:

Код:
[B([B(:).A2]==x).A2]=deal(y);


Есть ли какой-нибудь аналог (или пакет какой-нибудь) для Fortran?

Пока что всё. Не бейте сильно, пожалуйста. :)

 Профиль  
                  
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение31.10.2015, 19:01 
Заслуженный участник


16/02/13
4195
Владивосток
Чего-то странного вы хотите от патриарха языков программирования. По первому вопросу, может, и найдёте чего; по второму — безнадёга, имхо.

 Профиль  
                  
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение31.10.2015, 20:04 
Заслуженный участник


29/12/14
504
iifat в сообщении #1068778 писал(а):
Чего-то странного вы хотите от патриарха языков программирования. По первому вопросу, может, и найдёте чего; по второму — безнадёга, имхо.

Если честно, надеялся скорее на какие-нибудь пакеты (всё-таки языку столько лет, наверняка я далеко не первый сталкиваюсь с подобными вещами). Ладно, будем-с пробовать через всякие циклы делать и смотреть, сколько это времени займёт.

 Профиль  
                  
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение31.10.2015, 20:45 
Заслуженный участник


09/05/12
25179
Gickle в сообщении #1068762 писал(а):
1. Возможно ли поэлементное сравнение массивов без обращения к циклам, как в MATLAB? Не знаю, как это работает, но в MATLAB эта операция получается невероятно быстрой для любых размеров массивов (не в пример аналогичной операции, выполненной в рамках циклов).
Возможно, причем именно так это и выглядит. Вот кусочек программы с определениями массивов и собственно операцией:
Используется синтаксис Fortran
 integer,dimension(5) :: A,B
 logical,dimension(5) :: L

 L=(A>B)
 

Результат при этом будет массивом булевых переменных. Если хочется иметь именно целочисленный массив из нулей и единиц, то можно проделать, например, следующее:
Используется синтаксис Fortran
 integer,dimension(5) :: A,B,C
 C=0
 where(A>B) C=1

Gickle в сообщении #1068762 писал(а):
И пусть вектор B уже некоторым образом определён, и нужно для всех элементов, имеющих определённое значение (скажем, x) определённого поля (пусть A2), изменить значение этого самого поля на определённую величину (пускай y).
Аналогично. С Вашими обозначениями:
Используется синтаксис Fortran
where(B%A2==x) B%A2=B%A2+y
 

iifat в сообщении #1068778 писал(а):
Чего-то странного вы хотите от патриарха языков программирования. По первому вопросу, может, и найдёте чего; по второму — безнадёга, имхо.
Без проблем уже 20 лет как. :D

 Профиль  
                  
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение31.10.2015, 21:45 
Заслуженный участник


29/12/14
504
Pphantom
будем посмотреть. Большое спасибо. :)

 Профиль  
                  
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение02.11.2015, 12:34 
Заслуженный участник


29/12/14
504
Чтобы не засорять форум лишними темами, спрошу ещё несколько вопросов здесь, если никто не против:

1. Пусть имеется некоторый массив длины N. Для примера:
Используется синтаксис Fortran
integer :: a(10) = (/2,3,4,7,8,9,3,4,6,11/)

И есть некоторое число f:
Используется синтаксис Fortran
integer :: f = 5

Мне хочется получить массив номеров элементов исходного массива a, удовлетворяющих некоторому условию (пусть $a(i) > f$). Не знаю, как сделать это элегантнее, поэтому сделал это так:
Используется синтаксис Fortran
integer :: indx(10) = (/1,2,3,4,5,6,7,8,9,10/)
...
indx = -indx*(a > f)

Знак минус появился из-за того, что у меня почему-то значение T приравнивается -1 (к слову, я не совсем понимаю почему). На выходе получаем массив из нулей и номеров. По сути, как раз то, что нужно (хотя нули мне не шибко нужны). И теперь мне хочется прогнать какой-нибудь цикл по ненулевым элементам массива indx. То есть что-нибудь вроде:
Используется синтаксис Fortran
do p = indx
...
end do

Только правильно и без нулей ещё. :) Полистал вот тут и тут, но ничего путного не нашёл.

2. Тут заранее прошу прощения за, вероятно, ужасно корявую терминологию. Я пишу в Miscrosoft Visual Studio, после компиляции и запуска программы появляется консольное окно, куда нужно всякие данные вбивать. Так вот, есть ли возможность в рамках этой консоли вообще чего-нибудь? Ну, то есть на выходе программы у нас есть, скажем, массив a. Нельзя ли, как в каком-нибудь MATLAB или Julia language, тыкнуть что-нибудь вроде a(4) и получить на экране четвёртый элемент? Я чего ни тыкал - безрезультатно.

Заранее спасибо.

 Профиль  
                  
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение02.11.2015, 14:18 
Заслуженный участник


09/05/12
25179
Gickle в сообщении #1069500 писал(а):
1.
Обойтись чем-то одним встроенным в данном случае, насколько мне известно, не получится, придется действовать примерно так, как Вы начали.
Gickle в сообщении #1069500 писал(а):
Не знаю, как сделать это элегантнее, поэтому сделал это так:
Можно немного улучшить дело. Во-первых:
Используется синтаксис Fortran
 indx = (/(i,i=lbound(a,dim=1),ubound(a,dim=1))/)
Если перерабатываемый массив большой, писать вручную список натуральных чисел явно не стоит. :-)

Затем делаем такой фокус:
Используется синтаксис Fortran
 indx=merge(indx,0,a>f)
Третий аргумент - это логическое условие, в соответствии с которым в итоговый результат попадут либо элементы из первого аргумента (если условие выполнено), либо из второго (если нет). Второй аргумент фактически воспринимается как массив нужного размера из нулей (можно туда запихать что-нибудь другое, лишь бы оно заведомо не попадало в диапазон индексов исходного массива).

Теперь у нас есть массив нужных индексов, разбавленный нулями. Если нули хочется убрать, то остается вызвать функцию:
Используется синтаксис Fortran
  pack(indx,indx>0)
Некоторая проблема состоит в том, что результат получится неизвестной длины. Но можно заранее выяснить, какое количество элементов в массиве a удовлетворяют условию, вызвав функцию count(a>f) и соорудив массив для приема результатов нужного размера.
Gickle в сообщении #1069500 писал(а):
Знак минус появился из-за того, что у меня почему-то значение T приравнивается -1 (к слову, я не совсем понимаю почему).
А вот так делать не надо. Фортран - не Си, вид машинного представления булевых переменных стандартом не определен и может отличаться у разных компиляторов.
Gickle в сообщении #1069500 писал(а):
Ну, то есть на выходе программы у нас есть, скажем, массив a. Нельзя ли, как в каком-нибудь MATLAB или Julia language, тыкнуть что-нибудь вроде a(4) и получить на экране четвёртый элемент? Я чего ни тыкал - безрезультатно.
Нет, нельзя. Для подобного нужен отладчик (по идее, в MSVS он есть), но в нормальном состоянии работа с компилируемыми языками такое не позволяет. MATLAB и Julia - интерпретируемые (вторая, правда, с оговорками, но это сейчас неважно), там такое можно, но цена этой возможности - сильнейшее падение производительности.

-- 02.11.2015, 14:22 --

P.S. Кстати, с опозданием сообразил, что на использовании merge можно сэкономить. Второй и третий шаги разом делаются с помощью:
Используется синтаксис Fortran
pack(indx,a>f)

 Профиль  
                  
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение02.11.2015, 21:36 
Заслуженный участник


29/12/14
504
Pphantom
опять же большое спасибо за помощь.
Цитата:
Если перерабатываемый массив большой, писать вручную список натуральных чисел явно не стоит. :-)

Ну, это я условно и для простоты, что называется. :-)
Цитата:
А вот так делать не надо. Фортран - не Си, вид машинного представления булевых переменных стандартом не определен и может отличаться у разных компиляторов.

Странно это, как по мне. Всё-таки повсеместно (по крайней мере я нигде по-другому не встречал, кроме Фортрана) вроде принято, что 1 - правда, 0 - ложь, а Фортран вдруг решил "выделиться".

 Профиль  
                  
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение02.11.2015, 22:08 
Заслуженный участник


09/05/12
25179
Gickle в сообщении #1069662 писал(а):
Странно это, как по мне. Всё-таки повсеместно (по крайней мере я нигде по-другому не встречал, кроме Фортрана) вроде принято, что 1 - правда, 0 - ложь,
Вообще-то так принято только там, где булевых переменных нет. В противном случае использовать подобные штуки, даже если они допускаются компилятором, категорически не рекомендуется. В Фортране есть тип logical, поэтому забудьте про то, что логическое выражение можно интерпретировать как число, проще будет.

 Профиль  
                  
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение03.11.2015, 02:03 
Заслуженный участник
Аватара пользователя


30/01/06
72407
Gickle в сообщении #1069662 писал(а):
Всё-таки повсеместно (по крайней мере я нигде по-другому не встречал, кроме Фортрана) вроде принято, что 1 - правда, 0 - ложь

Это как раз далеко не повсеместно. Это новое веяние, в таких высокоуровневых языках, которые не желают уже иметь ничего общего с низким уровнем. А вообще вполне естественно связать с true значение, в котором все биты слова единичные - а это как раз и будет -1 в системе с дополнением до двух.

 Профиль  
                  
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение03.11.2015, 02:16 
Заслуженный участник


20/08/14
11766
Россия, Москва
Munin в сообщении #1069725 писал(а):
А вообще вполне естественно связать с true значение, в котором все биты слова единичные
Думаю здесь надо пояснить почему "вполне естественно" именно так: чтобы в качестве логических И, ИЛИ, НЕ работали обычные битовые операции И, ИЛИ, НЕ. Иначе будут ошибки: NOT(1) $\ne$ 0 - отрицание истины может не быть ложью если единицы не во всех битах; как и 1(истина) AND 2(истина) $\ne$ истине. Что для корректной работы потребует усложнения (и замедления) кода программ.

Но самое правильное - пользоваться логическими типами данных и оставить оптимизацию их обработки компилятору.

 Профиль  
                  
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение03.11.2015, 13:04 
Заслуженный участник


12/07/07
4522
В 386 появилась большая группа инструкций для работы с битами. В частности, группа инструкций SETcc (SETAE, SETE, SETNE, SETB, SETS,…). Инструкции этой группы позволяют по значению одного из флагов заносить в байт памяти или в 8-битный регистр значение 1 (если условие выполнено) или 0 (если не выполнено).

В вычислительных задачах операция not над логической величиной (в регистре или в памяти) встречается исключительно редко. С ходу я не смог придумать ни одного осмысленного примера.

А вот усложнения при сохранении значения флага в память, при указанном выше соглашении о низкоуровневом представлении true в Фортране, мы получаем.

Так что, на 386 и более поздних процессорах Intel как бы выгоднее для true использовать 1 в младшем бите и нули в старших.

Возможно, указанное выше соглашение связано с преемственностью или совместимостью с другими процессорами, имеющими не столь раздутый набор инструкций. (Другими процессорами я не интересовался.)

 Профиль  
                  
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение03.11.2015, 13:11 
Заслуженный участник


09/05/12
25179
GAA в сообщении #1069813 писал(а):
Так что, на 386 и более поздних процессорах Intel как бы выгоднее для true использовать 1 в младшем бите и нули в старших.

Возможно, указанное выше соглашение связано с преемственностью или совместимостью с другими процессорами, имеющими не столь раздутый набор инструкций. (Другими процессорами я не интересовался.)
Правильное утверждение состоит в том, что никакого подобного соглашения в Фортране нет. Способ хранения булевых переменных - внутреннее дело конкретного компилятора, реализованного для конкретной платформы. Поэтому на архитектуре 80386 и более поздних Intel можно использовать младший бит, а на каких-то других - что-то другое. Если не пытаться использовать нелегальное приведение типов, то никаких проблем не возникает.

Впрочем, реально Фортран позволяет проделывать подобные фокусы и в рамках стандарта (используя функцию transfer). Однако в этом случае контроль за осмысленностью результата оказывается целиком на совести программиста.

 Профиль  
                  
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение03.11.2015, 14:03 
Заслуженный участник


20/08/14
11766
Россия, Москва
GAA в сообщении #1069813 писал(а):
В вычислительных задачах операция not над логической величиной (в регистре или в памяти) встречается исключительно редко. Сходу я не смог придумать ни одного осмысленного примера.
Согласен, тоже навскидку не придумалось. Если именно в чисто вычислительных. А вот в близких к ним у меня встречается, бывает надо проверить непопадание числа в некоторое фиксированное множество значений (индекс в векторе или вариант ветки вычислений), в паскале использую if not(x in [1,2,5,99,200]) (не знаю как это в фортране) вместо switch/case. Правда после оптимизации компилятором оно может и в одинаковый код превратиться, но человеку первая форма иногда логичнее и понятнее, да и короче.

Pphantom в сообщении #1069815 писал(а):
Способ хранения булевых переменных - внутреннее дело конкретного компилятора, реализованного для конкретной платформы.
А вот это прекрасно, правильно и полностью поддерживаю.
Пока не нужны огромные (миллиарды элементов) массивы булевых переменных, в таком случае расходы памяти становятся неприемлимыми. А скорость работы может падать уже и при миллионе элементов - из-за "забивания" кэшей ненужными битами в байте/слове.
Но в вычислительных задачах доля времени на работу с булевыми переменными обычно ничтожна и если памяти не жалко, то правильнее отдать всё на откуп компилятору.

-- 03.11.2015, 15:00 --

GAA в сообщении #1069813 писал(а):
В 386 появилась большая группа инструкций для работы с битами. В частности, группа инструкций SETcc (SETAE, SETE, SETNE, SETB, SETS,…). Инструкции этой группы позволяют по значению одного из флагов заносить в байт памяти или в 8-битный регистр значение 1 (если условие выполнено) или 0 (если не выполнено).
Так что, на 386 и более поздних процессорах Intel как бы выгоднее для true использовать 1 в младшем бите и нули в старших.
Сомнительный аргумент: при использовании ещё более новых команд MMX/SSE/AVX сравнения выдают снова единицы во всех битах результата. А условные команды анализируют старший бит аргумента (знаковый). И уж в вычислительных задачах скорее будут использованы именно MMX/SSE/AVX, чем битовые команды SETcc.

 Профиль  
                  
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение03.11.2015, 15:29 
Заслуженный участник


12/07/07
4522
Pphantom, да вы к словам цепляетесь. :D
Конечно, соглашение, принятое в конкретном компиляторе Фортрана. Это и совсем начинающему понятно. Все соглашения о внутреннем представлении объектов являются соглашениями на уровне конкретного компилятора.

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

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

В SSE есть и инструкция, модифицирующая флаги: comiss (для 64 битных вещественных: comisd). Эта инструкция, как раз, чаще всего и используется для выполнения ветвления и сохранения значений флагов в переменных логического типа. Инструкции группы cmp значительно реже используются c сохранением результата в переменных логического типа для последующего управления ветвлением. Да, они [результаты] используются как наборы для логических операций над числами. И, да, конечно, удобно, что они содержат либо одни 1, либо одни нули. Не знаю как на Фортране, но в других языках это просто целые без знака. Это тоже, конечно, как правило соглашения конкретного компилятора.

[Т.е. можно, конечно, хранить в массиве из двух или четырех логических переменных с общей длиною 128 бит (SSE) или 256 (AVX 1 или AVX 2, короче: AVX 256). Но зачем?
Upd Да, и когда я изучал Фортран, более 25 лет назад, логического типа длиной 64 бита ещё не было. :D]

-- Вт 03.11.2015 14:35:40 --

Я это всё к тому, что не так всё просто и однозначно. Да и говорить на эти темы уместнее в другой теме; в Hardware.

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 21 ]  На страницу 1, 2  След.

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group