Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: C++ 6.0; Большие массивы; отимизация по времени  (Прочитано 20919 раз)
0 Пользователей и 1 Гость смотрят эту тему.
ezus
Опытный

il
Offline Offline

« : 12-03-2014 15:17 » 

Привет!

Есть 2 больших массива. Из них декартовым произведением получаю третий. Размер выходного массива может вылезать за допустимые пределы, но, к счастью, в процессе формирования он может оказаться существенно меньше произведения размеров 2-х входных массивов. Если памяти не хватает, то расчет прекращается, и пользователь должен задать более жесткие параметры на отсечение менее важных элементов.

Вопрос: какую структуру для хранения массивов выбрать?
Я рассматривал следующие варианты:
1.
Код:
ElementType* elements;
elements = new ElementType[size];

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

2.
Код:
CPtrArray elements;
Решает проблему нарашивания. Но каждый элемент создается через "new", что порождает потери на мелкое выделение памяти и фрагментацию. Конечно, для этого есть пулы, но опять неохота.

3.
Код:
CArray<ElementType,ElementType&> elements;
Решает проблему выделения памяти.
Но мне кажется, что любые манипуляции с элементами массива выполняются через переписывния элемента во временную память. А это очень большие затраты времени.
Надеюсь, что я ошибаюсь.

Возможно есть и другие варианты.

Буду рад любым комментариям.
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #1 : 12-03-2014 16:55 » 

Если используеш C++, то почему нельзя использовать обычные STL контейнеры. Например List. Правда, этот контейнер не позволяет произвольный доступ к элементам. По сути своей он представляет собой двухсвязанный список.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #2 : 12-03-2014 17:28 » 

Довольно путанное объяснение, но если это проблема хранения больших разреженных матриц (где несмотря на большие размеры мало элементов, а остальные есть NULL), то, разумеется, давно изобретены разные методы.

ezus, ты поясни:
- действительно ли речь про разреженные матрицы?
- каков характер доступа к элементам (равномерно рандомный, последовательный, рандомный в пределах региона матрицы, но последовательный обход регионов)?
- каков размер (оценка сверху - по максимуму и оценка в среднем - как обычно)?
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
ezus
Опытный

il
Offline Offline

« Ответ #3 : 13-03-2014 07:08 » 

Довольно путанное объяснение, но если это проблема хранения больших разреженных матриц (где несмотря на большие размеры мало элементов, а остальные есть NULL), то, разумеется, давно изобретены разные методы.
Скорее не "путанное", а неполное. Если често, то я просто ждал уточняющих вопросов.
Цитата
- действительно ли речь про разреженные матрицы?
Данные - это два линейных плотных массива объектов, каждый из которых содержит битовую маску.
Надо получить третий массив, содержащий новые объекты с маской = коньюнкции двух исходных масок.
Наверное, это можно представить в виде матрицы, но не вижу в этом большого смысла.
Цитата
- каков характер доступа к элементам (равномерно рандомный, последовательный, рандомный в пределах региона матрицы, но последовательный обход регионов)?
Доступ последовательный - перебор всех пар из 2-х входных массивов.
Цитата
- каков размер (оценка сверху - по максимуму и оценка в среднем - как обычно)?
Объявленного максимума не существует, но возможные размеры входных массивов порядка 5-10 тысяч. Вроде не много, но их произведение дает уже порядка 100 000 000, что не есть приятно. Как я уже писал, к счастью, в ходе произведения возможны существенные сокращения размеров выходного массива. Поэтому его размер заранее не известен.

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

Добавлено через 6 минут и 8 секунд:
Если используеш C++, то почему нельзя использовать обычные STL контейнеры. Например List. Правда, этот контейнер не позволяет произвольный доступ к элементам. По сути своей он представляет собой двухсвязанный список.
1. "К сожалению" я работаю с MFC.
2. Обработка массива в основном последовательная, поэтому двухсвязанный список не самое оптимальное представление для этого.
3. Как я понимаю, организация данных в виде списка подразумевает многократное фрагментированное выделение памяти, чего я очень хочу избежать.
« Последнее редактирование: 13-03-2014 07:14 от ezus » Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 13-03-2014 08:40 » 

ezus, 10 тыс битов? 1,2 тыс. байтов? И произведение 12,5 МиБ? Что тут экстремального?

Или ты всё-таки о чём-то другом говоришь?

Цитата: ezus
Надо получить третий массив, содержащий новые объекты с маской = коньюнкции двух исходных масок.
Наверное, это можно представить в виде матрицы, но не вижу в этом большого смысла.
А это вообще надо? Может проще будет вычислять всякий раз, когда понадобится?

