короткий короткий int в c?

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

Я понимаю, что в C нет однобитных типов (может быть, кто-то может объяснить мне, почему), и я также знаю, что если бы существовал short short int, он был бы 1 байтом, таким же, как char. Однако все логические операции в C возвращают целые числа (как и некоторые другие функции).

Итак, мои вопросы:

  • Есть ли способ заставить short short int существовать?
  • Если бы вместо этого я использовал char, снизилась бы производительность из-за всего приведения к int, которое нужно было бы сделать?
  • Есть ли другой способ, который мне не хватает?

На всякий случай, если это уместно, я компилирую с помощью GCC для C99.

ИЗМЕНИТЬ Я только что увидел на этой странице википедии, что там это тип _Bool, это действительно стандарт?


person Griffin    schedule 14.07.2011    source источник
comment
Не могли бы вы пояснить, почему все они должны быть переведены на int?   -  person aardvarkk    schedule 14.07.2011
comment
вы можете использовать битовые поля ( codepad.org/HMz2f7OR ). Использование char в качестве базового типа битового поля в C определяется реализацией (поэтому я не публиковал его в качестве ответа, потому что сейчас мне не хочется создавать 32 битовых поля для unsigned int), но работает для GCC.   -  person Johannes Schaub - litb    schedule 14.07.2011
comment
Ну, я не уверен, что они это делают, я предположил, что побитовое ИЛИ для двух символов потребует приведения, поскольку оно вернет целое число, как указано: en.wikipedia.org/wiki/Boolean_data_type#History   -  person Griffin    schedule 14.07.2011
comment
Что представляет собой каждый из этих битов? Например, как вы планируете получить доступ к значению бита [4264334543] и что вы будете с ним делать? Я спрашиваю, потому что может быть более эффективный способ хранения данных, который зависит от структуры, которую вы не раскрыли.   -  person AShelly    schedule 14.07.2011
comment
@AShelly они представляют ребро между двумя узлами в графе. Мне нужны значения для очень быстрого поиска, чтобы увидеть, существует ли край или нет.   -  person Griffin    schedule 14.07.2011
comment
Является ли ваша матрица смежности разреженной?   -  person Jacob    schedule 14.07.2011
comment
@Jacob, обычно это чуть больше 0,5, поэтому список смежности вдвое сокращает использование памяти. Но деление этого большого числа на 2 по-прежнему дает очень большое число, но гораздо более медленное время поиска.   -  person Griffin    schedule 14.07.2011
comment
Я знаю, что это непопулярный вопрос по C, но рассматривали ли вы C++? Он также не имеет битовых типов данных (на самом деле он есть, но немного тонковат), но в отличие от C он позволяет вам определять битовые поля с удобным синтаксисом и семантикой. Конечно, битовых полей C может быть достаточно для ваших целей.   -  person Konrad Rudolph    schedule 14.07.2011
comment
Просто любопытно, зачем вам 6,5 ТБ логических значений? Я пытаюсь угадать вариант использования для этого.   -  person Dani Barca Casafont    schedule 13.10.2015


Ответы (8)


Тип _Bool является стандартным в самой последней версии C, но это все еще не то, что вам нужно, потому что _Bool по-прежнему занимает как минимум один байт (как и char по определению).

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

person JSBձոգչ    schedule 14.07.2011
comment
Спасибо, а это сильно ударит по производительности? И да, на данный момент доступно 32 ГБ оперативной памяти. - person Griffin; 14.07.2011
comment
@Griffin, с такими большими размерами данных, как то, что у вас есть, стоимость перемещения вещей в память и из нее превышает стоимость выполнения. У вас нет 5e13 байтов памяти, на вашем компьютере есть только ~3e10, поэтому все, что вы можете сделать, чтобы набор данных поместился в памяти, будет победой. - person JSBձոգչ; 14.07.2011
comment
+1 на самом деле я создаю и анализирую очень большие графики. Цель состоит в том, чтобы получить узлы 1e7 (порядок, о котором я сейчас спрашиваю), но на самом деле даже матрица смежности для 1e6 потенциально займет 58 ГБ или ОЗУ. Со временем я смогу перенести все это на OpenCL и запустить на университетском суперкомпьютере, но это все еще проблематично. Мне нужно о многом подумать. Спасибо, что немного открыли мне глаза! +1 к вашему ответу тоже. - person Griffin; 14.07.2011
comment
@Griffin, есть более эффективные структуры данных для матрицы смежности, если это то, к чему вы стремитесь, и их использование может уменьшить объем памяти на несколько порядков. Вы можете попробовать задать отдельный вопрос об этом, если это то, что вы пытаетесь построить. - person JSBձոգչ; 14.07.2011

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

И нет такой вещи, как short short int, это просто char, который является наименьшим классом хранения целых чисел в C.

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

Небольшой пример может помочь проиллюстрировать:

Используя обычную целочисленную матрицу:

int mat[8*8]; // assuming row major order
int is_element_set(int x, int y) { 
  return mat[y*8 + x];
}

