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
()

i < V.size()

Компилятор же недостаточно умный, чтобы знать, что V.size() — константа, да?

x3al ★★★★★
()

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

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
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.