LINUX.ORG.RU

как ускорить вычисление в «for»?

 , ,


1

1

есть вот такое:

double a, b, c;
vector<double> V;

for (int i = 0; i < V.size(); ++i) {
	if(i > 1) V[i] = f(V.at(i-2), V.at(i-1));
	else 	  V[i] = i;
}
где V.size()>1e10; f(V.at(i-2), V.at(i-1)), например a*V.at(i-2) + b*V.at(i-1)+c*((V.at(i-2))/(V.at(i-1))).

как можно узнать(посчитать) побыстрее V.back()? можно и без vector, for...


можно попробовать вынести if из цикла, но обычно компилер сам это делает

Deleted
()

Тебе здесь вообще не нужен массив, нужно знать только последние два значения. Чтобы посчитать совсем быстро нужно написать на бумажке свою рекурсивную формулу и подумать как её можно превратить в обычную.

mashina
()
Ответ на: комментарий от Deleted

if уже выносил. не ускорило.

rgB
() автор топика
Ответ на: комментарий от x3al

const. для «понимания» упростил запись.

rgB
() автор топика

ВЕКТОР НЕ НУЖЕН!!1

        double prev_val = 1.0, prev_2_val = 0.0;
        for (unsigned int i = 2; i < V_size; ++i) {
                double new_val = f(prev_2_val, prev_val);
                prev_2_val = prev_val;
                prev_val = new_val;
        }

Результат в prev_val.

Deleted
()
Ответ на: комментарий от mashina

не все так просто. для каждого for, вообщем, a, b, с - разные... V.back() вывести не реально...
математика максимально уже упрощена...

rgB
() автор топика
Ответ на: комментарий от rgB

математика максимально уже упрощена

Интересно, а ты реально выделаешь массив на 80Gb чтобы это всё посчитать или просто такую хрень запостил не долго думая как бы задать вопрос по «математике» в разделе «development»?

mashina
()
Ответ на: комментарий от mashina

"немного" переборщил с порядком в size.[но это сути не меняет]
это жрет менее 1GB...

долго думая... по мелочам (в моем понимании) не обращался бы.
эта часть c for осталась проблематичной.
на оперативку сильно не смотрю. главнее cpu.

rgB
() автор топика
Ответ на: комментарий от ymuv

я гдето когдато вычитал, что с .at() считывание элементa происходит быстрее. и многие v переписал на .at(i)
и это проверим. спасибо.

rgB
() автор топика
Ответ на: комментарий от ymuv

.at() заменить на []. Не будет проверки на выход за пределы вектора.

Да тут вообще вектор не нужен.

Вынести if.

И if тут так же не нужен.

Deleted
()
Ответ на: комментарий от Nietzsche

конь не сферический.
это методы «nextnano» [а они закрыли код]. но под конкретную [не обобщённую] задачу.

rgB
() автор топика
Ответ на: комментарий от Nietzsche

Если это вопрос не про сферического коня, а необходимо практическое решение конкретной задачи, то я бы искал варианты тут...

Да, OpenCL ему действительно очень не хватает. Сожрать же просто так всю память мало, нужно ещё запустить процесс на каком-нибудь наименее приспособленном для задачи железе замедлив всё в несколько раз.

mashina
()
Ответ на: ВЕКТОР НЕ НУЖЕН!!1 от Deleted

спасибо (проверено)! скорости не добавило (визуально), но плюс в том, что теперь нет ограничения в size!

rgB
() автор топика

и последний вопрос про сферического коня:

vector<double> V1, V2, V3, vec(100);

for(unsigned i = 0; i < vec.size(); ++i) {
	vec[i]=f(V1,V2,V3,i);
}
f(V1,V2,V3,i) нужно ли объявить это как double f(многo vectors), если оно используется в нескольких местах.
создание таких функций double f(многo vectors) замедляет работу (время на передачу векторов функции) или эти функции удобны только для чтения?

rgB
() автор топика
Ответ на: ВЕКТОР НЕ НУЖЕН!!1 от Deleted

вечером отпишусь о затраченом времени вектор-метод vs этот метод для разных vector.size()

rgB
() автор топика
Ответ на: комментарий от rgB

не все так просто

Твой код не спасти, никак.

для каждого for