Цитата: ezus
Обработка массива в основном последовательная, поэтому двухсвязанный список не самое оптимальное представление для этого.
Это бред. Как раз для последовательного доступа связный список оптимален. Он неоптимален для рандомного доступа.

Цитата: ezus
Как я понимаю, организация данных в виде списка подразумевает многократное фрагментированное выделение памяти, чего я очень хочу избежать.
Вовсе необязательно. Можно зарезервировать массив элементов списка, из которого по принципу стека извлекать свободные для использования и возвращать освободившиеся после использования. Выделение памяти в куче и фрагментация при этом не возникают.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
ezus
Опытный

il
Offline Offline

« Ответ #5 : 13-03-2014 09:14 » 

ezus, 10 тыс битов? 1,2 тыс. байтов? И произведение 12,5 МиБ? Что тут экстремального?

Или ты всё-таки о чём-то другом говоришь?
Нет, это 10 тыс байт. И с ними нет проблем. Проблема с выходным массивом в "100 000 000" байт.
Цитата
Цитата: ezus
Надо получить третий массив, содержащий новые объекты с маской = коньюнкции двух исходных масок.
Наверное, это можно представить в виде матрицы, но не вижу в этом большого смысла.
А это вообще надо? Может проще будет вычислять всякий раз, когда понадобится?
Надо.
Цитата
Цитата: ezus
Обработка массива в основном последовательная, поэтому двухсвязанный список не самое оптимальное представление для этого.
Это бред. Как раз для последовательного доступа связный список оптимален. Он неоптимален для рандомного доступа.
Может быть и бред. Хотя мне казалось, что последовательное заполнение массива и его дальнейший последовательный перебор более эффективен, чем построение списка и пробег по нему.
Цитата
Цитата: ezus
Как я понимаю, организация данных в виде списка подразумевает многократное фрагментированное выделение памяти, чего я очень хочу избежать.
Вовсе необязательно. Можно зарезервировать массив элементов списка, из которого по принципу стека извлекать свободные для использования и возвращать освободившиеся после использования. Выделение памяти в куче и фрагментация при этом не возникают.
Сколько выделять под стек?
Под все  "100 000 000" байт у меня нет памяти.
Записан
sss
Специалист

ru
Offline Offline

« Ответ #6 : 13-03-2014 09:19 » 

ezus, зачем торопитесь отвечать? При чем тут стек.. Делайте растущий вектор. MFC позволяет использовать STL...

Добавлено через 30 секунд:
И 100 МБ не много, поверьте
« Последнее редактирование: 13-03-2014 09:19 от sss » Записан

while (8==8)
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 13-03-2014 09:26 » 

Цитата: ezus
Хотя мне казалось, что последовательное заполнение массива и его дальнейший последовательный перебор более эффективен, чем построение списка и пробег по нему.
А перебор сколько раз происходит после построения? Если 1, и нет фазы "быстрая работа" после "медленной подготовки", то и смысла нет. Сразу вычисляешь и сразу используешь результат.

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

Цитата: ezus
Проблема с выходным массивом в "100 000 000" байт.
Даже 100 МиБ - это вроде не так и много.
Цитата: ezus
Под все  "100 000 000" байт у меня нет памяти.
Допустим.

Так что же получается в итоге? Тебе надо 100 Мб массив, на который ты тратить память не хочешь. Зачем этот массив нужен, я пока так и не понял. Если это вопрос времени, то время и память - это всегда ресурсы альтернативные. Т.е. экономя на одном, тратишь другое. Т.е. раз нет памяти, значит больше времени. И встаёт вопрос о чём?

Ну хорошо, сколько памяти готов выделить под задачу?
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
ezus
Опытный

il
Offline Offline

« Ответ #8 : 13-03-2014 09:35 » 

Цитата: ezus
Хотя мне казалось, что последовательное заполнение массива и его дальнейший последовательный перебор более эффективен, чем построение списка и пробег по нему.
А перебор сколько раз происходит после построения? Если 1, и нет фазы "быстрая работа" после "медленной подготовки", то и смысла нет. Сразу вычисляешь и сразу используешь результат.

Если несколько проходов, то весь этот массив произведения рассматривается как кэш. Опять же, если проходы не полные, то время на построение полного произведения может быть даже больше, чем "на лету" вычислить нужные кусочки.
Нет никакого частичного использование. Массив является частью объекта, у которого своя жизнь, возможно выходящая за пределы конкретной сессии.
Цитата
Цитата: ezus
Проблема с выходным массивом в "100 000 000" байт.
Даже 100 МиБ - это вроде не так и много.
Цитата: ezus
Под все  "100 000 000" байт у меня нет памяти.
Допустим.

