Многомерные массивы. Начну с многомерных массивов. Допустим, вам нужно максимально эффективно работать с большими квадратными матрицами в C++ (скажем, умножать их друг на друга). Причём размер матриц становится известен лишь в runtime. Что делать?
Всякие
double a[n][n]
и std::array<std::array<double, n>, n>
не сработают, т. к. порядок матрицы (n) будет известен лишь в runtime. new double[n][n]
не сработает по этой же причине (лишь первое измерение массива, создаваемого new, может быть runtime-выражением). Попробуем так:double **a = new double *[n]; // Массив длины n указателей на double
for (int i = 0; i != n; ++i)
{
a[i] = new double[n];
}
Вроде нормально. Теперь к i-му j-му элементу можно обратиться при помощи a[i][j]. Вот только есть один нюанс. Массив a — это массив указателей. А не единый двумерный массив, одним куском размещённый в памяти. Значит, обращение к i-му j-му элементу будет медленнее, чем могло бы быть, если бы данные были размещены одним двумерным массивом. И работа с такой матрицей (умножение на другую матрицу и т. д.) тоже будет медленее. То же самое относится к std::vector<std::vector<
double>>
.UPD от 2016-12-11 0:00. Код выделения памяти выше можно написать и поэффективнее. Но моя статья не об этом, она об эффективности обращения к элементу.
А теперь правильный ответ:
double *a = new double[n * n];
Да, теперь к i-му j-му элементу придётся обращаться так: a[i * n + j]. Зато эффективно.
А как сделать так, чтобы синтаксис был нормальным (a[i][j]), но чтоб было эффективно? Нужно написать свой класс, который будет делать ровно это. В стандартной библиотеке такого нет.
Небольшое замечание. В C99 есть variable length arrays (VLA), но они здесь не помогут, т. к. gcc выделяет место для VLA на стеке, а матрицы у нас большие (я предупреждал) и в стек не влезут. (Тут я не прав, см. UPD.)
А вот в Fortran есть стандартный способ работы с динамическими двумерными массивами. Эффективно и с красивым синтаксисом обращения к i-му j-му элементу.
Было бы очень эффектно, если бы я написал здесь, что этот способ был в Fortran с самого начала. Что он поддерживался ещё в первом компиляторе Fortran'а, написанном в 1957-м году. В первом компиляторе Fortran'а (FORmula TRANslation), почти первого языка программирования на Земле (C создан не раньше 1969-го года). Что он поддерживался ещё когда программы на Fortran'е набирались на перфокартах. Я бы ещё поместил тут фотографию перфокарты для пущей убедительности. Но нет. Эта фича появилась в Fortran 90.
Однако Fortran 90 не такой уж и новый. 26 лет прошло. 26 лет эта фича есть в Fortran'е. А в C++ её нет до сих пор.
Вот так выглядит код для выделения памяти:
REAL, ALLOCATABLE :: A (:,:)
...
ALLOCATE (A (N,N))
И обращение к i-му j-му элементу происходит так: A(I, J) (впрочем, нужно учитывать, что в Fortran порядок индексов не совпадает с таковым в C и C++).
Впрочем, нормальный метод работы с многомерными массивами всё-таки есть в C++. В Boost.MultiArray. Но это Boost, это не стандартная библиотека, а потому не засчитывается.
restrict. Теперь про restrict. В Fortran'е в функцию можно передать два массива (видимо, по ссылке). И компилятор будет знать, что это два разных массива, а потому изменение одного не может привести к изменению другого. Т. е. если в функцию передан массив a и массив b, то компилятор знает, что изменение a[2] (пишу здесь в синтаксисе C) не приведёт к изменению b[3]. А значит, если в коде идёт запись в a[2], а затем чтение из b[3], то необязательно реально писать a[2] в память, а затем читать b[3] из памяти. Можно просто записать пока в регистр. Ищите в интернете по слову aliasing.
Так вот, а в C передать массив в функцию нельзя. Точнее, можно, не нет специального синтаксиса, чтобы показать компилятору, что в функцию передаётся именно массив. Если написать:
void f (int a[2])
ну или:
void f (int a[])
То это будет эквивалентно такому коду:
void f (int *a)
То есть фактически передаваться будет указатель. А значит, если мы передаём в функцию «массив» a и «массив» b, то передаваться будут указатели. А значит, у компилятора нет никакой информации о том, собираемся ли мы, используя один указатель, читать/писать память, доступную из другого, или нет (это было про C89, дальше будет пояснение). То есть он не знает, может ли так получится, что a[2] — это на самом деле b[3]. А значит, если мы пишем в a[2], а потом читаем из b[3], то компилятор не может это соптимизировать и вынужден сделать commit в реальную память. А значит, код будет медленнее эквивалентного на Fortran'е.
Лишь в C99 в языке наконец-то появилась фича restrict, которая позволила явно показать, что «вот эти вот указатели далеки друг от друга», то есть двигаясь начиная от одного, мы не попадём во второй. А значит, C вроде как догнал Fortran.
Но Fortran имеет огромную историю использования для высокопроизводительных математических вычислений. Не исключено, что в Fortran есть ещё несколько фич, которые ещё ждут своего часа: включения в C. И которые, возможно, всё ещё делают Fortran быстрее C.
Про статью. Начал писать ответ на этот коммент от aso. Коммент разросся, пришлось превратить его в статью. Плюс давно хотел написать про многомерные массивы в Fortran'е. Статья получилась сумбурной, особенно вторая часть, про restrict. И вообще Fortran я не знаю. :) Насчёт первой части, про многомерные массивы, я почти уверен во всём, что говорю. Во второй части я уверен насчёт того, что относится к C. А вот как там устроены правила алиасинга в Fortran'е, я не знаю, просто где-то в интернете я как-то прочитал, что появление restrict позволило C наконец приблизиться Fortran. А ссылку потерял. :)
UPD от 2016-12-10 14:03. Посмотрел на этот коммент от selgjos, поэкспериментировал с компилятором и понял, что с помощью C99 VLA всё-таки можно добиться нужного мне эффекта. Итак, написать вот так:
double a[n][n]
не получится, т. к. матрица может не влезь в стек. Зато можно так:double (*a)[n] = malloc (n * n * sizeof (double));
Теперь a — это то, что мне нужно. Единый блок размера n на n, размещённый в динамической памяти. С обращением к i-му j-му элементу при помощи a[i][j]. Если теперь нужно куда-то этот массив передать, это нужно делать так:
void f (int n, double a[n][n])
В общем, окей, в C есть нужные мне массивы. Как и в Fortran. А в C++ их по-прежнему нет.
UPD от 2016-12-12 19:12. Процитирую свой коммент:
Лично я не говорил, что якобы фортран и вправду и по сей день имеет некие преимущества перед си. Не имеет. Я написал эту статью, просто чтобы обратить внимание на факт, который, может быть, многие не знают. А именно, что, оказывается, фортран в некоторых моментах удобнее си. И что лишь совсем недавно си наконец догнал фортран по скорости.
UPD от 2016-12-12 22:49. Процитирую ещё один свой коммент:
Да не предлагаю я добавить в C++ многомерные массивы в стиле Fortran или C. Вся моя статья нужна просто, чтобы рассказать про этот курьёзный, так сказать, факт. Что в Fortran есть «нормальные» многомерные массивы, а в C++ — нет. Этот факт был удивительным для меня в своё время.
Комментарии (225)
maaGames
10.12.2016 07:49+6> Вот только есть один нюанс. Массив a — это массив указателей. А не единый двумерный массив, одним куском размещённый в памяти.
Это ОШИБОБЧНАЯ логическая установка, которая ложна для массивов произвольного размера. Для маленьких массивов, действительно, будет наблюдаться различие в скорости доступа. При этом, с действительно большими матрицами работать просто будет невозможно, потому что ОС не сможет выделить непрерывный блок памяти достаточного объёма. Особенно важно это для 32 битных программ. На 64 битных системах у меня случался bad_alloc для матриц буквально в десяток гигабайт объёмом. Вообще, если размер матрицы превышает размер страницы памяти, то нет разницы, линейный блок памяти или из нескольких кусков — накладные расходы по доступу к памяти превысят время одного лишнего умножения при вычислении индекса.vintage
10.12.2016 10:50+2А если идёт обработка изображений, то тут для ускорения нужно уже делать квадратную матрицу из квадратных матриц. А значит без класса транслирующего адреса всё равно не обойтись.
maaGames
10.12.2016 11:36Да в любом случае, для матрицы лучше сделать(взять готовый) класс. Из чисто практических соображений. Всё-таки объектно-ориентированное программирование.
zuborg
10.12.2016 14:10+1Дело не в лишнем умножении, а в дополнительном чтении указателя второго уровня — для больших массивов указателей это играет очень существенную роль.
maaGames
10.12.2016 14:16Именно, что лишнее разыменование указателя играет роль только для малых размерностей, когда была возможность уместить всю матрицу в пределах одной страницы памяти. Для матриц в сотни мегабайт и гигабайты — это уже не играет роли, т.к. страницы памяти могут переключатся даже в пределах одной строки матрицы. Как выше уже заметили, в определённых ситуациях делается блокирование матрицы, чтобы группировать фрагменты разных строк матрицы. В любом случае, работая с классом матрицы нет никакой сложности в том, чтобы изменять тип хранения её содержимого в рантайме, в зависимости от размеров этой матрицы.
alexeykuzmin0
12.12.2016 17:11При интенсивной работе с матрицей этот указатель попадет в кеш, что смягчит проблему.
sleeply4cat
10.12.2016 18:58Возможно ли заставить систему делать дефрагментацию RAM, если не удаётся выделить память?
maaGames
10.12.2016 19:11Во времена Вин98 можно было точно, потому что у меня была какая-то программа для дефрагментации оперативной памяти. Не уверен, что она действительно работала, но я был молод и доверчив…
С практической точки зрения ответ, скорее, нет.
DistortNeo
10.12.2016 19:28+1Поясните, пожалуйста, вопрос. Что такое «дефрагментация» RAM и для чего она нужна?
1. На уровне системы проблем нет благодаря механизму виртуальной памяти (за исключением всяких контроллеров, где нет защищённого режима, но там динамическую память не используют обычно). Память, с которым работает приложение в пользовательском режиме, может быть постранично отмаплена куда угодно.
2. А вот на уровне приложения проблема есть в 32-битном режиме за счёт ограниченности адресного пространства. Если вы выделили кусок памяти, то, вообще говоря, не можете его подвинуть, потому что вам придётся изменить значения всех указателей, которые на эту область памяти ссылаются. Неприятности вызывают и отображаемые в юзерспейс динамические библиотеки.
Чтобы иметь возможность двигать объекты в динамической памяти, консолидируя блоки, вы можете реализовать на C++ механизмы, используемые языкам со сборщиком мусора, за счёт небольшого падения в производительности и десятикратного геморроя из-за неправильно выбранного языка программирования.
P.S. То, что далёкие от программирования пользователи называют «дефрагментацией RAM» — это просто принудительный сброс данных приложений в своп и очистка буферов/кэшей.
Akon32
10.12.2016 22:10Доступ к одному линейному куску
a[x+y*sy+z*sz]
действительно быстрееa[z][y][x]
из-за меньшего числа доступов в память. Ещё в тестахa[x+y*sy+z*sz]
работало заметно быстрее, чемa[(z*sz+y)*sy+x]
, из-за суперскалярности процессора.
Проверено на 3D массивах размером сотни мегабайт. Конечно, ещё всё зависит от паттерна доступа. Не буду спорить, что на бОльших объёмах может быть bad_alloc.Но на "средних" объёмах разница в пользу линейной схемы хранения была заметна.maaGames
11.12.2016 05:52-1> Ещё в тестах a[x+y*sy+z*sz] работало заметно быстрее, чем a[(z*sz+y)*sy+x]
Может потому, что эти уравнения не равнозначны? Вот видите, даже в таком простом примере по памяти с ошибками реализовали. А это минимум пять минут на компиляцию и отладку.)
Я же не спорю, что линейный блок памяти быстрее «рваного». Я утверждаю другое, что нет смысла биться за непрерывный кусок, если матрица очень большая. Шансы на bad_alloc резко возрастают, а падение производительности ещё нужно доказать (в зависимости от паттерна доступа падения производительности может и не быть вообще).Akon32
11.12.2016 13:22+1Имелось в виду
a[x+y*strideY+z*strideZ]
иa[(z*sizeY+y)*sizeX+x]
. (strideX=1, strideY=sizeX, strideZ = sizeX*sizeY)
Мне показалось нужным показать только дерево выражения, поэтому stride и size я назвал одинаково (s). И немного напутал.
Я утверждаю другое, что нет смысла биться за непрерывный кусок, если матрица очень большая.
Как раз таки это имеет смысл (но ровно до тех пор, пока на bad_alloc не нарвётесь).
NeoCode
10.12.2016 11:07+4Проблема в Си в том, что A[N][M] это может быть как массив указателей на одномерные массивы, так и двухмерный массив. А причина этого в глупом (именно так) решении о том, что имя массива эквивалентно указателю на первый элемент массива. Написать символ взятия адреса для получения этого самого указателя не так уж и сложно. А теперь в результате этой «синтаксической оптимизации» мы получили то что массивы не являются «объектами первого класса». Их нельзя передавать в функции именно как массивы; нельзя возвращать из функций именно как массивы.
mikeus
10.12.2016 14:24+7Причина в том, что для того, чтобы всего лишь из имени массива можно было волшебным образом получать информацию о его размерности (чтобы иметь возможность использовать/передавать/возвращать массив как объект первого класса) необходима ещё служебная структура данных хранящая информацию об этом. Си — это достаточно низкоуровневый язык и типы данных, которые несут с собой такие такие скрытые структуры в нем отсутствуют как класс by design. К «проблеме» «глупой синтаксической оптимизации» это не имеет совершенно никакого отношения.
TheCalligrapher
11.12.2016 20:28"… имя массива эквивалентно указателю на первый элемент массива..." — поле такой белиберды дальше можно не читать. Написана ерунда.
Автоматическое приведение объекта типа "массив" к значению типа "указатель" делается в С не безусловно, а лишь в наборе четко оговоренных контекстов. Например, в контекстах операторов
&
иsizeof
такого приведения не делается.
Отсюда сразу становится ясно, что дело тот не в существовании такого приведения (которое, кстати, не является "синтаксической оптимизацией", а растет еще из B и BCPL, где массивы действительно являлись указателями), а в том, что ни у кого не хватает смелости расширить список контекстов, в которых такого преобразования не делается. Нет никаких физических преград для того, чтобы включить "копирующие" контексты в список контекстов-исключений, и тем самым сделать массивы копируемыми. Но соображения обратной совместимости, понятное дело, мешают сильно.
mikeus
12.12.2016 00:37Да, на самом деле это так — «ни у кого не хватает смелости расширить список контекстов» и, действительно, «нет никаких физических преград включить копирующие контексты в список исключений». Как хорошо бы иметь возможность просто написать: a = b или a = f(), где a и b — массивы одинаковой статической размерности (не нужно заморачиваться с memcpy() — разве не круто), а функция f() — просто супер — возвращает массив, копируя его поэлементно наружу.
Ни у кого не хватает смелости сделать массивы копируемыми в языке Си, да и соображения обратной совместимости, понятное дело, мешают сильно. :(
mafia8
10.12.2016 11:10-3double a[n*n]
a[i*n+j]
устроит?ivlis
10.12.2016 11:20+3Нет, конечно. Потому что хоть сколько-нибудь сложная формула превращается в ад.
mafia8
10.12.2016 11:58Можно привести пример сложной формулы? Чтобы было видно, в каком месте возникает сложность.
Например, a[complicated_formula(asdf,zxcv)*n+more_complicated_formula(more,arguments)].vintage
10.12.2016 12:09a[ ( ( y * cols + x ) / group * group + y % group ) * group + x % group ]
mafia8
10.12.2016 13:54+1Имелось ввиду, что есть ли разница между a[i][j] и a[i*n+j], даст ли вторая форма заметную дополнительную сложность.
bandit_erik
10.12.2016 16:09-1и зачем так писать? не проще выделить переменную под индекс?
или, снова, преждевременная оптимизация?vintage
10.12.2016 20:05И как это упростит и починит формулу?
bandit_erik
10.12.2016 22:14+1Никак, но вопрос же про индексы и удобство.
Вы замеряли или чисто теоретизируете?
DistortNeo
10.12.2016 18:32А теперь смотрите:
1. Для повышения производительности часто используется выравнивание строк. Получаем ещё один параметр — Stride.
2. Вы не можете вставить код для проверки выхода индексов за границы.
Единственное разумное решение — обернуть всё это дело в класс.phprus
10.12.2016 21:47> 1. Для повышения производительности часто используется выравнивание строк.
Или не используется, если некоторые алгоритмы можно преобразовать так, чтобы вместо перебора двух индексов перебирать один, проходя по всей матрице последовательно (фактически построчно).
В этом случае для векторизации выравнивание отдельных строк не требуется, так как конец одной строки и начало следующей можно обрабатывать в одной векторной инструкции. Да и для компилятора такой код векторизовать будет проще, чем перебор двух индексов.DistortNeo
10.12.2016 21:54Или не используется, если некоторые алгоритмы можно преобразовать так, чтобы вместо перебора двух индексов перебирать один, проходя по всей матрице последовательно (фактически построчно).
Это если вам ужасно повезло, и выполняемая операция является поэлементной.
В остальных же случаях, когда есть обращение к соседним элементам, придётся писать вложенный цикл с корректной обработкой граничных значений.
nikolaynnov
12.12.2016 05:19Единственное разумное решение — обернуть всё это дело в класс.
И назвать его cv::Mat…DistortNeo
12.12.2016 05:43+1Ну зачем же сразу так? Лично мне база OpenCV очень не нравится: зачем указывать тип пикселя при каждом обращении к нему, когда можно один раз указать тип изображения?
safinaskar
10.12.2016 13:45Я уже писал. В C89 и C++ это не сработает, т. к. n не известен на этапе компиляции. В C99 скомпилируется, там VLA есть, но упадёт в случае сколько-нибудь большой матрицы, т. к. размещается на стеке
semenyakinVS
10.12.2016 11:35+9Мм… То есть вот серьёзно? Целая статья, чтобы заявить «С — слоупок потому, что там нет стандартных 2Д-массивов»? Без особых идей решения проблемы, без нормального анализа ситуации, без тайм-тестов?
Заявка — двухмерные массивы нужно создавать вот так: «double *a = new double[n * n]»? А почему? Где объяснение? «Память выделяется не последовательно»?.. И что? Чем это плохо? Где объяснение? Загуглить про кеш-промахи? Если загуглить — зачем нужна данная статья?
Информация о restrict? Что это такое? «Адреса могут пересекаться»? Хм… Как-то непонятно. Можно подробнее?.. А подробнее нету. Да, можно поискать и почитать: раз, два. Но если нужно что-то искать — снова-таки, зачем данная статья?
Возможно, у меня с утра плохое настроение… Однако, по-моему, если превращать комменты в статьи без особой работы для наполнения статей полагающимся для статей смыслом, хабра из места познания нового и полезного превратится в ресурс для праздных заметок.
З.Ы.: Звиняюсь если кого обидел. Таковой цели не было. Просто хочется читать интересный материал.
tzlom
10.12.2016 13:32-1Нету — и не надо.
В С/С++ по большому счёту нет массивов вообще, есть
С — участок памяти индексируемый от его начала с шагом sizeof(T)
С++ — С или идиома «последовательные элементы списка» если мы вспоминаем про перегрузки
Это не массив в понимании «тип данных», точно так же нет и строк.
Сила С++ не в стандартной библиотеке а в абстракциях без накладных расходов (кроме расходов на мозг программиста, но тех кто пишет библиотеки гораздо меньше тех кто их использует). Та же реализация буста сама считает сдвиги (как и фортран под капотом тоже сам считает сдвиги), но вся эта каша скрыта от пользователя потому что она ему не нужна.
Пользователь хочет простую идиому вида " C = A * B; C[3,4] = -1; " — он её может получить. Не нужно реализовывать умножения матриц самостоятельно, не нужно реализовывать доступ к членам матрицы самостоятельно, всё работает и работает быстро.
С++ справляется с этой задачей. Да, через библиотеку, но он на то и универсальный язык, что на нём можно решить любую задачу написав подходящую абстракцию, а не жаться в рамки предоставляемые языком.
vintage
10.12.2016 13:38Пользователь хочет простую идиому вида " C = A * B; C[3,4] = -1; " — он её может получить.
С++ разве поддерживает мультииндексы?
LibertyPaul
10.12.2016 16:11Да, вы правы, сделать в C++ что то вроде A[x, y] не получится, но можно перегрузить оператор (), или реализовать метод at(x, y), и вобщем-то получить то-же самое.
DistortNeo
10.12.2016 18:35+4В C++ можно перегрузить оператор ()
int& operator ()(int x, int y); int operator ()(int x, int y) const;
vintage
10.12.2016 20:10Ну, это уже совсем за гранью добра и зла :-) Лучше уж тогда явно вызвать метод.
DistortNeo
10.12.2016 20:14+1Не, за гранью добра и зла — это возвращать что-то типа ElementWrapper с перегруженным оператором присваивания.
aso
12.12.2016 08:34Вы правы — это Ада.
Там массивы индексируются круглыми скобочками.
Хотя и в фортране всё не так однозначно…
do k=1,10
do j=1,20
do i=1,100
arr(i,j,k)=25! правильно
brr(k,j,i)=0! работоспособно, но медленнее в несколько раз
end do; end do; end do
(цитата из Вики)safinaskar
12.12.2016 18:49+1В фортране сперва в памяти лежит arr(1,1,1), потом arr(2, 1, 1), arr(3, 1, 1), ..., arr(1, 2, 1) и так далее.
Поэтому arr(i,j,k) будет быстрее всего, там во внутреннем цикле происходит обращение к данным, лежащим в памяти подряд (строчки кеша и так далее). Ну необходимость учитывать кеш относится вообще ко всем языкам программирования
ilmarin77
10.12.2016 13:48+1Эффективные многомерные массивы есть через библиотеки.
Например в BOOST: http://www.boost.org/doc/libs/1_62_0/libs/multi_array/doc/reference.html
Кстати, CBLAS как раз матрицы хранит в виде непрерывного массива.
sergio_nsk
10.12.2016 13:49+2Так вот, а в C передать массив в функцию нельзя. Точнее, можно, не нет специального синтаксиса, чтобы показать компилятору, что в функцию передаётся именно массив.
Раз уже пишите про C/C++, то дополню, что в С++ это можно.
#include <iostream> typedef int array[13]; void f1(array &a) { std::cout << "sizof(a) = " << sizeof(a) << std::endl; } template <typename T> void f2(T &a) { std::cout << "sizof(a) = " << sizeof(a) << std::endl; } int main() { int a[13]; f1(a); f2(a); return 0; }
Выводsizof(a) = 52
sizof(a) = 52selgjos
10.12.2016 13:49+3Начну с многомерных массивов. Допустим, вам нужно максимально эффективно работать с большими квадратными матрицами в C++
Только в контексте фортрана говорить об «максимально эффективно» не имеет смысла.
А как сделать так, чтобы синтаксис был нормальным (a[i][j]), но чтоб было эффективно?
А с чего это нормальный синтаксис? Кто определил тот «факт», что синтаксис через n не нормальный?
При этом читаем ниже:
И обращение к i-му j-му элементу происходит так: A(I, J)
Надо уже определиться с тем — какой собственно синтаксис является нормальным.
А по поводу «не может» — у меня почему-то может:
#include <stdio.h> #include <stdint.h> void f(uint64_t n, char p[n][n]) { fprintf(stderr, "%lu\n", &p[10][0] - (char *)p); } int main(void) { f(1024, (void *)(char[123456]){0}); }
Однако Fortran 90 не такой уж и новый. 26 лет прошло. 26 лет эта фича есть в Fortran'е. А в C++ её нет до сих пор.
А кому она нужна? Никому — кому нужно красиво — пишет на крестах и делает себе какой угодно синтаксис.
И компилятор будет знать, что это два разных массива, а потому изменение одного не может привести к изменению другого.
А теперь «фичу» чтобы получить обратный случай? Что? Её нету? Да вы что. Оказывается это никакая не фича, а просто иное поведение по умолчанию, а си может и так и так? Ну ничего — бывает.
Но Fortran имеет огромную историю использования для высокопроизводительных математических вычислений. Не исключено, что в Fortran есть ещё несколько фич, которые ещё ждут своего часа: включения в C. И которые, возможно, всё ещё делают Fortran быстрее C.
Такой истории нет. Производительность есть у компилятора( в случае фортрана). Уже наверное лет 20 как фортран никого не интересует и интересовать не может.
Точнее, можно, не нет специального синтаксиса, чтобы показать компилятору, что в функцию передаётся именно массив.
В тех компиляторах, в которых фотран быстрее жаваскрипта никакие рестрикты компилятору не упали. Это хинты для экспортируемых функций. Если «высокопроизводительных вычислений» собирать как в 95-м в разных единицах трансляции, то тут конечно всякое бывает. Но таким профессионалам дали lto.
А вот как там устроены правила алиасинга в Fortran'е, я не знаю, просто где-то в интернете я как-то прочитал, что появление restrict позволило C наконец приблизиться Fortran.
Как там в параллельной вселенной? Сишка на связи.safinaskar
10.12.2016 13:50А с чего это нормальный синтаксис?
Он удобнее. Сложнее ошибиться. Почитайте другие комменты, там плюются на a[i * n + j]
safinaskar
10.12.2016 14:10o_O, вы меня убедили, в C действительно можно. Переименовал статью и добавил UPD. :)
QuakeMan
11.12.2016 00:35Вроде бы как C++ включает в себе C89, а не c99.
char (*p)[12]; p = new char[8][12]();
https://ideone.com/99ixtJsafinaskar
11.12.2016 00:45Разные стандарты C++ ссылаются на разные стандарты C. Однако VLA всё равно ни один из стандартов C++ не поддерживает.
p = new char[8][12]();
Мне было очень сложно понять, что это значит. Пишите лучше просто p = new char[8][12]
В общем, не знаю, что вы хотели сказать этим кодом. C++ не поддерживает VLA, а значит, если в вашем коде сделать оба размера матрицы runtime-выражениями, код работать не будет. В C VLA есть, поэтому в C есть та фича, про которую статья
TheCalligrapher
11.12.2016 01:52+1Стандартный язык С++ никогда не включал в себя язык С. Даже С89.
nikolaynnov
12.12.2016 05:07Стандарт C++11 включает в себя C99 by reference. Т.е. как бы целиком.
safinaskar
12.12.2016 17:57+2Нет. C++11 действительно ссылается на C99 (т. е. C++11 references C99), но C++11 не содержит всех фич C99. C++11 не поддерживает VLA из C99. И вообще, C++11 и C99 имеют огромный список несовместимостей (да и вообще, C++ и C всех версий очень плохо между собой совместимы). Начиная с того, что в C символьные константы (например, 'a') имеют тип int, а в C++ — char. Недавно читал огромную статью со списоком несовместимостей, если надо — могу дать ссылку
nikolaynnov
12.12.2016 20:29+1Всё таки не просто ссылается как на левый документ. Многое оттуда берётся и в самом C++ уже не описывается.
C++ is a general purpose programming language based on the C programming language as specified in
ISO/IEC 9899:1999 (hereinafter referred to as the C standard). In addition to
the facilities provided by C, C++ provides additional data types, classes, templates, exceptions, namespaces,
operator overloading, function name overloading, references, free store management operators, and additional
library facilities.
Да и Майкрософт, например, всегда говорит о поддержке C99, как это требуется (они заявляют, что реализовали C99 на 99.9% кроме tgmath.h, так как это к чистому C относится, для C++ есть ctgmath, который у них реализован).
Да и вообще, тот же restrict по этим причинам в C++11 не описан, но ровно один раз упомянут:
17.2 The C standard library [library.c]
1 The C++ standard library also makes available the facilities of the C standard library, suitably adjusted to
ensure static type safety.
2 The descriptions of many library functions rely on the C standard library for the signatures and semantics
of those functions. In all such cases, any use of the restrict qualifier shall be omitted.safinaskar
12.12.2016 22:00Нет, ссылается. Это подтверждается большим списоком несовместимостей и фич C, отсутствующих в C++ (VLA, _Bool [в C++ такого ключевого слова нет] и т. д.). Нашёл всё-таки ту ссылку со списоком несовместимостей: http://david.tribble.com/text/cdiffs.htm .
C++ is a general purpose programming language based on the C programming language as specified in ISO/IEC 9899:1999
Эта фраза лишь сообщает всем известную мысль о том, что C++ основан на C, т. е. что главная модель, которую держали перед глазами авторы C++ — это C.
In addition to the facilities provided by C, C++ provides additional data types, classes...
Опять-таки, эта фраза лишь неформально нам сообщает о том, что кроме основных фич, которые есть в C, в C++ также есть классы и т. д.
Стандарт C++ self-contained, т. е. все фичи C++ должны быть упомянуты в стандарте C++. Они не появляются в C++ автоматически на том основании, что они есть в C.
Вот когда стандарт C++ говорит о сишных хедерах, он говорит, "<string.h> переносится в со следующими исключениями". Вот тут уже C++ явно говорит, что такая-то фича переносится, значит, так и есть.
Да, возможно, процитированный абзац неудачно сформулирован. Но вряд ли они его исправят, если, допустим, я зарепорчу им баг. Т. к. так принято, что стандарты и не предназначены для того, чтобы быть понятными вообще всем без подготовки, особенно в базовых вещах. Я помню, как-то зарепортил баг в POSIX по поводу непонятных, на мой взгляд, формулировок о функциях printf, scanf и т. д. Мне ответили (могу достать ссылку, здесь цитирую по памяти), "you should invest enough time in learning POSIX". Т. е. ты уже должен знать базовое.
Стандарт C++ не пишет, что в C++ есть restrict, а значит, его там и нет. А упомянут он там просто, чтобы дать понять, что декларации функций из стандарта C не нужно воспринимать как есть, нужно их воспринимать без слова "restrict". Потому что restrict в C++ как раз нет.
P. S. Решил проверить, если ли restrict в C++. И что бы вы думали? Его там действительно нет. Ни в C++11, ни даже в текущем черновике C++17. То есть C++ медленнее Fortran. Сейчас. Facepalm
safinaskar
12.12.2016 22:01Мне стало интересно, есть ли хоть какой-нибудь способ обойти отсутствие в C++ restrict. Если отсутствие многомерных массивов можно обойти с помощью умных классов, то что тут?!
TheCalligrapher
12.12.2016 19:05"Слышал звон да не знал где он". Ничего подобного в С++11 нет и никогда не было. С и С++ настолько фундаментально различные языки, что никакого "включения" между ними нет и быть не может.
By reference в С++ включается только интерфейсная спецификация стандартной билиотеки, да и то с массой оговорок.
k155la3
10.12.2016 20:00+2Насчёт «интересовать не может» — наука (по меньшей мере, в России) очень много пишет на Фортране. То есть, вот тот редкий случай, когда язык используется именно и только для того, для чего создавался.
Кроме того, переход с Фортрана во многих случаях — это планы на полста лет вперёд. Чисто как пример: у атомщиков переписанные коды потребуют пересертификации, а это дикое бабло и отвественность.DistortNeo
10.12.2016 20:08+1А можете привести пример? В моём научном окружении используют MalLab, Python, C#, C++, но никак не Fortran. Потому что Fortran — это шаг на 30 лет назад.
safinaskar
10.12.2016 21:29+1Процитирую Википедию:
Фортран широко используется в первую очередь для научных и инженерных вычислений. Одно из преимуществ современного Фортрана — большое количество написанных на нём программ и библиотек подпрограмм.
Имеется большое количество написанных на Фортране (в большей части на старых версиях языка) различных математических библиотек для матричной алгебры и решения систем линейных уравнений, библиотеки для решения дифференциальных уравнений. <...> Ряд таких пакетов создавался на протяжении десятилетий и популярен в научной среде по сей день, например — IMSL.
Большинство таких библиотек является фактически достоянием человечества: они доступны в исходных кодах, хорошо документированы, отлажены и весьма эффективны.В общем есть куча кода, переписывать его никто не собирается. Можно автоматически сконвертировать в C или C++. Но мы в результате получим машиночитаемый, а не человекочитаемый код. Плюс, возможно, полученный код будет работать медленнее, т. к. никто не гарантирует, что Fortran -> asm не быстрее Fortran -> C -> asm
selgjos
10.12.2016 20:46-5Контекст статьи «использования для высокопроизводительных математических вычислений». И именно в этом контексте фортран никого интересовать не может.
А то, что кто-то пишет на фортране по каким-то другим причинам — это не важно т.к. эти причины не есть «мы пишем на фортране, ибо нам надо максимально быстро».DistortNeo
10.12.2016 20:53+2А зачем тогда Intel выпускает и поддерживает свой Intel Fortran Compiler?
phprus
10.12.2016 21:54+2> Контекст статьи «использования для высокопроизводительных математических вычислений». И именно в этом контексте фортран никого интересовать не может.
Вот именно в этой области фортран дико популярен и конкурирует с C&C++ нередко выигрывая у них.
А приведенные выше MatLab, Python, та же Mathematica — это чаще всего лишь инструменты прототипирования или текущих расчетов над небольшими моделями.
Справедливости ради MatLab поддерживает параллельные вычисления на суперкомпьютерах, но на практике я не видел чтобы это активно применялось, хотя раз поддерживает, то наверняка не просто так…selgjos
11.12.2016 23:32-2Вот именно в этой области фортран дико популярен и конкурирует с C&C++ нередко выигрывая у них.
Где? В параллельной вселенной? В реальном мире в этих областях он на помойке. А то, что всякие пхп-эксперты мне ретранслирует поверья из-за своей запарты — из этого ничего не следует.
В реальном мире даже дефолтные диалекты сишки на помойке. Для этого достаточно взглянуть на любые блобы интела( выше эксперт рассказывает куллстори про штеудский компилятор фотрана), да и любые конкурентоспособные реализации. Фортран там невидно, но он 100% там есть. Единственное что есть на фортране — это протухшее дерьмо из 70х, которое не сливает в хлам только жаваскрипту. И то если повезёт.
Высокопроизводительные вычисления — это в современном мире только ручной контроль. Соответственно на коне всё то, что позволяет это делать. В частности без си никуда, ибо без интеграции с функциями ОС — никуда. Да и никакой вменяемый человек не будет писать на фортране т.к. это невозможно. Поэтому, собственно, фортран и находится на помойке. Качество кода определяется не столько языком, сколько человеком который на нём пишет, но опять же — человек уважающий себя на этом дерьме писать не будет, а значит его там никогда и не будет. В связи с этим именно от языка зависит будет ли способный человек писать на нём код.
Точно так же уважающий себя человек не будет писать на любом коболо-дерьме. Будь то фортран, бейсик, паскалик и прочее. Точно так же как и на хаскелях и лиспах. Именно поэтому их удел — забвение на помойке, либо хелворды и лабы всяких школьников. И не потому, что на них ничего вменяемого запилить нельзя, а только лишь потому, что никому из тех, кто это может сделать на них добровольно не сядет.
В целом в обществе пхп-адпетов этот разговор не имеет смысла, ибо кроме как к ретрансляции мифов и легенд из-за парты они ничего не могут.
А приведенные выше MatLab, Python, та же Mathematica — это чаще всего лишь инструменты прототипирования или текущих расчетов над небольшими моделями.
Эти хелворды к «высокопроизводительным вычислениям» не имеют отношения. А то, что о них кто-то говорит и их использует — этот как раз таки следствие того, что большинство адептов это производительности даже не нюхали, да и не нужна она для их хелвордов.
Справедливости ради MatLab поддерживает параллельные вычисления на суперкомпьютерах
Это на уровне заспавнить на mpi тонну дерьма? Не велика заслуга. Слово «супер» не делает код под этот «супер» супер. Никто до сих в параллельность на уровне суперскалярности и симдов не может, кроме как в подвалах интела в обнимку с ассемблером, либо каким-нибудь дсл.
safinaskar
12.12.2016 00:36Чтоа? Вот только не надо хаскелль и лисп складывать в одну кучу к коболам, на которых нормальные люди не пишут. Хаскелль и лисп — отличные языки со своей нишей, как и многие другие. Да хотя б даже зайдите на оф. сайт хаскелля https://www.haskell.org/ и посмотрите, сколько там пакетов в менеджере пакетов (да, кстати, у хаскелля есть менеджер пакетов, в отличие от c++, я помню, кто-то в комментах тут жаловался об отсутствии менеджера пакетов у c++)
selgjos
12.12.2016 07:06-4Вот только не надо хаскелль и лисп складывать в одну кучу к коболам
Я складываю в одну кучу не с т.з. языка, синтаксиса, его идей и прочего, а именно с ТЗ комьюнити — тех, кто их используют и возможностей самого языка.
Да и в целом я всё правильно сказал. Вся это это кобоальгольная семья. Которая существовала до того как появился си. А после си захватил как мир, так и все эти язычки.
Хаскелль и лисп — отличные языки со своей нишей, как и многие другие.
У них нет никакой ниши, кроме школьников и хипстеров. Их творения абсолютно бесполезные и неконкурентоспособны. Они несостоятельны в любой области.
Да и само понятие «ниши» для языка — это уже определения его как убогого. У языка не может быть «ниши» — у него может быть только порог вхождения.
Да хотя б даже зайдите на оф. сайт хаскелля https://www.haskell.org/ и посмотрите, сколько там пакетов в менеджере пакетов
И всё это мусор никому не интересный и никому не нужный, ну кроме адептов, хипстеров и прочих школьников.
Единственная причина почему хацкель не на помойке как остальные ФП-языки — это его мультипарадигмальность. Хотя он называется «функциональный» — он полностью дискредитировал ФП, как и коммонлисп. Ничего без циклов и классиков на этом позере не написать.
Всякие школьники с их кложурами и прочим маразмом мало кого за пределами говносайтиков интересуют.
да, кстати, у хаскелля есть менеджер пакетов, в отличие от c++, я помню, кто-то в комментах тут жаловался об отсутствии менеджера пакетов у c++
Зачем сравнивать жопу с пальцем? Хацкель псевдояп для школьников. Одно дело собирать хелворды школьников из шаблончиков на недоязычке, а другое дело интегрировать в себя всю широту того же С++ мира и системщины с тоннами легаси. Что там будет делать хацкель-адепт для получения своего гхц, пакетного манагера и прочего бинарного рантайма?
Да и что за враньё. У меня есть «менеджер пакетов» портеж называется. Ведь с C++ я получаю системный мир, а так же си, а с си — весь остальной(основной) системный мир.
Проблемы маздайщиков и прочих меня мало волнуют. В мире уважающих себя людей ничего этого нет.
mayorovp
12.12.2016 08:39+2Ваше мнение было очень ценным для нас. Только, кажется, вы забыли его аргументировать.
safinaskar
12.12.2016 18:26Да и само понятие «ниши» для языка — это уже определения его как убогого
Чтоа? То есть по-вашему существует лишь одна ниша и все в этой нише друг другу конкуренты, и, как следствие, среди языков существует один-единственный лучший? Нет. Есть несколько разных ниш. Есть ниша максимально близких к железу языков. В ней есть C, C++, Fortran и, возможно, Rust. Далее идут всё более медленные языки. Ещё есть специализированные ниши вплоть до одинэсов. Вы щас уподобляетесь тому чуваку с хабра, который написал большую серию статей про то, что якобы nim — самый лучший язык (могу найти, если надо)
selgjos
12.12.2016 22:06-3Зачем я с вами говорю — это бесполезно. Ваш уровень развития не позволяет вам ни то что говорить на те темы, которые вы поднимаете, но и даже минимально-приемлемо воспринимать реальность.
То есть по-вашему существует лишь одна ниша и все в этой нише друг другу конкуренты, и, как следствие, среди языков существует один-единственный лучший?
Вас сказать нечего. Если я определил то, что само понятие «ниши» для языка множит его на ноль и определяет говно. Каким образом и с чего вы взяли, что вы можете мне нести херню про какие-то «ниши»? Ниши для школьников. Всё просто.
У вменяемого языка нет ниши — у него есть только порог вхождения. Выше я это написал.
Есть несколько разных ниш.
Не верно. Очередная подмена понятий от школьника. Чем определяются эти ниши? Правильно — эти ниши есть разный уровень требований к качеству конечного результата.
Есть броузер — к нему есть высокие требования к качеству кода и качеству результата. Есть веб-школьник. У веб-школьника нет никаких критерием качества — они не нужны.
Качество кода, как и любого другого продукта определяет его цену. Всё просто. Это и есть ваши «ниши», но ниши-то эти для продукта, а не для языка.
Есть ниша максимально близких к железу языков. В ней есть C, C++, Fortran и, возможно, Rust.
Какое ещё железо. Уровень понимания в районе помойки. Есть управляемые языки, а есть не управляемый. К железу ничего из этого отношения не имеет. Язык — это не про железо.
Фортран вообще не является языком — это кусок дерьма. Он ничем не отличается от жаваскрипта.
Раст — такой же кусок дерьма, но в отличии от убожества фортрана он хотя-бы пытается мимикрировать под вменяемый язык и обладает хоть какими-то возможностями. Но опять же — его родили школьники и быть ему на помойке.
С++ — это надстройка пары костылей над си. В целом язык остался тем же.
Но опять же, как я уже говорил — сам язык никому в мире «высокопроизводительных вычислений» не упал — им можно только подтереться, если он управляемый.
Далее идут всё более медленные языки.
А почему они более медленные? Правильно — они менее управляемые. А почему они менее управляемый? Правильно — для управления нужна квалификация, а откуда она у школьников?
И вот мы и вышли на то, о чём я говорил — ниши существуют только в параллельном мирке адептов. Кто же сознается с тем, что он малоразвитая обезьяна, которая не осилила нормальный язык( вернее даже дело не в языке — дело в управляемости. Отвечать за всё сложно — вот школьник пытается сбежать от ответственности)?
Опять же — пример попроще. Литейное производство. Является ли кустарное литьё из какого-нибудь силумина «нишей»? Есть ли какая-нибудь ниша у силумина? Нет — её нет. Конечно, адепты будут орать, что ниша есть и прочее. Но на самом деле это применяется только потому, что у адептов нет ни бабок, ни квалификации на нормальный техпроцесс. И существует эта ниша только поэтому.
Точно так же и здесь. Существует мир пхп только потому, что у кого-то нет квалификации, а у кого-то нет бабок для нормальной работы. А т.к. все привыкли жрать дерьмо, то создавать дерьмо в порядке вещей.
Естественно есть «ниши», где дерьмо делать нельзя. Там и есть ниша С/С++. И без разницы какая это «ниша» в понятии школьников. Вебчик, либо не вебчик. Это ничего не определяет.
Ещё есть специализированные ниши вплоть до одинэсов.
Ну да. С чего вдруг какая-то секретарша/бухгалтерша сможет осилить вменяемый язык? Да и и это скриптуха убогая.
Вы щас уподобляетесь тому чуваку с хабра, который написал большую серию статей про то, что якобы nim — самый лучший язык (могу найти, если надо)
Ну смотрите. Вы написали, что у хацкеля есть ниша — я вам её определил. Школьники убогие. Вы можете назвать какую-то другую? Нет.
А высеры убогого ламерка про nim, io, haskell, rust и прочий мусор — ничего не стоят. Когда он высер на своём дерьме что-то кроме лабы, либо что-то конкурентоспособное с тем, что есть на вменяемом языке — тогда его высер будет иметь смысл.
Antervis
13.12.2016 05:50+1Предлагаю вам написать сайт на с++, запрос в бд на хаскелле и программу на микроконтроллер на js
п.с.уважаемый, вы не так делаете. Правильный троллинг — это когда вы пишете меньше, чем «жертва». Плюс, слишком явноilmarin77
13.12.2016 07:47https://github.com/cesanta/v7 — интерпретатор js для микроконтроллеров, кстати.
И еще такая штука есть: http://www.espruino.com/
selgjos
13.12.2016 09:41-2Предлагаю вам написать сайт на с++
Пишу. Это любимая тема всех балаболов. Проблемы в вебчике вызваны не «непригодностью» не жабаскрипта, а банальным «вендорлоком», а вернее шизофрения локом.
Да и собственно весь вебстек на С/С++ и написан.
Но вроде как пацаны одумались и начинаю выпиливать эту херню заменяя на нормальные решения( вон как оно оказалось). Адепты буквально пару лет назад ещё орали, что динамическая типизация, что жабаскрипт быстрее сишки — ко-ко-ко и прочее. А потом вдруг асмжс и оказывается всё иначе( жабаскрипт адепты до сих пор думают, что асмжс — это жс и приводят его как пруф того, что жс не ущербен). А потом вдруг тайпскрипты и оказывается всё иначе.
запрос в бд на хаскелле
Это не язык, а недоразумение. Я уже об этом говорил. Зачем мне писать что-то на убогом дерьме?
программу на микроконтроллер на js
Это такой же не язык.
В целом ваша потуга убога и глупа. Вам говорили не о том, что языков нет «ниш» в смысле, что они все «универсальны», а о том, что у языков у которых есть «ниша» — это уже не язык, а дерьмо.
И примеры я приводил, но вы слишком тупы, чтобы их понять и не нести мне херню. Не можете думать на уровня языков и прочих абстракций — думайте на бытовом языке. Это просто — надо только чуть подумать.
Специально для вас повторю ещё раз. «ниши» есть не у языков — ниши есть у продуктов, вернее ниши как уровни качестве — высота критериев оценки конечного продукта. В конечном итоге это определяется только дешевизной — это вообще свойство этого мира. Если можно впарить дерьмо — зачем делать не дерьмо? Если можно нанять обезьяну — зачем нанимать не обезьяну? Проблем больше. Затрат больше.
Вот так и получается, что в этом мире качество появляется только в ответственных проектах. Это и есть «ниша» вменяемых технологий и материалов. Корпус мобилки можно сделать из дерьма, а можно из стекла и алюминия. И у дерьма нет ниши — он ни по каким критериям не является конкурентом. Он просто дешевле и технология его применения проще и дешевле.
Точно так же и с языками.
phprus
12.12.2016 12:33+1Кажется, Вам немедленно нужно обратиться в компанию ВСМПО-АВИСМА для закупки титановых защитных щитков во избежание катастрофы.
А аргументация, базирующаяся на никнейме собеседника — это пожалуй даже оригинальная вещь. +1 Вам за изобретательность.
Резюмируя вышесказанное я вынужден процитировать господина mayorovp:
> Ваше мнение было очень ценным для нас. Только, кажется, вы забыли его аргументировать.
P.S. В тред призывается к.ф.-м.н. kbtsiberkin. Может быть он, как практикующий теорфизик, скажет по существу что-нибудь еще.selgjos
13.12.2016 04:47-3Я не понимаю зачем я спорю с вами, если это бесполезно. Вы не понимаете ни предмета, ни обладаете желанием чего-то добиться, кроме как выпячивать своё бессмысленное мнение, которое является убогое ретрансляцией мифов и легенд.
А аргументация, базирующаяся на никнейме собеседника — это пожалуй даже оригинальная вещь. +1 Вам за изобретательность.
Канонический пример балабола. Ему написали целую портянку — он ничего не осилил ответить — слился и высрал какую-то херню. Ну спрошу я вас — «какая именно моя аргументация основывалась на вашем никнейме?» и вы обделаетесь. Зачем это пишите? На что рассчитываете.
Резюмируя вышесказанное я вынужден процитировать господина mayorovp:
Ну это не имеет смысла. Хотя в вашей тусовке балаболов можно обвинять кого-то в отсутствии аргументации с отсутствующей аргументацией.
Я уже аргументировал своё мнение. Аргументация была с 2-х сторона. Со стороны «если он лучше, то почему его нет нигде?», а так же со стороны — почему собственно его нигде и нет. Если бы вы что-то могли — вы бы развивали тему, а раз нет — вы ничего не понимаете. А раз так — распинаться среди вас я не буду. Аргумент «первой стороны» никуда не пропал. Покажите мне фортран.
P.S. В тред призывается к.ф.-м.н. kbtsiberkin. Может быть он, как практикующий теорфизик, скажет по существу что-нибудь еще.
Ваш адепт ниже обосрался. Бывает.
Аргументация уровня «кукареку все думают, что фортран в дерьме, но это не так — можете мне поверить», а так же высеры уровня «выходят новые „версии“ фортрана». Просто смешно. Выходят новые версии паскаля, делфятинки, бейсика и прочего дерьма. Никого это не волнует.
safinaskar
11.12.2016 00:13-1Fortran — один из немногих языков, который действительно работает на скорости C. Собственно, сегодня есть лишь 3 языка, которые кроссплатформены и при этом обеспечивают максимальную производительность. Это C, Fortran и C++. Причём C++ лишь в случае, если не используются STL, мощный ООП и так далее.
«мы пишем на фортране, ибо нам надо максимально быстро» — да, вряд ли кто-то станет так делать. Новые проекты в этой сфере, видимо, начинают на C и C++.
Но если есть уже написанный на Fortran код, то никакого смысла переписывать его на C нет, т. к. производительность от этого не изменится.encyclopedist
11.12.2016 02:21+3Причём C++ лишь в случае, если не используются STL, мощный ООП и так далее.
STL и мощный ООП никак не мешают производительности при правильном использовании.
safinaskar
11.12.2016 02:38Я сейчас говорю про по-настоящему адский быстрый код. Необходимость написания которого в реальных задачах не возникает. Но если вам действительно нужен быстрый код, то каждый раз, когда вы будете писать слово "class" или "vector", вам нужно будет думать, "а как в результате будет выглядеть результирующий ассемблерный код?" В результате от использования STL и ООП придётся отказаться, т. к. они попросту проигрывают хорошему вручную написанному коду.
Вот скажем, поищите в интернете compiler benchmark game. Сможет ли STL/ООП решение быть на одном уровне с решениями, написанными вручную на C? Вряд ли
encyclopedist
11.12.2016 02:44+1Нет, при правильном использовании они дают точно такой же (с точностью до инструкции), код как написанный на С вручную. Конечно, для этого надо понимать, как работают те инструменты, которыми пользуешься.
Вряд ли
Не знаете — не пишите.
rPman
22.03.2017 01:09Без использовании интерференции, только несколькими экранами или нестандартной оптикой — серия микролинз например, но там в любом случае будут проблемы с разрешением, заметные).
Я бы не отказался от хотя бы по три экрана на глаз (фон, ближняя переферия и фокусные объекты), уже что то, размеры шлема при текущих технологиях громадны.DistortNeo
11.12.2016 03:08+1Вывод простой: если вам нужно работать с вектором, гарантировано имеющем длину не больше N (N — небольшое, до 8-16), и именно работа с вектором отжирает до 90% времени выполнения кода, то имеет смысл подумать об использовании собственной реализации вектора под конкретные условия.
Всё остальное — преждевременные оптимизации, усложяющие написание кода.
encyclopedist
11.12.2016 05:05+2Именно поэтому я написал про "правильное использование". Использование вектора тут не нужно, достаточно
std::array
:
int f2() { std::array<int, 4> v = {1, 2, 3, 4}; int sum = 0; for ( auto x : v) { sum += x; } return sum; }
компилируется в 2 инструкции:
f2(): # @f2() movl $10, %eax retq
TheCalligrapher
11.12.2016 07:40-1Мысль правильная, но пример, скажем прямо, не показательный и к производительности
std::array
прямого отношения не имеющий вообще. В реальном коде подобные optimization opportunities, понятное дело, не встречаются. Если, конечно, вы их нарочно не создаете.
RPG18
11.12.2016 10:34Т.к. разные инструкции процессора восполняются с разной скоростью, то простыня кода мало о чем говорит. Если перепишем std::vector на Си как АТД, пометим все как inline, то получим простыню когда. Естественно если будем компилировать код компилятором Си, то простыня получится поменьше из-за отсутствия кода, для работы с исключениями.
DistortNeo
11.12.2016 02:59+1Очень многое зависит от самого компилятора, точнее, от его способности оптимизировать код.
Тесты проводились только для g++, но g++ — не единственный в мире компилятор, да и не самый быстрый, помимо него ещё существуют msvc, llvm, icc и т.д.
До того, как я познакомился с ICC, я пытался переписывать узкие места кода (обработка изображений) на ассмеблере и получал двукратное ускорение по сравнению с msvc. Но когда я воспользовался ICC, оказалось, что он генерирует код такой же по скорости, а иногда и быстрее, чем вручную написанный на ассемлере.
selgjos
13.12.2016 07:14-1Вот смотрите как интересно получается. Как вы ко мне — так и к вам. Показательно.
Помогу вам.
Как я уже выше писал — производительность — это контроль.
class
Дак вот — классы(обычные) абсолютно предсказуемые и никак никому не мешают. Поэтому выкатывать это как аргумент не имеет смысла.
Проблема в классами именно в связки их с ООП, а оно предполагает aos, а им можно только подтереться.
Использовать же классы как простой сахар для передачи контекста в функцию никто не мешает, собственно этим они и являются.
vector
Опять же в контексте «ассемблерного кода» нету смысла говорить о векторах и прочих крестовых изваяний по причине того, что в конечном итоге крестобалабол сольётся на то, что для сравнения с вектором вам нужно реализовать такой же вектор, а иначе сравнение некорректно. Но это не имеет смысла, ибо вектор ничего не отличается от сишной лапши — он она и есть завёрнутая в Оинтерфейсик на шаблончиках.
И для того, чтобы смешать с дерьмом вектор, как и убогий фортран — надо перейти в реальный мир. Собственно в реальном мире вся производительность и существует.
И тут начинается разрыв шаблона у крестового балабола. Оказывается в реальном мире динамическая память есть на уровне памяти и вектор нахрен не нужен уже 10лет. Далее оказывается, что вектор( как и кресты) не умеют в реаллок. И тут опять разрыв шаблона — реаллок в любую часть памяти не требует копирования( как учили крестовых адептов).
А дальше идёт разрыв шаблона от ленивого связывания памяти. И оказывается reserve() в векторе нихрена не даёт памяти( как и маллок). И мы получаем память по мере обхода обработкой пейджфолта. Далее мы понимаем, что дефолтными сишными и крестовыми аллокатарами можно только подтрееться. И нам нужен префолт.
А потом когда мы узнём что такое память, что такое тлб и почему это плохо при RA, то мы желаем его «выпилить» нахрен. Опять же крестами можно только подтереться.
Ну и даже такой банальности как «выравнивание» нету. Приходится прикостыливать левый аллокатор. Были когда-то потуги с валараями, но нахрен они крестовикам?
т. к. они попросту проигрывают хорошему вручную написанному коду.
Только вот штука в том, что хороший код кто-то должен написать, а язык должен это позволять + не стоит забывать, что хороший код — это не код на языке, а нечто большее.
Сможет ли STL/ООП решение быть на одном уровне с решениями, написанными вручную на C?
Что-то я там не вижу фортрана. Фанатизм — такой фанатизм.
Что самое интересное там фортран-днище написано ручным c2f, а компилятор его собирается встроенным f2c. Полезность зашкаливает.staticlab
13.12.2016 17:57+1Скажите, пожалуйста. Вы, как я понимаю, умный человек, пишете на си какие-то высокопроизводительные сверхоптимизированные программы и, очевидно, получаете за это хорошие деньги. Зачем Вам спускаться на уровень этих школьников и быдлокодеров, пишущих на убогоньких быдлоязычках за доширак?
selgjos
15.12.2016 05:52-2Дело не в том, кто я — это никого не волнует, точно так и «кто вы».
Опять же — вы пытаетесь врать и себе и остальным. Пытаетесь выставить меня в свете будто-бы я дартаньян и шизофреник. Зачем?
Вы явно врёте про то, что я называю кого-то школьником. Дело не в этом. Школьник и быдлокодер — это не плохо и из этого ничего не следует. Ни у всех есть время, желание и способности. Да и не выгодно это особо.
Если же на вещи смотреть не с зашоренными глазами, не пытаться себе врать, то всё становится понятно. Обвиняю я в чём-то людей не потому, что они чем-то от меня отличаются. В этом нет ничего плохого. Обвиняю я их потому, что будучи несостоятельными в тех областях, о которых они пытаются рассуждать — они, собственно, что-то утверждают и проповедуют.
Никто не обвиняет человека в том, что они сидел и писал хервордики на фортране — для него язык — это калькулятор. Зачем мы обращаемся к его авторитету, зачем он что-то утверждает?
Зачем тому, кто не знает ни языка, ни матчасти рассуждать о том почему, где и как кто кого обгонял. Это же глупо?
Подмена понятий и самообман — это ваша беда. Если вам сложно мыслить абстракциями — пытайтесь понимать мир через бытовой уровень. Все адепты поголовно считают малоквалифицированную рабсилу быдлом. Скрывают или нет — это так. Они могут относиться к этому с пониманием, но в любом случае считают, что это не особо высокий уровень развития.
Почему же мы не называем это нишей? Дело не в их квалификации — это просто ниша. Ведь так?
Почему вы такие непоследовательные? Говно вы называете говном. Чем говнокод отличается от вашего кода? Он ведь то же работает. Чем нормальная машина отличается от дерьма? Ведь она то же едет?
И посмотрите на рекламу ширпотреба, на защитников ширпотреба — что они говорят? Правильно — он как раз-таки говоря о «нише». Не говно дороже, сложнее и прочее. И подавляющее большинство тех, кто орёт мне про «нишу» — считают их идиотами. А в чём отличии? Правильно — его нет.
Самообман штука такая. Свой «труд» сложно назвать говном. Себя вообще сложно оценить объективно. И те, кто драят сортиры думают точно так же как и вы. Это просто ниша. И отношение у них к вам такое же, как и у вас ко мне.
И естественно каждая кухарка эксперт как рулить государством, любой колхозник в курсе как сделать хорошую машину и какая хорошая. Школьник знает как лучше сделать игру. Секретарша как одинеску. И когда вы на них смотрите — вас смешно. Вы считаете их дураками.
Но ведь никаких отличий нет? Каждый видит ниже себя. Что там вася делает не так. Но ведь я не вася. Я 100% думаю не так как этот вася. Это в мечтах адепта. А реально он ничего от васи не отличается. Поводки всё те же, только несколько в другом виде.
staticlab
15.12.2016 09:38+1Пытаетесь выставить меня в свете будто-бы я дартаньян.
Обвиняю я их потому, что будучи несостоятельными в тех областях, о которых они пытаются рассуждать — они, собственно, что-то утверждают и проповедуют.
Никто не обвиняет человека в том, что они сидел и писал хервордики на фортране — для него язык — это калькулятор.
Т.е. ваша проблема только в том, что вы не осилили ничего кроме фортрана?
Обвиняю я в чём-то людей не потому, что они чем-то от меня отличаются.
вы слишком тупы, чтобы их понять и не нести мне херню
Ваш уровень развития не позволяет вам ни то что говорить на те темы, которые вы поднимаете, но и даже минимально-приемлемо воспринимать реальность.
Да и никакой вменяемый человек не будет писать на фортране
Точно так же уважающий себя человек не будет писать на любом коболо-дерьме. Будь то фортран, бейсик, паскалик и прочее.
днище не понимает почему не работает инвок
Убогая ламрюга. Как это прекрасно, когда обосравшийся балабол начинает съезжать на левые понятия, а потом что-то из себя строит.
Разумеется, вы сейчас снова будете психовать и оскорблять меня и всех окружающих, но чем именно вы лучше всех остальных? Тем, что знаете C++?
каждый балабол уверен в том, что можно нести любую херню и он прав по факту.
Но ведь никаких отличий нет? Каждый видит ниже себя. Что там вася делает не так. Но ведь я не вася. Я 100% думаю не так как этот вася. Это в мечтах адепта. А реально он ничего от васи не отличается.selgjos
15.12.2016 12:35-2Разумеется, вы сейчас снова будете психовать
Если вы думаете, что я психую — это неверно. Меня это не колышет.
и оскорблять меня и всех окружающих, но чем именно вы лучше всех остальных?
Я никого не оскорблял. Это ваше восприятие. Если вы не позволяете себе говорить и утверждать на те темы в которых не разбираетесь — вы не имеете отношения к тем о ком говорил я. А если это так, то проблема явно не во мне.
Да и я нигде не говорил что я лучше — это очередная невменяемость вашего восприятия. Мне не важно кто вы. Я не оцениваю вас. Я оцениваю то, что вы пишите. Оцениваю ваши слова и суждения. Я оцениваю их не противопоставляя себе, а отдельно. Зачем вы приплетаете меня? Лишь потому, что это известный вам шаблон ответа? Вы не уникальны.
Тем, что знаете C++?
Язык тут не причём. Вы же пастили мои пасты из другой темы — там я говорил, что С++ говно. А в другой говорил что си говно. Я не являюсь адептом какого-то языка и прочее. Меня это мало волнует.
Так всегда. Когда я не соответствую каким-то общепринятым верованиям — меня начинают обвинять в чём-то. Говорю плохо про С++ — не осилил. Про сишку — не осилил. Это восприятия мира сектантами — всё что не по их — этого не может существовать. Это говорит еретик, урод и прочее. Сжечь его — забанить, заминусовать, заспамить.
Так было везде. В прошлый раз я пытался писать вменяемо, но меня опять довели. Я кидал уже пруфец — https://habrahabr.ru/users/firsttimecxx/comments.
Я люблю эльбрус — я пытаюсь объяснять людям в чём проблема и как сделать лучше — ты хейтер. Я люблю си и даже С++ и пытаюсь объяснить людям в чём проблема С++, чтобы сделать его лучше — я хейтер.
Всё что я прошу — понимание. Надо понимать, а не верить в какую-то херню которую кто-то сказал. Адепты го верят, что их не развели с их горутинами. Они верят, что ОС не может в 100потоков. Им показываешь обратное — бесполезно.
В целом меня это достало + в теме про С++ мне попались совсем невменяемые люди, которые просто врали, врали и врали. А т.к. у меня ни времени, ни кармы, чтобы им отвечать — я уже перестал воспринимать их как людей.
Вы не хуже других. Я не лучше вас. У всех разные способности, желания, обстоятельства и текущие условия. Я не против вас. Я не понимаю просто — зачем рассуждать, утверждать, называть других дебилами и не воспринимать альтернативной точки зрения, если вы даже в том о чём рассуждаете не разбираетесь?
RubyFOX
27.03.2017 09:58Да, нужно в биполярный переделать, дел на 10 минут или даже меньше. Раскрыть, перерезать дорожку, закрыть.
selgjos
15.12.2016 19:50-2Тогда почему вы называете других дебилами
Не было такого. А почему я отвечаю жестко? Я не вижу желания от людей вести какую-то осмысленную дискуссию, а зачем мне тогда делать то не же самое?
и не воспринимаете альтернативных точек зрения?
Потому что это не точки зрения, не? Это глупая ретрансляция легенд, мифов, «одна бабка сказала», либо «я не понимаю того, о чём я говорю». Это никак не котируется за мнение.
Да и ладно — это не аргумент. Просто эти мнение, даже предположим, что это мнение — не являются аргументированными. Люди начинают утверждать «фортран жив и может» — их спрашиваю — «где?», а в ответ тишина, либо не ссылка на такие же пустые утверждения, либо совершенно на левые темы.
Допустим «на фортране просто писать хелворды» и с этим никто не спорит, что на фортране удобнее писать тому, кто на нём/паскалике пишет всю свою жизнь. Правда эти рассуждения не имеют отношения к теме. Напомню — «высокопроизводительные вычисления» и «быстрее си».
Ну и да, в моём понимание «альтернативных точек зрения» быть не может — это невозможно. Оно может быть так, либо иначе. Ни никак не так и не иначе одновременно. Точки зрения и разговоры про них любите вы(общественность тутошняя) — поэтому я взываю вас соответствовать. При этом моё несоответствие этому никак не позволяет вам делать то же самое. Ведь себя же «вы» не обвиняете в том, в чём обвиняете меня?
Ну а в целом я уважаю любые мнения, если они осмысленное — т.е. человек может объяснить причины и вселенную в которой это может работать, даже если это не эта.
safinaskar
15.12.2016 19:26Если (допустим) вы действительно не тролль, как минимум не ругайтесь (ну там "обосрался", "говно" и так далее). Ну и тон другой сделайте. И не придётся постоянно новые аккаунты создавать. Не надо фраз вроде "Кто же сознается с тем, что он малоразвитая обезьяна, которая не осилила нормальный язык". Так, может, в личных блогах пишут. Может, это ваш стиль, саркастический, но тут так не принято. Нормально пишите, аргументированно
nikolaynnov
12.12.2016 05:12+1Эх, автор ещё явно такого не видел:
//Допустим, есть строка «abcd»,
//Как получить значение третьего элемента?
//Можно, например, так:
char c = «abcd»[3];
//а можно еще и так:)
c = 3[«abcd»];
onetime
10.12.2016 14:23+1Ничто не мешает перекастовать указатель из маллока к указателю на VLA нужной формы. Массив будет получаться сплошным и любой размерности. Единственная проблема — вылет за границу, но если ты взялся за C, надо уметь это отлавливать.
int (*array)[N] = calloc(N*M, sizeof(int)); for(int i = 0; i < M; i++) for(int j = 0; j < N; j++) // Обработка A[i][j]
kefirfromperm
10.12.2016 14:25+1В Fortran'е вообще много удобств для работы с массивами. Операция поэлементного сложения или вмножения в сях близко нет. Приходится циклы городить.
Idot
11.12.2016 17:50А как обстоит со скоростью у APL?
(поясню о чём речь: APL имеет встроенные средства работы с матрицами)
mwizard
10.12.2016 15:49+2Для передачи в аргументах именно массивов есть static:
Оно говорит компилятору — «a это массив int-ов с не менее, чем пятью элементами». Компилятор никак не проверяет истинность этого утверждения, и если передать не то, или меньше элементов, будет UB.void foo(restrict int a[static 5]);
Akon32
10.12.2016 16:21+6Преимущество С++ — в расширяемости (в разумных пределах).
Не знаю как в фортране, но в C++ можно легко написать требуемый в данной ситуации (например, который может работать на GPU и на CPU) класс для "многомерного массива". Или взять готовый из boost, blitz++, или другой библиотеки (тысячи их).
Поэтому все double a[n][n] — в топку, на C++ так не пишут. А пишут наподобие
array2D<double> a(n,n); a.setDim(m,m); a(x,y) = 2 * a(y,x);
И в фортране вы вряд ли (возможно, я ошибаюсь) напишете
GPUArray2D<double> b(n,n); b.copyFrom(a); gpuProcess(b);
Тем более, матрицы — это такая нужная каждый день фича, что за пять лет разработки ГИС непосредственно кодить что-либо с матрицами мне потребовалось раз пять, хотя без них даже ничего не отрисуешь.
И зачем впихивать матрицы в и без того раздутый стандарт? Они прекрасно реализуются в библиотеках.
safinaskar
10.12.2016 19:59Вы правы, как и другие комментаторы с такими же мыслями. Просто хотел обратить внимание читалей на эту неожиданную, наверное, для многих мысль, указанную в заголовке. Прикольнуться, так сказать
Akon32
10.12.2016 22:16+2Меня больше беспокоит, что долго не было стандартного API файловой системы (в С++17 — уже есть). Его, в отличие от матриц, просто средствами языка не реализуешь.
AlexHa
10.12.2016 17:31А почему «были»? И были, и есть, компилятор Fortran поддерживается фирмой Intel и оптимизирован под процессоры этой фирмы для наилучшего быстродействия. Последняя версия языка, если не ошибаюсь, от 2013 года. Какой-то странный спор, что лучше, отвёртки плоские или отвёртки крестовые. Под каждую задачу свой инструмент, и каждый пользуется тем инструментом, который ему удобнее. Зачем об этом спорить-то? В фортране ещё много чего есть, и комплексные типы переменных и перемножение матриц одним оператором, и библиотеки IMSL. Скорость вычислений определяется тестами, а не бла-бла-бла на форумах.
Lol4t0
10.12.2016 19:08В C++17 до сих пор нет нормальных многомерных массивов
Неверно
http://www.boost.org/doc/libs/1_39_0/libs/multi_array/doc/user.html
DistortNeo
10.12.2016 19:32Boost не является частью C++17, а реализовать функционал сторонними библиотеками проблем не вызывает.
Вообще, правильное утверждение должно звучать так: «Синтаксисом и стандартной библиотекой C++17 не предусмотрены многомерные массивы».Lol4t0
10.12.2016 19:45+3А зачем они вообще нужны в стандартной библиотеке?
Вот чего действительно нет, так это нормальной системы управления зависимостями
DistortNeo
10.12.2016 20:12+2А зачем они вообще нужны в стандартной библиотеке?
Не нужны. Потому что их желаемое представление в памяти, в зависимости от задачи, может быть различным. А C/C++ слишком низкоуровневые, чтобы насаждать такие вещи.
Вот чего действительно нет, так это нормальной системы управления зависимостями
Это потребует радикального пересмотра стандартов и приведёт к потере обратной совместимости, а на такое никто не пойдёт. Проще сделать форк от C++ (=новый язык).safinaskar
10.12.2016 22:05Что вы имеете здесь в виду под управлением зависимостями? Менеджер пакетов для C++? Скажем, как npm для nodejs? Если да, то для создания такого не нужно ничего менять в языке. И даже в стандарт такой менеджер пакетов добавлять не нужно. Его нужно просто сделать. Я слышал, что есть даже несколько конкурирующих решений
DistortNeo
10.12.2016 22:15+1Что вы имеете здесь в виду под управлением зависимостями?
Простоту подключения стороннего кода. Как сборки C# или Java.safinaskar
11.12.2016 00:27-1И зачем для этого самого подключения нужно пересматривать стандарт? Просто берём менеджер пакетов, устанавливаем через него нужную вам либу, добавляем в используемую вами систему сборки опции для сборки с этой либой, добавляем нужные инклуды и готовы. Или вам нужно, чтобы ещё и в систему сборки опции сами прописывались? Или может, чтобы ещё и инклуды кто-то за вас дописывал? Опять-таки, всё это в принципе это осуществимо. То есть можно написать соответствующие инструменты. К стандарту это вообще не относится.
Под какой ОС пишите? Какая у вас система сборки? Мейкфайлы или что? Я просто совершенно не могу понять, зачем для этого «подключения стороннего кода» нужно переделывать стандарт.
Или может, вы хотите отказаться от препроцессорных инклудов и сделать вместо этого другое решение, как в других языках? Ну так на это есть Modules TS, такой proposal для стандарта C++, ищите в интернете. И я не думаю, что этот proposal так уж сильно переделывает весь стандарт. Что аж язык проще форкнутьDistortNeo
11.12.2016 01:03+1Или вам нужно, чтобы ещё и в систему сборки опции сами прописывались? Или может, чтобы ещё и инклуды кто-то за вас дописывал?
Конечно! Я хочу написать всего одну строчку: #import <...>, а всё остальное должен сделать компилятор-линковщик, без прописывания дополнительных опций в виде магических путей и магических дефайнов.
C++ плох также тем, что в нём нет стандартного описания проекта. Системы сборки (Makefile) предназначены, как это ни странно, именно для сборки, а не для описания проекта, которое вообще не должно содержать никаких команд. Как следствие — зоопарк всяких automake-ов.
Я просто совершенно не могу понять, зачем для этого «подключения стороннего кода» нужно переделывать стандарт.
Затем, чтобы подключение стороннего кода стало удобным, как в других языках.
Или может, вы хотите отказаться от препроцессорных инклудов и сделать вместо этого другое решение, как в других языках?
В точку! Препроцессор — зло. Представьте себе, сколько надо будет переписать кода, чтобы не осталось ни одного #include?
Под какой ОС пишите? Какая у вас система сборки? Мейкфайлы или что?
Под разные. Использую vcxproj и голый makefile, причём оба редактирую вручную, проекты у меня небольшие (до 50 файлов).safinaskar
11.12.2016 01:12-1Ещё раз скажу, что всё это вопрос инструментов (я сейчас про единый конфиг проекта). Нужно чтобы кто-то просто создал подходящие инструменты. К стандарту это не имеет отношения.
А что касается конкретно отказа от препроцессорных инклудов, ещё раз скажу: ищите по словам modules ts, работа ведётся. И для введения этих modules стандарт придётся поменять лишь немного. А сами либы не придётся разом все переписать, работа будет вестись постепенно. Почитайте про эти modules, там скорее всего объясняется как они собираются постепенно внедрять свои модули
DarkEld3r
12.12.2016 19:58К стандарту это не имеет отношения.
С одной стороны, да. С другой, тот же filesystem, казалось бы, тоже доступен в виде библиотеки, причём кроссплатформенной — бери да пользуйся. Но некоторые вещи всё-таки удобнее иметь в стандарте. Заодно это вынудит основных вендоров договориться между собой. Иначе могут наделать разных, каждый из которых придётся допиливать.
vintage
10.12.2016 20:18+3Затем, что многомерные массивы имеют весьма широкое применение в различных областях. Это не какая-то "высшая математика". А синтаксису бы не помешала поддержка мультииндексов и срезов.
DistortNeo
10.12.2016 20:29К сожалению, в C++ есть одна неприятная штука — comma operator, будет мешать при определении многомерных индексов.
vintage
10.12.2016 21:07Аргументам функций же она не мешает, так что ничего страшного, если и в квадратных скобках её больше не будет. Не думаю, что кто-то находясь в здравом уме и трезвой памяти использовал этот оператор в таком контексте.
TheCalligrapher
12.12.2016 20:17-1Каким образом фича языка может "мешать" — ума не приложу...
mayorovp
12.12.2016 21:29Очень просто. Раньше выражение
int x[2,3]
означало массив из трех элементов, аx[1,0]
— обращение к нулевому.
Если разрешить мультииндексы — то старый код может сломаться.
TheCalligrapher
12.12.2016 21:55Первая часть — неверно. Это никогда не "означало массив из трех элементов", как вы ошибочно полагаете.
В С89/90 и С++ размер массива в объявлении массива должен задаваться константным выражением. Но константное выражение в этих языках грамматически не может содержать оператора "запятая" на верхнем уровне. Поэтому последовательность
int x[2, 3]
является грамматически неверной, т.е. не вообще в принципе никак не распарсиваемой в этих языках.
Единственным грамматически верным способом протащить оператор "запятая" в константное выражение является использование дополнительных круглых скобок:
int x[(2, 3)]
. Однако в С и pre-C++11 С++ тут дополнительно вступают в силу уже явные (неграмматические) ограничения, дополнительно оговоренные в тексте стандарта: константным выражениям открытым текстом запрещено использовать оператор "запятая".
В post-C99 С размер локального массива уже не обязан быть константным выражением, но грамматика по прежнему сформулирована так, что
int x[2, 3]
не является распарсиваемой последовательностью. Поэтому в С99 разрешается толькоint x[(2, 3)]
.
В post-C++11 C++ разрешается использование оператора "запятая" в константных выражениях, но структура грамматики оставлена прежней, то есть в С++11
int x[2, 3]
по прежнему не является распарсиваемой последовательностью. Поэтому в С++11 разрешается толькоint x[(2, 3)]
.
Вторая часть — верно. Действительно
x[1,0]
— это обращение к нулевому элементу и да, тут вы правы: оператор "запятая" мешает в контексте доступа. Тут бы потребовалось волевое решение: модификация грамматики по образу и подобию грамматики объявления (как я описал выше): грамматически запретить использование оператора "запятая" на верхнем уровне выражения. В принципе, возможно это стоило бы сделать вообще везде, т.е. разрешить использование оператора "запятая" только внутри скобок.mayorovp
12.12.2016 22:13Ну, второй части достаточно чтобы создать проблемы с обратной совместимостью.
TheCalligrapher
12.12.2016 22:22Это так, но последнее время и С и С++ ведут себя довольно смело с депрекацией фич, которые могут создать проблемы с обратной совместимостью. В С++ чего стоят одни только депрекации dynamic exception specification и неявного объявления функций копирования в классах.
crea7or
10.12.2016 21:21Но простите, STL тоже к языку относится скорее формально, а не как часть самого языка. Никто не мешает использовать любые другие библиотеки без какого либо STL вообще. И, кстати, много чего из буста постепенно мигрирует в этот самый STL.
DistortNeo
10.12.2016 21:40STL — гарантированный поддерживаемый минимум любым современным компилятором C++. Вы можете быть уверены, что STL есть всегда.
Если же STL вдруг нет (ну бывает — опять же микроконтроллеры), то у вас уже не C++, а C с классами.
TheCalligrapher
10.12.2016 22:11Автор статьи не увидел леса за деревьями.
Первый способ организации многомерного массива через индивидуальное выделение памяти для каждой строки массива — это то, как учат создавать run-time-sized двухмерные массивы студентов-первокурсников. И именно и только студенты-первокурсники так и делают. Уже ко второму курсу студент внезапно понимает, что когда речь идет об ручном выделении памяти для обычной матрицы, нет никаких причин выделять память для каждой строки индивидуально. Поэтому при "ручном" выделении памяти никто не поступает так, как показали вы, а делают несколько по-иному
double **a = new double *[n]; double *data = new double[n * n]; double *row = data; for (int i = 0; i != n; ++i, row += n) a[i] = row;
А теперь достаточно просто внимательно взглянуть на код выше, чтобы увидеть, что разница между этим вариантом, и вашим вариантом с пересчетом индексов заключается только в том, что вы настаиваете на постоянном пересчете индексов "на лету", то есть на явном выполнении умножения
i * n
при каждом доступе к элементу[i][j]
. А этот вариант просто-напросто вычисляет произведениеi * n
и запоминает адресa[i]
для каждой строкиi
заранее, сохраняя его в отдельном массиве.
С концептуальной точки зрения реализацию с запоминанием адресов строк можно считать классической оптимизацией через препроцессинг: "выполним препроцессинг, потратим немного больше памяти для сохранения результатов этого препроцессинга, зато потом будем брать готовенькое, вместо того, чтобы каждый раз перевычислять заново".
Я не буду утверждать, однако, что эта овчинка стоит выделки, т.е. что такой перпроцессинг будет иметь какой-то оптимизационный эффект (скорее всего нет), но суть не в этом. Суть в том, что разница между вариантами, который вы преподнесли как "неправильный"/"неэффективный" и "правильный"/"эффективный" — эфемерна. Вы обфусцировали сущность первого варианта частоколом ненужных индивидуальных выделений памяти, и тем самым обманули сами себя.
P.S. Индивидуальное выделение памяти для строк матрицы, разумеется, не является безусловно бессмысленным. Оно может обладать ценностью в разнообразных jagged-array применениях, когда необходимо представлять "рваные"/разреженные матрицы и/или заниматься индивидуальным memory management для каждой строки. Но ваша-то статья говорит совсем не об этом…
Akon32
10.12.2016 22:41+2Тут можно поспорить.
Во-первых,a[i*n+j]
часто выполняется быстрее, чем 2 разыменования указателяa[i][j]
(доступ к памяти — медленный); во-вторых, компиляторы выносят за пределы цикла подобные лишние вычисления.
Так что оптимальный вариант зависит от конкретной ситуации.
И ещёнемного странно видеть рассуждения о студентах вместе с кодом
new double[n * n]
. Есть же механизм RAII, разумно будет его использовать. Иначе сложно корректно освободить память.TheCalligrapher
10.12.2016 23:03Не совсем понятно, о каком "споре" идет речь, если вы фактически повторяете именно то, что я сказал во второй части своего комментария.
Замечание жа про RAII в контексте данного обсуждения неуместно — речь идет совсем не об этом.
safinaskar
10.12.2016 23:58+2Рассмотрим данный вами фрагмент кода. Причём предположим, что обращаться к i-му j-му элементу мы будем как a[i][j]. Тогда в вашем варианте выделение памяти будет происходить быстрее, чем в варианте с выделением памяти для каждой строчки. А время обращения к i-му j-му элементу будет тем же. Но я в своей статье обращал внимание на обращение, а не на выделение. Поэтому я не стал усложнять статью приведением вашего варианта. И конечно, я о нём знал.
Теперь по поводу того, что быстрее, умножение или обращение к вот этим вот вашим «закешированным» результатам умножения. Конечно, первое. Т. к. для обращения к вот этому отдельному массиву нужно обращаться к памяти. Пускай даже это будет кеш первого уровня, но это всё равно обращение куда-то. А умножение можно сделать в одних только регистрах.
Допустим, есть матрица и нам нужно её удвоить. Причём допустим, что нужно это сделать, идя по столбцам, т. е. идя сперва по второму индексу, а потом по первому. Да, постановка задачи искусственна, т. к. по строчкам было бы быстрее. Но всё же предположим, что нам это зачем-то нужно. Например, потому что это упрощённый вариант некой реальной задачи, в которой действительно нужно идти именно по столбцам, и по строчкам никак не получится.
Так вот, допустим мы выделили память одним куском (double *a = new double[n * n]
). Тогда код будет выглядеть так:
for (int j = 0; j != n; ++j) // j идёт по столбцам, т. е. по второму индексу { for (int i = 0; i != n; ++i) // i идёт по строчкам, т. е. по первому индексу { a[i * n + j] *= 2; } }
А теперь допустим, что у нас есть этот ваш вспомагательный массив. А основная память выделена по строкам (как у меня в статье) или одним куском (как у вас), это не так важно. Тогда код будет выглядеть так:
for (int j = 0; j != n; ++j) // j идёт по столбцам, т. е. по второму индексу { for (int i = 0; i != n; ++i) // i идёт по строчкам, т. е. по первому индексу { a[i][j] *= 2; } }
Так вот, разумеется, первый код гораздо быстрее второго. В первом коде внутренний цикл будет оптимизирован так:
double *b = a + j; for (int i = 0; i != n; ++i) b[i * n] *= 2;
или так:
double *end = a + n * n + j; for (double *b = a + j; b != end; b += n) *b *= 2;
То есть фактически во внутреннем цикле процессор просто пройдётся по ряду ячеек в памяти, которые расположены с шагом n и удвоит их. Во втором же случае так соптимизировать будет невозможно. Процессору нужно будет пройтись по массиву a, разыменовать каждый элемент, и на основании его посчитать ещё один адрес и в нём уже удвоить значение. С учётом того, что обращение к памяти гораздо медленнее арифметических операций, это будет очень медленно.semenyakinVS
11.12.2016 03:53-2Нужно пробовать и смотреть на скорость. У меня где-то валялись несколько классов для перформанс-тестов (когда-то алгоритмы сортировок сравнивал с их помощью). Могу завтра бросить ссылку на проект (только вычищу его в начале). В понедельник, если до того времени никто не озаботится раньше, могу заделать, собственно, тесты для проверки всяких тезисов по поводу быстродействия работы с матрицами. Всяко осмысленнее разговора на уровне общих понятий будет.
safinaskar
11.12.2016 00:02Добавил небольшой UPD в статью, чтобы не было таких вопросов
TheCalligrapher
11.12.2016 00:21Я не понимаю, к чему это.
В моем комментарии нигде не сказано, что вариант с "кэшированием" результатов умножения будет каким-то образом работать быстрее. Абстрактный паттерн в данном случае действиельно "оптимизания через препреоцессинг", но работать это в данном конуретном случае будет скорее всего медленнее, о чем ясно сказано в моем комментарии. Поэтому мне не понятно, зачем вы разражаетесь в ответ исследованиями на тему скорости работы такого подхода.
Речь идет совсем не о скорости.
Целбю моего комментария является лишь демонстрация того факта, что физичекская организация хранения собственно полезных данных матрицы в обоих случаях не должна принципиально отличаться. Отличие, на которое вы напирали с самого начала статьи — лишь побочный эффект навязанного вами же способа выделения памяти. Ни более, ни менее.
safinaskar
11.12.2016 00:49что физичекская организация хранения собственно полезных данных матрицы в обоих случаях
В каких обоих случаях? Я тут вижу уже 3 способа. Один new, два new и мой "частокол".
Отличие, на которое вы напирали с самого начала статьи
Опять-таки, отличие между чем и чем?
В общем, поясните последний абзац
lookid
10.12.2016 23:35-6Это всё STL. Ад полнейший. Лучше бы убрали и взяли какие-нибудь корпоративные контейнеры гугла или ЕА. И модули добавили.
dimka11
11.12.2016 00:51Кроме c++ и fortran, в каких других языках нет многомерных массивов, а в каких есть?
ElectroGuard
11.12.2016 00:51К слову — Delphi давно работает с многомерными массивами на уровне компилятора. Как известного, так и неизвестного (динамические) размера. И в параметрах можно их передавать, позже узнавая и устанавливая размерность. И обращение идёт как Arr[i][j]. И в памяти подряд данные лежат. В общем — все плюшки.
aso
12.12.2016 08:29+1Паскаль изначально различал массивы и указатели «по дизайну».
Правда, там, в результате — были сложности с передачей массивов произвольного размера в процедуру.
dkosolobov
11.12.2016 01:47Вспомнился обширный интересный комментарий kraidiky о невероятной разумности компилятора фортран. Правда, он не стал, как автор, раздувать из комментария статью (может, всё таки, зря).
iperov
11.12.2016 11:22-2В C++ много чего нет, зато есть много ненужного мусора.
Я был ярым фанатом C++ как ребенок-максималист. Но сейчас повзрослел, остепенился, добавил пару плюсов в язык, и теперь смотрю в стабильное будущее.
BigW
11.12.2016 15:48По поводу массива с данными, а не с указателями, тут есть одна очень веселая штука, на которую я в свое время наступил. Времена WinXP и Server2003. Мне необходимо разместить в памяти изображение размером всего-то 300 метров (битмап-карта). памяти на машинке 1,5 гига (XP ела если мне не изменяет память метров 300-500 всего) На серваке больше 4, но программа на 32 бита. И в какой-то момент у меня программа начинает вываливаться с ошибкой — не могу выделить память… (malloc, кажется, возвращал ошибку). После перезагрузки — все ок! Начинаю разбираться и оказывается, что памяти то много, но одного большого куска куда бы влезло 300 метров нет… Выход — свой мэнеджер памяти %) приехали, называется…
В 7 и 10 вроде как подход к выделению поменялся, но, если честно, не следил. так что аккуратнее с памятью и стеком, даже в винде до сих пор себе можно вполне спокойно отстрелить ногу…
aso
12.12.2016 08:26+2Так вот, а в C передать массив в функцию нельзя. Точнее, можно, не нет специального синтаксиса, чтобы показать компилятору, что в функцию передаётся именно массив. Если написать:
void f (int a[2])
ну или:
void f (int a[])
То это будет эквивалентно такому коду:
void f (int *a)
Таки int * const a, что даёт некоторые нюансы.
Вообще, что характерно:
FORTRAN 77 (1980)[править | править вики-текст]
[...]
Увеличена максимальная размерность массива с 3 до 7. Сняты ограничения на индексы массива.
Усовершенствованы и расширены возможности работы с процедурами.
Fortran 2008 (2010)[править | править вики-текст]
Стандартом предполагается поддержка средствами языка параллельных вычислений (Co-Arrays Fortran)[5][11]. Также предполагается увеличить максимальную размерность массивов до 15,
(Вики, наше всё)
Т.е. ценой внесения в язык высокоуровневых абстракций (в отличие от Си/С++) — становится ограничение на предельную размерность массива, которую необходимо изменять на уровне стандарта…kbtsiberkin
12.12.2016 13:40-1А где может понадобиться 15-тимерный массив? Ограничение вполне уместно, т.к. в физических приложениях редко больше 4х нужно бывает (разные там струнные теории и иже с ними — особый случай, но не уверен, что народ там как раз на фортране считает — больше аналитики в этих областях).
aso
12.12.2016 14:10А где может понадобиться 15-тимерный массив?
Везде.
Ограничение вполне уместно,
Ой, шо?
Здесь только что били пяткой в грудь, шо Фортран — круть немерянная по сравнению с Си — а теперь «ограничение вполне уместно»?
т.к. в физических приложениях редко больше 4х нужно бывает
Фкаких «физических»?
(разные там струнные теории и иже с ними — особый случай,
Откройте для себя понятие фазового пространства.
Для материальной точки — это будет шесть измерений, для протяжённого тела (с вращениями) — уже девять.
Массив таких тел… ой.
Обсчёт электромагнитного поля — две векторные величины в каждой точке, шесть отсчётов на точку трёхмерного пространства.
Приращения полей — по три отсчёта на каждую ось для обоих полей.
Т.е. это всё влёгкую улетает далеко и за три, и даже за пятнадцать измерений.kbtsiberkin
12.12.2016 14:16С фазовыми пространствами и нелинейной динамикой вполне знаком. Всегда было проще делать кучку маломерных массивов, пусть даже их и 15-20 штук оказывалось. Впрочем, это вопросы технические. Предельная вложенность циклов также может ограничивать предел размерности.
aso
12.12.2016 14:45+1Ну вот о том и речь, что громогласные рассуждения про «замечательную способность по работе с матрицами» как-то незаметно переводятся на кучу несвязных маломерных массивов — от чего код начинает выглядеть просто чудовищно.
kbtsiberkin
12.12.2016 15:28+1Возможно, возможно. Вы ещё количество GOTO в некоторых программках наших не видели. По старинке, старшее поколение продолжает писать де-факто на fortran-77. Но научный расчёт — штука странная. И здесь уж точно позволительно компилятору быть умнее программиста, который и не программист по сути, а просто имеет за плечами базовый курс программирования, численных методов и некоторый опыт в весьма узкой, надо сказать, области.
Что замечено, опять же, на личном опыте:
1. Редкая программа используется более чем одним человеком. Есть всего пара примеров в поле зрения, где программы написаны давно, и потихоньку модифицируются. Но за перфекционизмом в коде не гонятся, благо программа простая и позволяет легко понять, что в ней есть — простое решение конечно-разностной системы уравнений. Остальные пишут код под себя. Да, это не оптимально с точки зрения затрат времени. Но зато позволяет разобраться в специфических методах и глубже понять особенности физики задачи, что на первых порах очень важно. В дальнейшем, при развитии темы, программа может потихоньку модифицироваться, что обычно сводится к добавлению в уравнения новых слагаемых и/или изменению граничных условий. Конечно, есть некоторый костяк алгоритмов, текст которых, будучи единожды написанным, в дальнейшем не меняются годами у одного и того же автора.
2. Редкая программа используется для решения более чем одной задачи. Не считая доработок в виде добавки новых слагаемых в уравнения — это правда. Тем более что на каждое подробное(!) исследование уходит не один год, а на написание оптимальной универсальной программы может понадобиться столько же времени. Разве что человек, стремящийся к ускорению счёта, проведёт оптимизацию кода или добавит в него директивы OpenMP. И то таких случаев тоже очень немного.
Важно помнить, что учёные в большинстве не пишут пакеты для других. Для нас компьютер — это та же логарифмическая линейка в совокупности с таблицами Брадиса, которыми просто надо уметь пользоваться, но нет нужды делать это в совершенстве и рисовать свои шкалы на лог.линейках.aso
12.12.2016 15:41-1По старинке, старшее поколение продолжает писать де-факто на fortran-77.
Хорошо хоть не Фортран-66.
Что замечено, опять же, на личном опыте:
1. Редкая программа используется более чем одним человеком. Есть всего пара примеров в поле зрения, где программы написаны давно, и потихоньку модифицируются.
Ну тогда вообще непонятен предмет разговора.
Люди не умеют программировать ни на Си/С++, на на чём другом.
Уйдут эти люди — придут другие, которые будут юзать Си, питон или Матлаб с Октавой.
Для МКЭ — Ансис или Саломе.
Ну и т.д.
А все разговоры о «преимуществах Фортрана» — это так, рассуждения для бедных.DistortNeo
12.12.2016 16:08+1О чём и речь. Математики-физики редко являются хорошими программистами, поэтому пишут как могут. А программисты не могут написать эффективную программу, потому что не хватает способностей понять то, что придумал математик-физик, и применить оптимизации.
Поэтому часто (но не всегда!) бывает, что математик дико неэффективно использует суперкомпьютер для тех задач, где достаточно использования обычного компьютера с GPGPU. Ничего плохого здесь нет: для суперкомпьютера код можно написать на коленке, в отличие от GPU.aso
13.12.2016 13:21-1О чём и речь. Математики-физики редко являются хорошими программистами, поэтому пишут как могут.
Странно.
А ведь программирование и ЭВМ выросли из математики — и длительное время рассматривались едва ли не как часть математики.
А программисты не могут написать эффективную программу, потому что не хватает способностей понять то, что придумал математик-физик, и применить оптимизации.
Мне, честно говоря, не совсем понятно — чего может не хватать матфизику для более-менее нормального понимания Си/С++. Не на уровне senior'а — но хотя-бы начального middl'а.
Не в смысле написания библиотек — а в смысле понимания и использования самого языка.
Поэтому часто (но не всегда!) бывает, что математик дико неэффективно использует суперкомпьютер для тех задач, где достаточно использования обычного компьютера с GPGPU.
Страшно слушать такое про математиков.
Сегодня, кажется, в среде математиков даже общепринятыми становятся обозначения из Вольфрамовской Математики ихних «закорючек».
Какой там «фортран», боже мой…DistortNeo
13.12.2016 17:42+3Странно.
А ведь программирование и ЭВМ выросли из математики — и длительное время рассматривались едва ли не как часть математики.
Ага, только вот программирование начиналось с алгоритмов и вычислительной математики. Сейчас же можно быть хорошим программистом, не понимая в математике вообще ничего.
Мне, честно говоря, не совсем понятно — чего может не хватать матфизику для более-менее нормального понимания Си/С++
Опыта и времени. С тем же успехом матфизик может вести бухучёт и класть плитку.
Навыки более-менее адекватного программирования на C++ появляются только через пару лет опыта программирования как основного рода деятельности. Если вы считаете, что это не так, значит именно место эффект Даннинга — Крюгера.
kbtsiberkin
12.12.2016 16:13+1Не будут. Мы их фортрану учим. Современному. Радиофизики, будущие железячники и софтовики, на нашем физфаке учат Си. Фундаментальные физики учат Фортран.
Есть ещё матлаб с симулинком, на соседней кафедре — там радиофизики в нём что-то своё моделируют. ANSYS я так же благополучно применял для ряда задач, где геометрия дурацкая была и сетку руками писать было бы лишней тратой времени.
Питон — он же интерпретируемый. Откуда там скорость счёта? Си — да, есть люди, которые периодически начинают писать на нём. Не справляются, быстро вязнут в указателях, итераторах и правильном выделении памяти. К вопросу о скорости выполнения подойти не успевают за время обучения или сроки выполнения проекта.mayorovp
12.12.2016 17:07+1Неужели нет более простых языков программирования, чем современный Фортран?
kbtsiberkin
12.12.2016 19:03У части студентов база в виде чего-нибудь, обычно паскаля, имеется. Таких у меня на потоке было процентов 60, сейчас статистику не наводил. Но вроде учат и сдают успешно. Другое дело, что сдают успешно, а программировать всё равно не умеют, когда на третьем курсе вдруг дело доходит до расчётных исследовательских работ. Или до моего спецкурса со странным названием «Решение задач на ЭВМ», который в английских резюме предпочитаю писать как «Advanced numerical methods».
По фортрану же — современный куда проще старого, 77-го. Just for fun переписывал несколько своих программ с f90 на f77, используя все его ограничения. Жутковато, честно говоря. А f90 изучал, проводя аналогии с паскалем, который до этого был в 10-11 классах. C начал осваивать так же на этапе старшей школы, в параллель с паскалем, но тоже чисто для себя. Правда, так его и не знаю, хотя разобраться в вычислительных программах и допилить их для своих нужд, в принципе, могу. Но не хочу.
nikolaynnov
12.12.2016 20:43Не будут. Мы их фортрану учим. Современному. Радиофизики, будущие железячники и софтовики, на нашем физфаке учат Си. Фундаментальные физики учат Фортран.
А потом мы спрашиваем: почему наши ученые не конкурентоспособные?
Слава не_знаю_даже_кому, что такое не во всех университетах. Вот в ННГУ на ФизФаке 15 лет назад обучали на C++/C#/Mathematica.kbtsiberkin
12.12.2016 21:26+2Не беспокойтесь, Mathematica и Maple (и MATLAB на радиофизическом профиле) у нас тоже есть в программе обучения. А если у человека с головой всё в порядке — он с любым языком освоится. Глобальная проблема не в языке, а в нынешней системе образования и финансирования науки.
Учёные не конкурентоспособные? Наукометрический холивар что ли развести ещё. Вокруг есть масса людей, прекрасно известных на мировом уровне, с прекрасными индексами цитирования. Навскидку — опять же наш город Пермь; провинция глубокая, да. Навскидку по ближайшим кабинетам: кфмн, 34 года, h=8; наш экс-завкаф, дфмн, Заслуженный деятель науки РФ, h=14; его супруга, дфмн, Заслуженный деятель науки РФ, h=16; профессор, дфмн, h=8, маловато вроде бы, но — adjunct professor в университете в США; профессор, дфмн, h=18; профессор, дфмн, завлаб, h=28. И утечки мозгов хватило в 90-е гг. Некоторые вернулись, правда. Но с некоторыми не вернувшимися удаётся держать связь — и таким образом уже не один десяток лет жива большая российско-французская коллаборация (к сожалению, совсем недавно прекратилась двойная аспирантура), российско-бельгийская коллаборация с участием ESA, и разные прочие приятные сердцу мелочи.
Везде есть люди, способные научить. И везде есть люди, способные научиться. Даже в глубине африканских саванн или амазонских джунглей, где племена до сих пор за выживание борются.
Но не везде есть условия. На грант РФФИ много не разработаешься при нынешних суммах и типичных коллективах в 8-10 участников. Или гранты поддержки Ведущих научных школ РФ, в коллективах которых по 80 человек, а сумма ещё ниже среднего РФФИ. С РНФ люди зашевелились, что характерно. И с «УМНИК»-ом, хотя это уже более специфическая область. Но всё потому, что возможности появились, и нормальная поддержка.
И наука наша адекватно себя на мировом уровне держит. Другое дело, что об этом не говорят массы, кому куда интереснее обсасывать очередной разбившийся «Прогресс» или искать вину Роскосмоса в неудаче марсианской миссии, несмотря на то, что посадочный модуль полностью принадлежал ESA.nikolaynnov
12.12.2016 23:10+1Ну ОК, наши пермские физики-фортранщики самые физически-фортранутые физики-фортранщики в мире, убедили. :)
Если, что, то я не считаю, что у нас проблема с конкурентноспособностью наших учёных. Тем более, что моя кафедра, например, процветала, в том числе из-за разработки и продажи коммерческого специализированного софта.
Но многие, когда видят утверждения, подобные тому, что я взял в цитату, не испытывают гордость за российскую науку, и в принципе я их понимаю, помню, как лет 13 назад плакали бывшие одноклассники, которых в НГТУ заставляли изучать фортран, и когда они слушали от меня про C#
kbtsiberkin
12.12.2016 21:34И ещё двоих забыл указать, из лаборатории «за стенкой».
Два дфмн: постарше (выпуск 1974 г.), h=20, активно работает с европейскими астрофизиками, и помладше (год рождения — 1974), h=16, специализируется в той же области. Оба в сущности занимаются магнитной гидродинамикой и математикой (вейвлет-анализом).ilmarin77
12.12.2016 23:18В западной науке эмпирическое правило: h ~ количество лет работы в науке (т.е после получения PhD).
h ёще по-разному считают, google scholar завышает довольно сильно по сравнению сo scopus, например.
kbtsiberkin
13.12.2016 11:52Здесь все данные из scopus, уж подписку университет обеспечивает.
Эмпирика эта примерно верна для физиков, но уже давно известно, что h=20 — это отличный показатель для активного физика и очень рядовой для активного химика или биолога. Для математиков h ниже.
aso
13.12.2016 13:00Оба в сущности занимаются магнитной гидродинамикой и математикой (вейвлет-анализом).
И как рисовать вейвлеты на фортране?
Рисуя тонны малоразмерных матриц? 0_0
Antervis
13.12.2016 06:04-1а как можно вообще доверить человеку писать код на любом яп, если он «вязнет в указателях, итераторах и правильном выделении памяти»? Это же база. Он потом так и будет писать код, который переписать быстрее, чем выполнить
mayorovp
13.12.2016 06:51Просто нужны языки где не требуются указатели, итераторы и правильное выделение памяти. И они даже есть.
Во-первых, можно вовсе убрать динамическое выделение памяти. Или оставить, но только на стадии инициализации программы. Именно этим путем идут, когда дают студентам Фортран.
Во-вторых, можно использовать языки со сборщиком мусора. Те же C# или Java.
Antervis
13.12.2016 07:39да, но это будет как бегун со сломанной в детстве ногой. И когда такому программисту скажут «че-то вот здесь оно долго работает, можешь сделать чтобы быстрее считалось?» он не просто не будет знать как ускорить, но даже не будет знать, из-за чего программа работает медленно.
mayorovp
13.12.2016 08:31Да кто скажет-то, если все программы "для себя" пишутся?
Обратите внимание, там учат физиков, а не программистов!
aso
13.12.2016 13:02Просто нужны языки где не требуются указатели, итераторы и правильное выделение памяти. И они даже есть.
Остаётся непонятным — зачем в Си/С++ активно использовать указатели и динамическое выделение памяти — ежели в нём не разбираешься?
Си достаточно хорош и без этого.
safinaskar
13.12.2016 12:35Да блин, мне кажется позиция kbtsiberkin давно уже всем понятна. Fortran позволяет сразу научиться писать код. Такой, какой нужен в высокопроизводительных вычислениях. Без необходимости разбираться с этими указателями. Поэтому его и любят в academia. И на удивление всякие умножения матриц на фортране работают так же быстро, как и на си. А сегфолт получить сложнее.
Да, си мощнее. Но физикам фортран лучше по указанным выше причинам. Физикам компьютер нужен лишь как инструмент. Им не нужно уметь по-настоящему хорошо прогать.
Но сразу хочу сказать. Я только что лишь попытался пояснить позицию kbtsiberkin. Сам я не фанат фортрана. Вся эта статья написана просто чтобы рассказать хабру интересный факт о фортране. Не более. Сам я прогаю на C++.aso
13.12.2016 13:06-3Да блин, мне кажется позиция kbtsiberkin давно уже всем понятна. Fortran позволяет сразу научиться писать код.
Только это будет говнокод.
Нечитаемый, немодифицируемый и требующий крайне высоких трудозатрат для своей поддержки.
А фортран плох, прежде всего — отсутствие ясной и чёткой концепции — «что это» и «для чего оно».
Языки «сверхвысокого уровня», типа Матлаба — имеют развитые средства вывода — графики, мультипликацию, симуляцию.
Си/С++ — близок к аппаратуре, и позволяет целенаправленно оптимизировать программы под неё.
А фортран?
«Напиши код абы как — а транслятор откомпилирует в идеальную программу»?
А вывод будет в виде таблиц?DistortNeo
13.12.2016 17:47+2В научной среде программный код является не конечным продуктом, а инструментом. Написал код на коленке — получил результат. Если результат не понравится, код успешно хоронится. А если результат хороший, тогда можно заморочиться и написать нормально.
alexeykuzmin0
14.12.2016 13:55+1Насколько я понимаю научную среду, если результат хороший, переписывать тоже незачем. Каждый код пишется один раз для одной статьи, и для большинства статей даже из областей, напрямую связанных с программированием (например, в теории оптимизации) кода алгоритма найти совершенно невозможно. Каким образом производится проверка экспериментальных данных — даже думать страшно.
mayorovp
14.12.2016 14:10+1Проверка экспериментальных данных обычно производится независимыми экспериментами.
aso
13.12.2016 12:57+1Не будут.
Человек предполагает — а бог располагает. :)
Мы их фортрану учим. Современному.
Вас бог покарает за развращение малолетних!!! ;)
Фундаментальные физики учат Фортран.
Ну т.е. всевозможные тензоры — в программах этих фундаментальных физиков — не реализуются. Ручками, всё ручками…
Чудесно.
Традиции — стррашшная сила…
Питон — он же интерпретируемый. Откуда там скорость счёта?
Не знаю — но люди что-то на нём кропают, есть NumPy, SciPy.
Есть (был?) какой-то проект на Питоне по сбору и расшифровке генетической информации — читал о нём лет пять — семь назад.
Не справляются, быстро вязнут в указателях, итераторах и правильном выделении памяти.
Гхм.
Во-первых — «прикладные» программисты должны пользоваться библиотеками.
Ну в во-вторых — паходу они таки не знают и не понимают Си — в заглавной статье тоже написано множество глупостей, к примеру.safinaskar
13.12.2016 13:03Каких глупостей? Мне интересно
aso
13.12.2016 13:11Например, глупостью является фраза, что double a[5][10] есть «массив указателей», «не размещаемый в памяти единым куском».
safinaskar
12.12.2016 19:11+1Лично я не говорил, что якобы фортран и вправду и по сей день имеет некие преимущества перед си. Не имеет. Я написал эту статью, просто чтобы обратить внимание на факт, который, может быть, многие не знают. А именно, что, оказывается, фортран в некоторых моментах удобнее си. И что лишь совсем недавно си наконец догнал фортран по скорости
Antervis
13.12.2016 08:00вы прицепились к отсутствию в старых версиях си и с++ слова restrict, которое в компиляторах появилось очень давно. Игнорируя оптимизации, которые есть (или возможны) в си/с++, и которых нет и не будет в фортране
Antervis
12.12.2016 09:56а за счет чего «Fortran быстрее C»?
safinaskar
12.12.2016 18:52?!?!?!? Дык про это вся моя статья была. Во-первых, restrict. До недавнего времени за счёт него Fortran был быстрее C. Далее, в настоящее время, видимо, они сравнялись по скорости. Но, скажем, лет 10-20-30 назад Fortran был действительно намного быстрее C. Тут в этих комментах ссылались на рассказ про супербыстрый оптимизатор фортрана, могу найти
Antervis
13.12.2016 06:12+1restrict делается одним условным define'ом, благо все основные компиляторы такую фичу поддерживают. А еще? Я даже не говорю о том, что стандарт языка и реализация его в компиляторе — чуть чуть разные вещи.
Shamov
12.12.2016 11:40+2Если бы в языке была возможность делать матрицы с доступом через [i][j], то ею бы всё равно никто не пользовался. Для максимальной эффективности всё равно пришлось бы делать специальный класс. Ведь при работе с матрицами чуть менее, чем всегда, нужны не столько операции доступа к произвольному элементу, сколько операции перехода с следующему элементу по вертикали или по горизонтали. И соответствующие итераторы можно реализовать вообще без умножения. Более того, переходы к следующему элементу нужны не сами по себе, а как часть более сложных операций, в которых участвуют весь i-й столбец и вся j-я строка. При помощи итераторов доступ к столбцам и строкам изнутри любых функций можно организовать, не вынимая самих элементов из матрицы.
safinaskar
12.12.2016 18:55-1Не согласен. Если в языке есть вот эти массивы, которые мне нужны ([i][j], но чтоб в памяти подряд), то никакие итераторы не нужны. Просто пишем тупой низкоуровневый код в стиле C. А оптимизатор сам уберёт эти умножения там, где надо
Shamov
12.12.2016 22:03Давайте проясним, что именно вы предлагаете. Нужно зафиксировать в стандарте языка С++ конкретный способ хранения двумерного массива в памяти, удобный лишь для работы с матрицами. Причём при помощи кода, написанного в стиле языка С. Кроме того, ещё нужно зафиксировать требование к оптимизатору убирать умножение там, где надо. Это, кстати, где конкретно? Видимо, в стандарте должен быть прописан некий эвристический алгоритм, позволяющий оптимизатору определить, когда программист использует двумерные массивы для хранения матриц, а когда нет.
Ну, что ж! Обязательно напишите пропозал и держите нас в курсе. Очень интересны комментарии членов комитета.
safinaskar
12.12.2016 22:48Да не предлагаю я добавить в C++ многомерные массивы в стиле Fortran или C. Вся моя статья нужна просто, чтобы рассказать про этот курьёзный, так сказать, факт. Что в Fortran есть «нормальные» многомерные массивы, а в C++ — нет. Этот факт был удивительным для меня в своё время.
Кроме того, ещё нужно зафиксировать требование к оптимизатору убирать умножение там, где надо
Поясню, что я тут имел в виду. Рассмотрим такой код на C++:
double *a = new double[n * n]; for (int i = 0; i != n; ++i) for (int j = 0; j != n; ++j) ++a[i * n + j];
Здесь во внутреннем цикле есть умножение. Но если скомпилить это с оптимизацией, это умножение будет вынесено за пределы внутреннего цикла. Ну или убрано вовсе. Я имел в виду только это. То есть вот эту оптимизацию, которая уже есть в компиляторах.Shamov
13.12.2016 00:21+1Есть ещё один курьёзный факт. В С++ вы можете переопределить оператор [] у собственного класса матрицы и использовать его точно так же, как двумерный массив. И память для элементов сможете выделять так, как пожелаете. Зачем при наличии таких возможностей ещё и дополнительно перегружать обычные массивы лишними ограничениями на то, каким образом они должны храниться в памяти в многомерном случае?
mayorovp
13.12.2016 05:57Если я правильно помню, нельзя перегрузить оператор [] так, чтобы он принимал два индекса.
Antervis
13.12.2016 06:13+1вы можете перегрузить operator [] так, чтобы он возвращал reference wrapper, который в свою очередь перегрузит operator [] для другой размерности. И будет вам array[i][j][k];
semenyakinVS
14.12.2016 17:47Сразу вспомнилась старая статья на Хабре, где чувак делал оператор --> (длинная стрелка)…
Кстати, у нас на проекте почему-то били по пальцам за использование операторов. Типа, код не очевидным делается от этого и можно лишние операции получить случайно. Слышал, это типа распространённое мнение. Но сам считаю что иногда можно — и использую.DistortNeo
14.12.2016 17:57+1А ещё операторы «головастик вперёд» и «головастик назад»: ~- и -~.
Сам считаю допустимым перегрузку операторов только для чисел, иногда — для векторов.
Antervis
15.12.2016 06:32+1Кстати, у нас на проекте почему-то били по пальцам за использование операторов
Многие начинающие программисты, только познакомившись с переопределением операторов, очень любят определять операторы (всякие << >> ^) там, где простые функции очевиднее. А вот случаи где операторы действительно нужны и удобны встречаются намного реже и, как правило, требуют более опытного программиста (например, написание собственного контейнера с итераторами). Поэтому проще запретить
… и можно лишние операции получить случайно
Оператор отличается от явного вызова функции только семантически.semenyakinVS
15.12.2016 15:21Оператор отличается от явного вызова функции только семантически
На проекте это объясняли так, что, мол, выражение "vec = ((a+b)/r)*A" визуально выглядит невинно и не предвещает "vec.set(a.sum(b).divScalar( r ).mulMatrix(A))" со всеми вытекающими из этого временными объектами и умножениями. Я немного пробовал спорить — мне ответили, что был печальный опыт использования операторов. Я поверил и старался ими не усердствовать.wander
15.12.2016 15:34+2В книге «Шаблоны С++. Справочник разработчика», есть целый раздел, посвященный оптимизации таких выражений, для исключения создания «лишних» временных объектов. Описанный подход немного потерял актуальность с выходом новых стандартов, но для понимания сути очень полезно почитать, я думаю. Чтобы не слепо верить и не никогда использовать, а разобраться и делать осознанный выбор.
DistortNeo
15.12.2016 16:58В моём проекте по обработке изображений операция (a + b) / r представляет собой создание временного объекта, который только накапливает операции. При каждом обращении к пикселю (x, y) производится вычисление (a(x,y) + b(x, y)) / r(x, y).
Создание объекта происходит только при явном вызове:
((a + b) / r * A).instance();
На С++ с шаблонами это делается на раз-два. А вот чтобы добиться того же эффекта на C#, чтобы не было виртуальных вызовов, дженериков, да ещё чтоб все опрации были параллельными, пришлось позаморачиваться с кодогенерацией на лету.mayorovp
15.12.2016 17:04С другой стороны, в C# очень простая кодогенерация на лету, в отличие от C++...
Shamov
13.12.2016 08:53-2Либо можно перегрузить оператор ,(запятая) для int'ов, чтобы он возвращал некий объект типа matrix_position_t, и уже для него перегрузить [].
Antervis
15.12.2016 06:24нормальные компиляторы давно умеют не просто «выносить умножения за пределы внутреннего цикла», но и менять порядок итерации, если он не является оптимальным. После чего еще и применять SSE инструкции для работы с этим массивом. Итого ваш неоптимизированный код над многомерным массивом развернется в линейный проход по 4/8 элементов. В фортране почему-то (наверно в силу хитрой реализации многомерных массивов) порядок индексации в коде важен (кто-то в комментариях писал).
Antervis
15.12.2016 06:14возможно, вы не в курсе, но арифметика на итераторах в бинарном виде преобразуется в операции над адресами точно так же, как арифметика на указателях и операторах []. Если только не используются какие-то оболочки, которые компилятор не может оптимизировать. STL в флагманских компиляторах оптимизируется на ура.
kbtsiberkin
12.12.2016 13:38+1Меня тут внезапно призвал phprus
Главный вопрос, насколько понимаю, жив ли фортран и где именно он жив? И народ по-прежнему не верит, что язык с 50-летней историей активно применяется? Ну это вы зря, ей-богу. Откуда бы тогда взялись стандарты Фортран 2003 и 2008, которые хоть и с запозданием, но начинают воплощаться в компиляторах?
А кроме того, уже не первый год уверен, что никакая Mathematica и даже C++ не позволяют добиться тех же результатов с приемлемым уровнем простоты реализации. Плюс отлаженность, скорость, оптимизация и прочие плюшки, которые можно получить на интеловских компиляторах, благо на кафедру удалось приобрести для кластера комплект (давненько уже) и пощупать его на честной основе. Ну и на свободных, в общем-то, тоже много интересных возможностей есть, если не обращать внимания на оптимизацию под процессоры.
А активность использования Фортрана у нас вполне себе велика. Фактически, в Пермском научном центре среди гидродинамиков-расчётчиков можно выделить три типа: первые считают на фортране, вторые — в пакетах типа ANSYS, третьи, недавно обнаружились — воплощают метод конечных разностей в Mathematica. В московских институтах, специализирующихся на механике сплошных сред, ситуация выглядит аналогично. По-поводу, скажем, задач квантовой механики и физики магнетизма, которых у нас не так много — выборка слишком невелика, наверное, чтобы статистику навести. Тут я пока предпочитаю руками на бумажке, но недавно доросла одна задача до необходимости численного счёта — за 20 минут накидал на Фортране программку для взятия интеграла в двумерной области, и она благополучно шуршит уже вторую неделю, выдавая разные результаты.
По собственному опыту и по взгляду на коллег имею следующее впечатление: чтобы успешно писать на C++, надо суметь разобраться с классами и основами ООП, чтоб хотя бы представлять устройство и структуру реализуемой программы. Да, есть сферы, где C/C++ на порядки лучше Фортрана. Моя программистская практика сводится прежде всего к большому количеству именно вычислительных программ на Фортране и C. Так вот, на Фортране вообще думать не надо, что и куда. Завёл кучу переменных, написал, как им положено себя вести и что с ними происходит, и запустил счёт.
Среди этого немножко затесалась работа с микроконтроллерами, и с ними использую именно компиляторы на основе C. На почве Фортрана было тяжеловато осваивать, но в целом жить можно. Но реализовывать численный счёт на них было бы туговато.Vjatcheslav3345
12.12.2016 22:59Может, использовать вместо С — Аду, возможно, пожертвовав небольшой частью скорости? Ада — тоже стабильный язык (не меняется десятилетиями (последняя версия языка — от 2012 и я не знаю никаких серъёзных причин, по которым он опять сильно изменится в течении лет 30)), кроме того, понятный, привычным к паскалю людям (которых в России и СНГ немало), — поэтому наработки на нём не пропадут с течением десятилетий. Судя по тому, что его часто применяют для встраиваемых систем и систем реального времени а также военной техники — язык не из медлительных и не требует суперресурсов для работы, но, при том, способный сделать жизнь "программирующего непрограммиста"-физика, студента или аспиранта более лёгкой, не мучая его попусту.
selgjos
13.12.2016 11:28-2А кроме того, уже не первый год уверен, что никакая Mathematica
Какое отношение это имеет к высокопроизводительным вычислениям?
и даже C++ не позволяют добиться тех же результатов с приемлемым уровнем простоты реализации.
Т.е. ваша проблема только в том, что вы не осилили ничего кроме фортрана? Аргумент все аргументам аргумент.
Плюс отлаженность, скорость, оптимизация и прочие плюшки, которые можно получить на интеловских компиляторах
Интеловский компилятор является самым слабым компилятором, а как максимум топ2, если мы ограничим код тем, что осилите написать вы. Для справки — в мире существует всего 3компилятора.
Вы используете ifc даже не понимая в чём его собственно основная фишка. Его фишка — это реплейс вашего дерьма на готовый вменяемый код. Он понимает множество паттернов, которые используют для написания дерьма за партой. А так же вмести с ним в комплекте идут десятки блобов. Собственно когда фотран-адепт берёт своё дерьмо и сравнивает с mkl — он потом молится на штеуд. Ему кажется, что это какое-то невероятно колдунство.
И собственно тогда, когда дело доходит уже до сборки вменяемого кода — интел-днище даже в шедулинг под свои камни не может и сливает в хлам гцц, как и шланг.
скорость
А можете хоть что-то показать на фортране? А то послушаешь вас фортран педалирует, а как посмотришь на мир — хрен где его найдёшь, кроме как в мусорном баке.
за 20 минут накидал на Фортране программку для взятия интеграла в двумерной области, и она благополучно шуршит уже вторую неделю, выдавая разные результаты.
К высокопроизводительным вычислениям ваше изваяние отношения не имеет.
Собственно поэтому школьники снимают с х86 пару гигафлопс, а нормальные пацаны терафлопс. Понюхайте хоть штеудские блобы. А так да, в параллельной вселенной всё круто — накидал дерьма и веришь, что оно само смоглось.
Так вот, на Фортране вообще думать не надо, что и куда.
Ну вот она собственно и причина.
kbtsiberkin
13.12.2016 12:01-1Ну хорошо. Допустим. Что тут оптимизировать, чёрт возьми? Двумерный интеграл в шестиугольной области тут. Примерно вида I(x,y) = Int( f(x, y, \xi, \eta) d\xi d\eta ), только в полярных координатах, с записью результата в файл и ещё дополнительным его усреднением по углам.
Сумма она сумма и есть, распараллелить разве что слегка (сетка не того размера только). Если у кого-то после этого кода вытекут глаза, уж пардоньте, я физик. :)
Заголовок спойлераprogram Graphene_Chi
real(8), parameter :: Pi = 3.14159265d0, &
K0 = 2.0d0*Pi / dsqrt(3.0d0)
real(8), dimension(:), allocatable :: chi_t
real(8), dimension(:,:), allocatable :: phi
real(8), dimension(:,:,:), allocatable :: Kx, Ky, chi
real(8), dimension(1:6) :: T = (/ Pi / 3.0d0, 0.0d0, -Pi / 3.0d0, -2.0d0*Pi / 3.0d0, Pi, 2.0d0*Pi / 3.0d0 /)
real(8) K0N, Pi3M, t0, q, beta, chi_0
integer N, M, p, i, j, p1, i1, j1, n_Ma
character(255) outname, avgname
open(1, file = "input.txt", form = "formatted")
read(1,*) N, M, t0, beta, n_Ma, outname, avgname
close(1)
allocate(phi(1:6,0:M))
allocate(chi_t(0:N))
allocate(Kx(1:6,1:N,0:M))
allocate(Ky(1:6,1:N,0:M))
allocate(chi(1:6,1:N,0:M-1))
q = 1.5d0*dsqrt(3.0d0)
K0N = K0/N
Pi3M = Pi / (3.0d0*M)
write(*,'(A,$)')"Grid creation starts..."
! grid - angular
do p = 1, 6, 1
do j = 0, M, 1
phi(p,j) = T(p) - Pi / 6.0d0 + j*Pi3M
enddo
enddo
! grid - radial; point (0, 0) should be calculated separately
Kx = 0.0d0
Ky = 0.0d0
do p = 1, 6, 1
do i = 1, N, 1
do j = 0, M, 1
Kx(p,i,j) = (real(i)/real(N))**2*K0*dcos(phi(p,j)) / dcos(phi(p,j) - T(p))
Ky(p,i,j) = (real(i)/real(N))**2*K0*dsin(phi(p,j)) / dcos(phi(p,j) - T(p))
enddo
enddo
enddo
write(*,'(A)') " done"
! susceptibility integration
chi = 0.0d0
write(*,'(A)')"Integration starts..."
do p1 = 1, 6, 1
write(*,'(A,I4,A)') "Sector ", p1, " starts..."
do i1 = 1, N, 1
write(*,'(A, I4)') "Line ", i1
do j1 = 0, M-1, 1
do p = 1, 6, 1
do i = 0, N-1, 1
do j = 0, M-1, 1
chi(p1, i1, j1) = chi(p1, i1, j1) + &
0.25d0*( F( Kx(p,i,j), Ky(p,i,j), Kx(p1,i1,j1), Ky(p1,i1,j1), beta, n_Ma ) + &
F( Kx(p,i+1,j), Ky(p,i+1,j), Kx(p1,i1,j1), Ky(p1,i1,j1), beta, n_Ma ) + &
F( Kx(p,i,j+1), Ky(p,i,j+1), Kx(p1,i1,j1), Ky(p1,i1,j1), beta, n_Ma ) + &
F( Kx(p,i+1,j+1), Ky(p,i+1,j+1), Kx(p1,i1,j1), Ky(p1,i1,j1), beta, n_Ma ) ) * &
( dsqrt(kx(p,i+1,j)**2 + ky(p,i+1,j)**2) - dsqrt(kx(p,i,j)**2 + ky(p,i,j)**2) ) * & ! dk
0.5d0*( dsqrt(kx(p,i+1,j)**2 + ky(p,i+1,j)**2) + dsqrt(kx(p,i,j)**2 + ky(p,i,j)**2) ) * Pi3M ! dphi
enddo
enddo
enddo
enddo
enddo
write(*,'(A)') " done"
enddo
write(*,'(A)') " done"
chi_0 = 0.0d0
do p = 1, 6, 1
do i = 0, N-1, 1
do j = 0, M-1, 1
chi_0 = chi_0 + &
0.25d0*( F( Kx(p,i,j), Ky(p,i,j), 0.0d0, 0.0d0, beta, n_Ma ) + &
F( Kx(p,i+1,j), Ky(p,i+1,j), 0.0d0, 0.0d0, beta, n_Ma ) + &
F( Kx(p,i,j+1), Ky(p,i,j+1), 0.0d0, 0.0d0, beta, n_Ma ) + &
F( Kx(p,i+1,j+1), Ky(p,i+1,j+1), 0.0d0, 0.0d0, beta, n_Ma ) ) * &
( dsqrt(kx(p,i+1,j)**2 + ky(p,i+1,j)**2) - dsqrt(kx(p,i,j)**2 + ky(p,i,j)**2) ) * & ! dk
0.5d0*( dsqrt(kx(p,i+1,j)**2 + ky(p,i+1,j)**2) + dsqrt(kx(p,i,j)**2 + ky(p,i,j)**2) ) * Pi3M ! dphi
enddo
enddo
enddo
chi_0 = 0.5d0*chi_0 / (2.0d0*Pi)**2*q
chi = 0.5d0*chi / (2.0d0*Pi)**2*q
! susceptibility output
write(*,'(A,$)')"Output starts..."
open(1, file = trim(outname), form = "formatted")
write(1,'(1x,I4,3E18.5E3)') 0, 0.0d0, 0.0d0, chi_0
do p = 1, 6, 1
do i = 1, N, 1
do j = 0, M-1, 1
write(1,'(1x,I4,3E18.5E3)') p, Kx(p,i,j), Ky(p,i,j), chi(p,i,j)
enddo
enddo
enddo
close(1)
write(*,'(A)') " done"
open(1, file = trim(avgname), form = "formatted")
chi_t(0) = chi_0
write(1,'(1x,2E18.5E3)') 0.0d0, chi_t(0)
do i = 1, N, 1
chi_t(i) = 0.0d0
do j = 0, M/2, 1
chi_t(i) = chi_t(i) + chi(1,i,j)
enddo
chi_t(i) = 2.0d0*chi_t(i) / M
write(1,'(1x,2E18.5E3)') Ky(6,i,0), chi_t(i)
enddo
close(1)
write(*,'(A)') " done"
deallocate(phi)
deallocate(Kx)
deallocate(Ky)
deallocate(chi)
contains
! electron dispersion relation
real(8) function E(x, y)
real(8) x, y
E = t0*dsqrt( 1.0d0 + 4.0d0*dcos(0.5d0*y)**2 + 4.0d0*dcos(0.5d0*y)*dcos(0.5d0*dsqrt(3.0d0)*x) )
end function E
! subintegral function
real(8) function F(x, y, x1, y1, beta, n)
real(8) x, y, x1, y1, beta, w_n
integer n
w_n = (2*n+1)*Pi / beta
F = ( (-w_n**2 - (E(x+x1,y+y1)**2 - E(x,y)**2) )*E(x+x1,y+y1)*dtanh( 0.5d0*beta*E(x+x1,y+y1) ) + &
(-w_n**2 + (E(x+x1,y+y1)**2 - E(x,y)**2) )*E(x,y)*dtanh( 0.5d0*beta*E(x,y) ) ) / &
( ( w_n**2 + (E(x+x1,y+y1) + E(x,y))**2 ) * ( w_n**2 + (E(x+x1,y+y1) - E(x,y))**2 ) )
end function F
end program Graphene_Chi
mobi
13.12.2016 13:05+3Вы элементы массивов не в том порядке обходите, наружный цикл желательно делать по последнему индексу, и т.д. вплоть до внутреннего по первому. Плюс, сравнить с вариантом, когда индекс 1:6 не первый, а последний — я не знаю, что в итоге будет лучше векторизовано, если функция F будет заинлайнена (-ipo в ifort), — операции над 6 элементами (плюс — размер известен, минус — не степень двойки), или цикл 0:N-1. Для лучшей поддержки avx можно попробовать выровнять элементы массива, используя 1:8 вместо 1:6. Ну и, OpenMP никто не отменял.
Salabar
12.12.2016 22:35Почему отсутствие многомерных массивов в STL — это такая проблема? Вот он пишется за 24 строчки (25, public забыл). Любой компилятор новее cfront заинлайнит вызов конструктора и получится тот же самый a[i*n+j]. Еще сорок строчек — это по правилам сделать операторы копирования, перемещения и т.п. Можно упороться шаблонами, чтобы у нас были скольки-угодномерные массивы, если очень хочется, еще строчек на сто.
http://pastebin.com/BBEsSAUM
HOMPAIN
>Так вот, а в C передать массив в функцию нельзя. Точнее, можно, не нет специального синтаксиса, чтобы показать компилятору, что в функцию передаётся именно массив. Если написать
void f (int a[]) — это разве не говорит компилятору, что будет именно массив? То что туда можно пихнуть не массив, а в принципе что угодно — это скорее дополнительная фича языка.
>А значит, если мы передаём в функцию «массив» a и «массив» b, то передаваться будут указатели. А значит, у компилятора нет никакой информации о том, собираемся ли мы, используя один указатель, читать/писать память, доступную из другого, или нет
Какая связь массивов и указателей с тем, что две перемененные не зависят друг от друга внутри функции? Если бы компилятор знал что то это массивы, то я бы не смог один в другой записывать?
akzhan
Смысл в том, что массивы A и B, определенные в Fortran, однозначно не пересекаются.
Аналог в C++ -
Этот хинт объясняет компилятору, что объём памяти, на который указывает A, в пределах функции точно не пересекается с объёмом памяти, на который указывает B. Это позволяет оптимизировать многие операции, например, такие, как копирование данных.
Подробнее https://ru.wikipedia.org/wiki/Restrict
P.S.: Нотация [] в C/C++ идентична нотации *. По крайней мере на практике.
safinaskar
Нет. Эта конструкция вообще ничем не отличается от void f (int *a). Да, это совершенно нелогично, но это так. Можете проверить, что в любом коде замена одной конструкции на другую ничего не меняет
DistortNeo
Есть только один случай, когда int[] и int* не эквивалентны — перегрузка вызовов в C++:
Здесь f1, f2, f3 — идентичные функции, но функция f4 может принимать на вход исключительно ссылки на массивы из 100 интов.
TheCalligrapher
С одной стороны, я не совсем понимаю, какое отношение вариант
f4
имеет к вопросу эквивалентности (или неэквивалентности)int []
иint *
. В этом варианте параметр имеет типint (&)[100]
, а это неint []
и неint *
. Поэтому как это может быть "одним случаем, когдаint[]
иint *
не эквивалентны" — в упор не ясно.Если говорить именно об
int []
, то никакой неэквивалентности быть не может.С другой стороны, если говорить об общем случае типа
T [N]
в списке параметров функции, то определенные отличия cT *
есть. Например, в С требуется, чтобыT
был полным (complete) типом (требование снято в С++). Также в обоих языках требуется положительностьN
, если оно указано. Эти требования, понятное дело, не распространяются на вариантT *
.DistortNeo
Это имеет практическое значение, т.к. позволяет сделать так, чтобы для T* вызывалась одна функция, а для T[N] другая.
Лучше дайте ответ на вопрос: верно ли, что если типы T1 и T2 эквивалентны, то и типы T1* и T2* будут эквиваленты?
В первом случае вы получите ошибку, что функция уже определена, во втором и третьем случаях — нет, это будет три перегрузки одной функции.
А самое смешное, что во всех случаях typeid будет возвращать одинаковый результат, т.е. typeid(int[100]) == typeid(int[]) == typeid(int*).
TheCalligrapher
Видимо мне надо более впрямую выражать свои мыслои, а не заниматься дипломатичным хождением вокруг да около.
Поэтому еще раз: тип
int (&)[100]
не имет ничего общего с типамиint *
иint [100]
, поэтому ваш пример сf4
никакого отношения к вопросу эквивалентностиint *
иint [100]
не имеет. Т.е. написана ерунда.Далее: да, в языке С и С++, если типы
T1
ИT2
эквивалентны, то и типыT1 *
ИT2 *
тоже эквивалентны.Но вы, очевидно, запутались в природе "эквивалентностей" наблюдаемых в списках параметров функций. На самом деле в языках С и С++ типы
T [N]
иT *
эквивалентными не являются и никогда не являлись. "Эквивалентность" о которой идет речь в данном случае — не более чем следствие неявной замены типаT [N]
на типT *
в процессе интерпретации объявления функции языком. Эта подмена — четко выделенный и оговоренный в спецификациях этих языков отдельный шаг процесса такой итерпретации, а не следствие какой-то врождленной натуральной "эквивалентности"T [N]
иT *
.Еще раз напомню, кстати, что даже в параметрах функций коррекность обявления типа
T [N]
проверяется еще до выполнения вышеупомянутой подмены, то есть при неполном типеT
и/или неположительном значенииN
вы получите ошибку в языке С, в то время как проблем сT *
не было бы. Т.е никакой полной "эквивалентности" тут нет.А уж откуда вы взяли бред про
typeid(int[100]) == typeid(int[]) == typeid(int*)
— ума не приложу. В языке С++ все этиtypeid
дают попарно неравные результатыВывод
http://coliru.stacked-crooked.com/a/84c8488ed029d2e0
DistortNeo
… которая вполне успешно используется в STL в функции begin, например.
Наверное потому, что мой компилятор (Intel C++ Compiler) здесь выдаёт true, а не false.
TheCalligrapher
Где и как именно в функции
begin
используются "исключения из "эквивалентности"int *
иint []
?Ну уж я не знаю, как мог Intel C++ Compiler так опростоволоситься. У меня нет под руками живого Intel C++ Compiler, но разглядывание ассемблера от Intel C++ Compiler на godbolt показывает, что для этих типов он генерирует раздельные
type_info
объекты...DistortNeo
Да, именно этот момент я и упустил.
T[N] меняется на T*, но (T*)[N] на T** — нет.
Возможно, баг. У меня при компиляции в x86 вывод 1, 1, 1, а при компиляции в x64 вывод 1, 0, 0. Должно быть 0, 0, 0, понятное дело.