2009-10-16 2 views
1

Мне нужно сохранить коллекцию int и double (представляющую номинальные и реальные значения) в C++. Я мог бы, очевидно, сохранить их все в std::vector<double>, но это кажется немного неправильным и не получает бонусных баллов за эстетику.Самый эффективный способ хранения смешанной коллекции удвоений и ints

Я мог бы также приготовить что-то на основе полиморфизма, но мне также нужна коллекция, чтобы быть действительно эффективной: как хранение, так и извлечение данных в коллекции должны быть как можно быстрее. Мне трудно судить, будет ли такое решение максимально эффективным.

Я также нашел boost::variant, что может быть полезным здесь.

Дополнительная информация: количество элементов в коллекции будет небольшим (< 100) и известно при инициализации коллекции.

Подведение итогов: я мог бы решить это бесчисленными способами, но я не уверен, что было бы хорошим решением, когда (i) эффективность действительно важна и (ii) я также хочу написать несколько приятный код. Какой у меня лучший выбор?

Редактировать, дополнительная информация: Коллекция представляет собой «строку» в большем наборе данных, ее элементы представляют значения определенных «столбцов». Свойства строк известны, поэтому известно, какие данные хранятся в каком месте. «Эффективность», о которой я говорю, - это прежде всего эффективность извлечения значения int/double определенного столбца, хотя важна и быстрая настройка значений. У меня есть некоторые функции, которые работают с данными, которые необходимо восстановить как можно быстрее. Пример:

typedef std::vector<double> Row; 

void doubleFun(Row const &row) 
{ 
    // Function knows there's always a double at index 0 
    double value = row[0]; 
    ... 
} 

void integerFun(Row const &row) 
{ 
    // Function knows there's always an integer at index 1 
    int value = row[1]; 
    ... 
} 

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

Просто хранить как vector<double> тоже нормально, но это зависит от того, насколько быстро происходит преобразование между двойным и int (что, вероятно, довольно впечатляет).

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

+0

Вы не предоставили нам достаточно информации, чтобы узнать лучшее решение - Каковы свойства коллекции? Разрешены ли дубликаты? Важен порядок? Должен ли он сортироваться? Требуется ли сохранить тип данных, или он действителен для вставки 10.0 (double) и извлечения 10 (int)? – Tom

+0

Также, какой показатель эффективности вы пытаетесь оптимизировать? Общая площадь? Время вставки? Случайное время доступа к поиску? Время итерации? – Tom

+0

Обновлено с дополнительной информацией, извините за то, что вы не слишком поняли вначале. Надеюсь, теперь это лучше. –

ответ

5

Является ли заказ важным пунктом в вашем контейнере?

Если не так:

class MyContainer 
{ 
    std::vector<double> doubles; 
    std::vector<int> ints; 

    push(double value) { doubles.push_back(value); } 
    push(int value) { ints.push_back(value); } 

    .... 
}; 

Итератор часть (чтобы просмотреть весь контейнер) может быть немного сложнее ...

+0

Учитывая обновленные требования, это выглядит наиболее разумным. – Tom

3

Вы можете использовать тип объединения и использовать его в своем векторе. Но в этом случае вам нужно будет каким-то образом узнать, какие элементы вектора следует рассматривать как int и какие из них следует рассматривать как двойные. Чтобы отслеживать, какие из них являются ints, а какие - удваиваются, вы можете использовать битрейт или что-то в этом роде.

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

#include <vector> 
#include <bitset> 

union di 
{ 
    double d; 
    int i; 
}; 


int main(int argc, char* argv[]) 
{ 

    std::bitset<2> bitsetInts; 

    std::vector<di> v; 
    di e1; 
    e1.d = 3.9; 
    v.push_back(e1); 

    di e2; 
    e2.i = 3; 
    bitsetInts.set(1); 
    v.push_back(e2); 

    return 0; 
} 
+0

это здорово, если максимальный размер исправлен, именно то, о чем я думал. – Tom

1

Существует загрузочный кортеж, который вы можете использовать, если знаете типы во время компиляции. Но если количество элементов невелико, эффективная потеря 100 байт не должна вызывать беспокойства.

3

Я бы выбрал решение boost::variant, оно идеально подходит для ваших нужд.

5

Почему бы не использовать непосредственно вектор double? Так как целые числа могут быть преобразованы в двойные, без потери точности ... он выглядит для меня самым простым и эффективным решением.

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

+0

true, теперь 10.0 a double или integer? – gbjbaanb

+0

Реальный вопрос: «Является ли 10.0 нормальным или реальным значением?». Но, как я сказал в своем ответе ... у меня недостаточно информации. Тот же вопрос можно задать в случае использования вариантов. –

+0

@ Cătălin A boost :: variant is type save, вы можете использовать посетителя для получения правильного типа – TimW