Так что же получается в итоге? Тебе надо 100 Мб массив, на который ты тратить память не хочешь. Зачем этот массив нужен, я пока так и не понял. Если это вопрос времени, то время и память - это всегда ресурсы альтернативные. Т.е. экономя на одном, тратишь другое. Т.е. раз нет памяти, значит больше времени. И встаёт вопрос о чём?

Ну хорошо, сколько памяти готов выделить под задачу?

Виноват - поддался на провокацию.
 "100 000 000"  - это не байт, а элементов, каждый из которых в свою очередь содержит свою информацию размером в десятка раз и более. Так что памяти действительно не хватает.
Записан
sss
Специалист

ru
Offline Offline

« Ответ #9 : 13-03-2014 09:40 » 


 "100 000 000"  - это не байт, а элементов, каждый из которых в свою очередь содержит свою информацию размером в десятка раз и более. Так что памяти действительно не хватает.


Создать словарь для похожих элементов.. Иначе ничего не делать..

Добавлено через 1 минуту и 26 секунд:
При таких объемах вы не то оптимизируете.. Вам не работу организации памяти, а подход сохранения надо переделывать
« Последнее редактирование: 13-03-2014 09:42 от sss » Записан

while (8==8)
ezus
Опытный

il
Offline Offline

« Ответ #10 : 13-03-2014 09:42 » 

ezus, зачем торопитесь отвечать?
Тороплюсь - уж очень нужно.
Цитата
При чем тут стек.. Делайте растущий вектор. MFC позволяет использовать STL...

Ключевое слово растущий.
Кроме того, добавление нового элемента может привести к удалению ранее созданных, что приводит к дырам в массиве. Конечно, можно параллельно организовать список пустот, но это дополнительные затраты времени.

У меня нет проблем реализовать это в принципе - я обратился за помощью в поиске наиболее оптимального варианта.

Добавлено через 1 минуту и 58 секунд:
Создать словарь для похожих элементов.. Иначе ничего не делать..
Что такое словарь похожих элементов?
« Последнее редактирование: 13-03-2014 09:44 от ezus » Записан
ezus
Опытный

il
Offline Offline

« Ответ #11 : 13-03-2014 09:47 » 

При таких объемах вы не то оптимизируете.. Вам не работу организации памяти, а подход сохранения надо переделывать
Что можно предложить в замен попарного перебора, если нужен именно он?
Задача из области алгебр, и мне надо выполнить произведение двух скобок.
Записан
sss
Специалист

ru
Offline Offline

« Ответ #12 : 13-03-2014 09:47 » 

Я бы создал объект раздел  CreateFileMapping. И двигал окно памяти

Словарь - как делают архиваторы...  Ищут частоту вхождения фрагментов текстов и из самых частых создают словарь. А в месте вставки не элемент, а индекс элемента в словаре..
Записан

while (8==8)
ezus
Опытный

il
Offline Offline

« Ответ #13 : 13-03-2014 09:58 » 

sss, к сожалению, эти алгоритмы существенно тяжелее по времени, чем линейные
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #14 : 13-03-2014 10:03 » 

Цитата: ezus
"100 000 000"  - это не байт, а элементов, каждый из которых в свою очередь содержит свою информацию размером в десятка раз и более.
Так причём тут тогда биты?

Я же сразу спросил про разреженную матрицу: если true, есть какой-то объект-элемент, если false - NULL.

Поскольку NULL-ов много, хранить массив нет смысла. Достаточно иметь словарь пар "индекс-объект" (или даже исходные координаты в обоих массивах "индекс-индекс-объект"). Память на хранение указателей, содержащих NULL, не расходуется.

Однако указателей на 50 Мб - это не так и много. Значит проблема в чём-то другом.

Если на false тоже есть объект, но другой, то, как говорит sss, нужно группировать по подобию. Т.е. два словаря - один для true-объектов, другой для false-объектов.

Если же это всё вообще в память не лезет в принципе, тогда я не понимаю, о чём вообще речь? Тогда нет и массива, а нужно строить объект по потребности, или хранить это где-то на диске.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
ezus
Опытный

il
Offline Offline

« Ответ #15 : 13-03-2014 10:10 » 

Еще раз спрошу.

Код:
CArray<ElementType,ElementType&> elements;
elements.SetSize(10,10);

elements[5].name = "ququ";   // A)

int x = elements[2].x;   // B)


Операторы присваения в случаях А и В работают на прямую с памятью массива или со временной памятью?
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #16 : 13-03-2014 10:16 » 

ezus, должен с той же - раз ссылочный тип аргумента.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
ezus
Опытный

il
Offline Offline

« Ответ #17 : 13-03-2014 10:18 » 

