2014 dxdy logo

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

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




На страницу 1, 2  След.
 
 Сравнение массивов и ещё один вопрос по Fortran
Сообщение31.10.2015, 18:19 
День добрый, столкнулся с рядом проблем на 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 
Чего-то странного вы хотите от патриарха языков программирования. По первому вопросу, может, и найдёте чего; по второму — безнадёга, имхо.

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

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

 
 
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение31.10.2015, 20:45 
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 
Pphantom
будем посмотреть. Большое спасибо. :)

 
 
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение02.11.2015, 12:34 
Чтобы не засорять форум лишними темами, спрошу ещё несколько вопросов здесь, если никто не против:

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 
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 
Pphantom
опять же большое спасибо за помощь.
Цитата:
Если перерабатываемый массив большой, писать вручную список натуральных чисел явно не стоит. :-)

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

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

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

 
 
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение03.11.2015, 02:03 
Аватара пользователя
Gickle в сообщении #1069662 писал(а):
Всё-таки повсеместно (по крайней мере я нигде по-другому не встречал, кроме Фортрана) вроде принято, что 1 - правда, 0 - ложь

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

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

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

 
 
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение03.11.2015, 13:04 
В 386 появилась большая группа инструкций для работы с битами. В частности, группа инструкций SETcc (SETAE, SETE, SETNE, SETB, SETS,…). Инструкции этой группы позволяют по значению одного из флагов заносить в байт памяти или в 8-битный регистр значение 1 (если условие выполнено) или 0 (если не выполнено).

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

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

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

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

 
 
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение03.11.2015, 13:11 
GAA в сообщении #1069813 писал(а):
Так что, на 386 и более поздних процессорах Intel как бы выгоднее для true использовать 1 в младшем бите и нули в старших.

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

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

 
 
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение03.11.2015, 14:03 
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 
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  След.


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