Если у тебя форов много - это может тебя спасти. Можно за время одного считать штук 100.

anonymous
()
Ответ на: комментарий от rgB

используется еще #pragma omp parallel for

Что ты там параллелить собрался, не подскажешь?

anonymous
()

1. Вынести if наружу.
2. Избавиться от at() в пользу [].
3. Избавиться от v.size() на каждой итерации.
4. Перейти от int к size_t.
5. Префиксный инкремент тут нафиг не нужен.

andreyu
()
Ответ на: комментарий от andreyu

1. Вынести if наружу.
2. Избавиться от at() в пользу [].
3. Избавиться от v.size() на каждой итерации.

нинужно мусорить в коде, это все компилятор сделать должен

anonymous
()
Ответ на: комментарий от x3al

Компилятор же недостаточно умный

Вектор же шаблонный, заинлайнит и после этого сообразит что это константа

anonymous
()
Ответ на: комментарий от anonymous

Вектор же шаблонный, заинлайнит и после этого сообразит что это константа

Это зависит внутренности for { } - если она тоже заинлайнится и компилятор догадается что она не оказывает сайд эффектов на V, то будет так. Иначе такие оптимизации невозможны.

mashina
()
Ответ на: комментарий от andreyu

1. переписал это все как this
2. исправил at() в пользу [].
3. int num_poi = v.size() делаю сразу (или до) по объявлению вектора, если эта инфа нужна часто.
4. займусь этим
5. а как тогда обращаться к каждой ячейке? .begin() - .end() использовать?

rgB
() автор топика

независимо от V.size() (время на создание вектора не учтено).
для одной итерации for с вектором затрачивается ~26 машинного времени (arb.unit.).
для одной итерации for с double затрачивается ~9 a.u.
после усложнения формулы f(V.at(i-2), V.at(i-1)) соотношение такое 35 a.u.(vector) - 13 a.u. (double);

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

rgB
() автор топика
Ответ на: комментарий от anonymous

1. Вынести if наружу.
2. Избавиться от at() в пользу [].
3. Избавиться от v.size() на каждой итерации.

нинужно мусорить в коде, это все компилятор сделать должен

Компилятор самовольно избавится от проверок выхода за границы в at(), сам догадается, что v.size() в данном случае константа?

andreyu
()
Ответ на: комментарий от rgB

5. а как тогда обращаться к каждой ячейке? .begin() - .end() использовать?

Зачем? Есть префиксный инкремент, есть постфиксный. Но в вашем случае префиксный не дает каких-либо ускорений. Вы же инкрементите pod тип, а не итератор.

andreyu
()
Ответ на: комментарий от andreyu

если верить этому то смысл есть только в переходе на size_t.
a префиксный или постфиксный... пока оставим как есть.

rgB
() автор топика
Ответ на: комментарий от rgB

Яж тебе задал конкретный вопрос, ответить, не? Зачем ты отвечаешь каким-то несвязным набором слов?

Давай задам ещё раз - вычислять 100разных форов написанных нормально и 1 написанный тобою стоит столько же. Если у тебя есть эти 100разных форов, то сделать что-то вменяемое можно, если нет - нет. Т.е. тебе надо конкретно ответить на вопрос - да/нет.

используется еще #pragma omp parallel for

И как успехи? У тебя цикл никак не параллелится.

anonymous
()

Спасибо всем! работает как часы!
переписал в for вектор на 3 double.
переписал все .at() на [], int на size_t

минус - конфликт pragma и size_t:

#pragma omp parallel for
for (size_t i = 0; i != arr.size(); ++i)
  arr[i] += arr[i];
но с этим жить можно.

rgB
() автор топика
Ответ на: комментарий от anonymous

не пойму смысла в <«100» нормальных for>.

вот так пытаюсь параллелить:

#pragma omp parallel for
for (int j = 0; j < count; ++j)
double a=some_vector_a[j], b=some_vector_b[j], c=some_vector_b[j];
vector<double> V;
for (int i = 0; i < V.size(); ++i) {
	if(i > 1) V[i] = f(V.at(i-2), V.at(i-1),a,b,c);
	else 	  V[i] = i;
}
other_vector[j]=V.back();
}
но это уже другая история...

rgB
() автор топика
Ответ на: комментарий от anonymous