Есть 2 больших массива. Из них декартовым произведением получаю третий. Размер выходного массива может вылезать за допустимые пределы, но, к счастью, в процессе формирования он может оказаться существенно меньше произведения размеров 2-х входных массивов. Если памяти не хватает, то расчет прекращается, и пользователь должен задать более жесткие параметры на отсечение менее важных элементов.

Память выходного массива растет непрерывно в процессе формирования, и "Если памяти не хватает, то расчет прекращается,". Но мне надо тянуть до последнего, то есть брать максимум возможного.

sss, к сожалению, массивы принципиально последовательные, содержащие "непохожие" объекты.

Добавлено через 1 минуту и 47 секунд:
ezus, должен с той же - раз ссылочный тип аргумента.
Спасибо, возможно это и есть решение проблемы. Мне нужно было подтверждение и я его получил.
Спасибо.
« Последнее редактирование: 13-03-2014 10:20 от ezus » Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #18 : 13-03-2014 10:26 » 

Цитата: ezus
Память выходного массива растет непрерывно в процессе формирования, и "Если памяти не хватает, то расчет прекращается,". Но мне надо тянуть до последнего, то есть брать максимум возможного.
Т.е. нужна минимизация "накладных расходов" на хранение структур данных?

Ну в таком случае надо комбинировать связный список и массивы. Т.е. делать блоками из небольших массивов, между собой связанных в список. Тогда переаллокация массива по мере его роста не требуется. В том числе, если массиву некуда расти из-за фрагментации памяти, он не будет целиком копироваться в новое место, если он реально большой. В том числе, если память фрагментирована, непрерывный массив гораздо скорее упрётся в потолок, нежели отдельные кусочки.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
ezus
Опытный

il
Offline Offline

« Ответ #19 : 13-03-2014 10:38 » 

Dimka, согласен, я так и собираюсь сделать.
Хотя адресацию придется делать самому, а это накладные расходы, если прятать ее в спец класс массива.
Если для перебора в непреравном участке использовать стандартную индексацию, тогда переход из участка в участок придется перенести на функциональный уровень, а это не хорошо с т.зр. объектного подхода.
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #20 : 13-03-2014 11:03 » 

ezus, чего??

Тебе надо сделать класс типа ArrayList с перегруженным оператором [], который внешне выглядит как массив, а внутри сделать связный список из блоков-страниц. Для каждой указать смещение от 0 - т.е. 0 в блоке будет N от начала всего массива.

Это никаким боком не противоречит объектному подходу. Это даже в других языках уже сделано.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
ezus
Опытный

il
Offline Offline

« Ответ #21 : 13-03-2014 11:18 » 


Тебе надо сделать класс типа ArrayList с перегруженным оператором [], который внешне выглядит как массив, а внутри сделать связный список из блоков-страниц. Для каждой указать смещение от 0 - т.е. 0 в блоке будет N от начала всего массива.

Это никаким боком не противоречит объектному подходу. Это даже в других языках уже сделано.
Я так понимаю, что в оригинале доступ к i-ому элементу получается через A+ii*sizeof(A), а перегруженный оператор сначала должен определить номер блока, затем найти его или пробегая по списку, или через массив косвенной адресации, и только потом получаем доступ к элементу массива через что-то подобное A+ii*sizeof(A).

Когда я говорил о нарушении ОО, я имел ввиду в циклах по массивам функционального уровня добавить один дополнительный цикл по блокам, тогда при каждом обращении к элементу не будет этих дополнительных затрат на определение и переход к блоку.
« Последнее редактирование: 13-03-2014 11:20 от ezus » Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #22 : 13-03-2014 12:10 » 

ezus, ты ж сам сказал, что всё однопроходное. Какая тогда разница, косвенная там адресация или прямая?
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
ezus
Опытный

il
Offline Offline

« Ответ #23 : 13-03-2014 12:52 » 

Да, наверное, ты прав.
За советы спасибо.
Записан
sss
Специалист

ru
Offline Offline

« Ответ #24 : 13-03-2014 13:43 » 

Вообще - просто очень туманная задача.. Более четкое определение элементов может помочь. Если они не однотипны по размеру -  о каких вообще массивах может идти речь? Тогда смысла нет - только список разноразмерных буферов
« Последнее редактирование: 13-03-2014 13:46 от sss » Записан

while (8==8)
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #25 : 13-03-2014 13:48 » 

sss, самое туманное - как этим всем пользоваться, когда оно построено. Исходя из этого и нужно выбирать структуру. А об этом почти ничего не было сказано.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
ezus
Опытный

il
Offline Offline

« Ответ #26 : 13-03-2014 13:53 » new

Еще раз спасибо.
Как и ожидалось поиск сокращения времени придется искать в области сокращения размерностей, а это совсем другой вопрос. Так что эту тему можно считать закрытойю
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines