Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Шаблон статического вектора

505
30 ноября 2007 года
vAC
343 / / 28.02.2006
Надо вот сделать шаблончик для вектора постоянной длины, вот только одной штуки я не учел, когда за это взялся. Вот фрагмент:
 
Код:
// Static vector hold policy
template <int n, typename T>
class Vector_static {
private:
    T m_data[n];

public:

           Vector_static(T x1, T x2, T x3, T x4) ...?
...

А теперь как сделать конструктор, в который бы передавались
значения координат? Разумеется, все ограничено длиной в 4 элемента. Специализация шаблона может быть только функциональной, а не структурной. А так бы можно было сделать объединение с нужным числом элементарных элементов для 4-х конкретизаций и дело в шляпе...
Думаю, придется делать отдельные классы для первых четырех...а жаль :(
3
30 ноября 2007 года
Green
4.8K / / 20.01.2000
IMHO это изврат.
Но уж если извращаться, до до конца... и в академических интересах.
Не применяй на практике конкретно эти варианты, т.к. они лишь усложнят простую задачу. Но методы решения запомни, могут пригодиться в реальных условиях.

Вариант 1
Можно, просто, сделать четыре вида конструкторов (поколичеству аргументов).
Можно воспользоваться макрсом BOOST_PP_REPEAT из библиотеки boost и нагенерить их, чтоб не писать вручную. Хотя для четырех вариантов проще воспользоваться Copy/Paste.
Чтоб пользователь случайно не вызвал не тот конструктор, сделать внутри конструктора проверку на кол-во аргументов.
 
Код:
Vector_static(T x1, T x2, T x3, T x4) {
    { typedef char check[N==4?1:0]; }
    .....
}

Vector_static(T x1, T x2, T x3) {
    { typedef char check[N==3?1:0]; }
    .....
}

Если пользователь ошибется с кол-вом аргументов конструктора, то компиляция обломится, но вот с неинформативным сообщением.

Вариант 2
Можно создать один конструктор со значениями параметров поумолчанию.
А далее внутри взять ровно столько значений, сколько надо.
Для этого нужен некоторый промежуточный "преобразователь", который из "перечисления" сделает "массив" значений, чтоб можно было итерироваться. В качестве такого "преобразователя" сойдет твой же класс:
 
Код:
Vector_static(T x1, T x2=0, T x3=0, T x4=0) {
    Vector_static<4, T> transformer(x1, x2, x3, x4);
    for(int i=0; i<N; ++i) {
        m_data = transformer.m_data;
    }
}

Компилятор от цикла, по идее, должен будет избавиться.
Накладные расходы будут с созданием объекта-трансформера.
Хотя, умный компилятор может это дело и оптимизировать.
3
30 ноября 2007 года
Green
4.8K / / 20.01.2000
Вариант 3
Оптимизация варианта 2. Без слов :) :
 
Код:
Vector_static(T x1, T x2=0, T x3=0, T x4=0) {
    switch(4-N) {
    case 0: m_data[3] = x4;
    case 1: m_data[2] = x3;
    case 2: m_data[1] = x2;
    case 3: m_data[0] = x1;
    }
}
505
30 ноября 2007 года
vAC
343 / / 28.02.2006
Прошу прощения, на самом деле проблема-то у меня в другом...и думаю, что это уже не проблема, просто от этой паранойи увеличения производительности у меня уже голова кругом идет :)
Для меня очень критична скорость работы программы, т.к. это курсовая работа и и должна быть посчитана к среде. А считает она дней 8 на двухядерном процессоре. Распараллеливание впринципе меня устраивает, коэффициент 1.93, алгоритм достаточно простой, в основном обычное умножение и сложение. Прогонял профилировщиком, нашел, что работа с матрицами и векторами занимает львиную долю, правда в основном на доступ к элементам, а не конструкторам. Поэтому и решил извратом заняться...

На самом деле я хотел выполнить инициализацию при конструировании:
 
Код:
Vector_static(T x1, T x2):
m_x1(x1),
m_x2(x2)
{
}

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

Кстати, оригинальное решение, еще не встречал :)
 