этот for (int i = 0; i < V.size(); ++i) я не пытаюсь параллелить.

rgB
() автор топика
Ответ на: комментарий от rgB
vector<double> V;
for (int i = 0; i < V.size(); ++i) {
    ...
}
other_vector[j]=V.back();

А у тебя не возникает, случаем, ощущения, что тут что-то не так?

mashina
()
Ответ на: комментарий от mashina

писал на быструю... о возможности параллелить прагмой...

vector<double> other_vector(count);
#pragma omp parallel for
for (int j = 0; j < count; ++j) {
vector<double> V(num_poi);
    ...
    for (int i = 0; i < V.size(); ++i) {
        ... 
    }
other_vector[j]=V.back();
}
теперь все так?

rgB
() автор топика
Ответ на: комментарий от rgB

Выкати f(), которые ты будешь использовать.

но это уже другая история...

Это основная история.

не пойму смысла в <«100» нормальных for>.

Ты ведь правильно понял к чему я толкал про «много форов» - это параллелизм. Только вот параллелизм есть не только на уровне отдельных ядер, но и внутри - почитай про «суперскалярную архитектуру», про параллелизм на уровне данных, а почему твой реализация антипаттерн для неё - я думаю ясно.

anonymous
()
Ответ на: комментарий от rgB

Хотя в первом посте есть:

a*V.at(i-2) + b*V.at(i-1)+c*((V.at(i-2))/(V.at(i-1)))

Ты сюда форфан деление впихнул или оно тебе действительно нужно? Желательно, чтобы его не было, иначе это жопа.

anonymous
()
Ответ на: комментарий от anonymous

ok.

vector<double> Z(num_poi), other_vector(count);
#pragma omp parallel for
for (int j = 0; j < num_poi; ++j) Z[j]=...;

vector <double> a(count);

#pragma omp parallel for
for (int j = 0; j < count; ++j) {
a[j]=...;
vector<double> V(num_poi), M(num_poi);

#pragma omp parallel for
    for (int i = 0; i < V.size(); ++i) M[i]=f(Z[i],a[j]);
    ...
    for (int i = 0; i < V.size(); ++i) {
        V[i]=M[i]*
(((Z[i]-a[j])+1/M[i-1]+1/M[i])*V[i-1]
-2*V[i-2]/M[i-1]);
    }
other_vector[j]=V.back();
}
так выглядит ужасно както... но видно V [ i ]!
столько выкатил, для понимания(ужаса?). что программист, наверное:
1 так бы не писал...
2. здесь кучу всего можно переписать.
но загвоздка (время затраты) было именно только в том FOR!
p.s. пока писал, может где-то что-то пропустил.

rgB
() автор топика
Ответ на: комментарий от rgB

Обращение к V[i-1] и V[i-2] при (i == 0) - это явный баг. Да и сам V тут, опять же, не нужен. Если значение M используется однократно, то M тоже не нужен.

Deleted
()
Ответ на: комментарий от rgB

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

for(int i=1; i<v.size(); --i)
{
  v[i] = f(v[i-1], v[i]);
}
Можно сделать чтото типа:
double *d = &v[0];
for(int i=v.size(); i>0; --i, ++d)
{
  d[1] = f(d[0], d[1]);
}

Ну и конечно F сделать инлайном / макросом

zaz
()
Ответ на: комментарий от Deleted

предлагаю поставить точку в обсуждениях. еще раз спасибо всем!

1. это версия до обсуждения этого топика. в данном случае опустил все if (смотрите выше).
2. V уже переписал через double.
3. М через double перепишу завтра-послезавтра.
4. for (int i = 0; i < на for (size_t i = 0; i != — там где #pragma omp parallel for можно пренебречь.
5. почитал про «суперскалярную архитектуру».

p.s. выбрасывать main-код на 150 строк не вижу смысла, если загвоздка была только в одном for. все остальное будет переписано с учетом всех замечаний.

p.p.s матлаб считал все за 10 мин. с++ ранее — <1 минут. сейчас — <10 c.
и это все умножаем на ~400 --> ([80:0.1:120])
оптимизация прошла на ура!

rgB
() автор топика
Ответ на: комментарий от zaz

я только подружился с классами и объектами.
указатели и ссылки пока не осилил. за наводку дякую!

rgB
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.