С растровым изображением:

unsigned char mat[8]; // assuming CHAR_BIT == 8
int is_element_set(int x, int y) { 
  return mat[y] & (1 << x);
}
person user786653    schedule 14.07.2011
comment
Спасибо, я предпочитаю меньше занимать место, чем снижать производительность, так что, кажется, я сделал это как можно лучше? Кроме того, поскольку мое битовое поле будет примерно 5000000000000000 бит, в каком типе я могу его хранить? - person Griffin; 14.07.2011
comment
Вы бы сохранили его в 5e13/8 символов или 5e13/32 целых. В любом случае это > ~ 5 Террабайт. Так что я определенно рассмотрю эффективность использования пространства — получение этих данных в основной памяти и из нее не будет быстрым. - person AShelly; 14.07.2011
comment
Это МНОГО битов. В принципе, вы должны хранить его в unsigned char mat[5000000000000000/CHAR_BIT], но, похоже, вам лучше смотреть на разреженные структуры данных (если ваши данные разрежены). - person user786653; 14.07.2011
comment
@Griffin Меньшее пространство во многих случаях может быть более эффективным, даже если ваш код должен выполнять немного больше работы, поскольку меньшие данные могут помещаться в кеши, которые на порядок быстрее, чем работа в основной памяти. Вы узнаете только путем измерения для вашего конкретного случая. - person nos; 14.07.2011
comment
+1 к вашему ответу. Как вы можете видеть из другого ответа, мне есть о чем подумать. Спасибо за ваш вклад. - person Griffin; 14.07.2011

У вас есть около 50 терабит данных. Вы хотите разместить их все в оперативной памяти сразу? Было бы полным безумием использовать более одного бита оперативной памяти для хранения одного бита информации, и даже в этом случае ваш компьютер должен был бы быть размером с самый большой суперкомпьютер на этой планете. Забудьте о производительности битовой упаковки. Вам придется беспокоиться о совершенно других вещах.

person n. 1.8e9-where's-my-share m.    schedule 14.07.2011

5e13, это около 5,6 терабайт памяти, которые вам понадобятся только для представления вашего битового поля. Вероятно, есть лучший способ справиться с вашей проблемой.

person Patrick Schlüter    schedule 15.07.2011

Возможно, вы могли бы использовать какую-нибудь разумную реализацию структур битовых полей, доступных в ANSI C.

Что-то вроде этого:

typedef struct node_t_
{
    char bit0 : 1;
    char bit1 : 1;
    char bit2 : 1;
    char bit3 : 1;
    char bit4 : 1;
    char bit5 : 1;
    char bit6 : 1;
    char bit7 : 1;
} node_t;

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

person Ivan Filgueiras    schedule 14.07.2011

C99 stdbool.h позволяет использовать bool. Однако здесь ваша проблема заключается в том, что 4.9999995e13/8 даст более или менее 6.2500e+12 ($10^9$ — Гбайт, $10^12$ — Тбайт), поэтому вам нужно более 6 Тбайт реальной + виртуальной памяти (чтобы быть счастливый). Это говорит о том, что вы делаете что-то еще неправильно. Вам нужно «масштабировать» вашу проблему на подзадачи, с которыми вы можете справиться, используя меньше памяти.

person ShinTakezou    schedule 14.07.2011

Как предлагали другие люди, вам, вероятно, следует использовать битовое поле.

Кроме того, если вы просто используете значения true/false, и одно из значений гораздо менее распространено, чем другое, рассмотрите возможность использования неявного кодирования. Вы можете легко сделать это с помощью структуры данных карты. Когда вы работаете с графами, это сэкономит вам огромное количество памяти, если ваш граф совсем разреженный. Если вы объедините это с методами упаковки битов, описанными выше, вы можете даже поместить все это в ОЗУ. Однако нужно быть довольно умным с индексацией.

Еще одна вещь, которую вы могли бы сделать, если вас не волнует снижение производительности во время обработки (т. е. если вы больше беспокоитесь о сохранении данных, чем об их обработке), — запустить структуру через сжатие алгоритм в блоках. Есть библиотека C для bzip2, которая может сэкономить вам 90% или больше на чем-то подобном. Недостатки в том, что это займет (очень!) много времени. Вы можете получить сравнимую производительность с побитовым компрессором, таким как Dynamic Markov Compression (DMC), и они намного быстрее.

person John Doucette    schedule 15.07.2011

Я пытаюсь выжать из своей памяти как можно больше.

Если бы это было правдой, то вы бы не тратили 8 бит на хранение 1 бита данных. Вы бы использовали битовое поле.

Если вы знаете что-нибудь о содержимом матрицы, вы можете использовать другие оптимизации. Например, если вы знаете, что большая часть матрицы обычно равна нулю, вы можете сохранить только пары x,y элементов, равных единице.

Если нет, то 4.9999995e13 займет около 6 ТБ ОЗУ!

person kirsch    schedule 09.04.2014