Код:
{ typedef char check[N==3?1:0]; }
3
30 ноября 2007 года
Green
4.8K / / 20.01.2000
Кстати, можно специализировать только конструкторы.
Тогда в случае ошибки пользователя, будет выводиться ошибка линковки.
Код:
template <int n, typename T>
class Vector_static {
public:
    Vector_static(T x1);
    Vector_static(T x1, T x2);
    Vector_static(T x1, T x2, T x3);
    Vector_static(T x1, T x2, T x3, T x4);
};

template<>
Vector_static<1>::Vector_static(T x1) {
}

template<>
Vector_static<2>::Vector_static(T x1, T x2) {
}

..........
505
30 ноября 2007 года
vAC
343 / / 28.02.2006
Именно на этом варианте я и остановился :)
3
30 ноября 2007 года
Green
4.8K / / 20.01.2000
Цитата: vAC
Прошу прощения, на самом деле проблема-то у меня в другом...и думаю, что это уже не проблема, просто от этой паранойи увеличения производительности у меня уже голова кругом идет :)
Для меня очень критична скорость работы программы, т.к. это курсовая работа и и должна быть посчитана к среде. А считает она дней 8 на двухядерном процессоре. Распараллеливание впринципе меня устраивает, коэффициент 1.93, алгоритм достаточно простой, в основном обычное умножение и сложение. Прогонял профилировщиком, нашел, что работа с матрицами и векторами занимает львиную долю, правда в основном на доступ к элементам, а не конструкторам. Поэтому и решил извратом заняться...

На самом деле я хотел выполнить инициализацию при конструировании:
 
Код:
Vector_static(T x1, T x2):
m_x1(x1),
m_x2(x2)
{
}

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

Кстати, оригинальное решение, еще не встречал :)
 
Код:
{ typedef char check[N==3?1:0]; }


Не там ищешь тормоза! Однозначно, не там!
Либо алгоритм не той сложности (я про О-большое), либо слишком много лишних операций.
Вот ты пытаешься оптимизировать создание объекта. И сколько ты на этом выиграешь? Какие-то доли процента.
А ведь оптимизация бывает не только "изнутри", но и "снаружи".
Может стоит оптимизировать не создание объекта, а количестве создаваемых, пересоздаваемых объектов?
Как элементарный пример: передавать объекты не по значению, а по ссылке (я бы за передачу по значению руки бы обрывал).
Кешировать результат, чтоб не пересчитывать одно и тоже по нескольку раз.
Многократно использовать уже готовые объекты (пул объектов), чтоб не конструировать заново.

Ты сам подумай, что должна делать программа, чтоб загрузить комп на 8 дней? :o

Это такая грубая ошибка: скатываться на низкоуровневую оптимизацию не проделав высокоуровневую. На низкоуровневой оптимизации выигрывают считанные проценты производительности. Ну ускоришь ты свою программу на 1%, будет она считаться не 8 дней, а 7 дней и 22 часа. Эти 2 часа тебя устроят? Сколько ты уже потерял времени? Думаю, больше этих 2х часов.

Не туда копаешь! Смотри алгоритм и реализацию.

P.S.
Я частенько даю такую задачу на собеседовании:
эта математическая функция работает очень медленно:

 
Код:
char func(char);

ускорьте работу программы. :)
505
30 ноября 2007 года
vAC
343 / / 28.02.2006
Ну конструкторы-то я заодно уж решил оптимизировать. Дело в том, что программа уже настолько вылизана, что некуда, итак в 30 раз увеличил скорость по отношению к оригиналу. Вся задача-то состоит из итераций трех последовательных операций, каждая из которых работает с несколькими матрицами, умножая и складывая элементы, в каждой из них арифметические операции я сгруппировал, чтобы не считать лишнее.
Алгоритм с линейной зависимостью от размера и требуемой точности. Если увеличили в N раз размер, то в N раз считать будет дольше, с точностью тоже самое. А загрузить на столько запросто можно, сам в это раньше не верил. Программа расчитывает процессы газовой динамики в ракетном двигателе, чем более мелкая задана сетка, тем больше узлов надо считать, мне надо порядка 120 тысяч. По точности нужно идти с шагом в 1E-6 миллисекунды и достичь нужно где-то 3 миллисекунды. Т.е. где-то 3 млн. итераций. Время одной итерации где-то 200, 250 миллисекунд. Арифметика простая.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог