Как биты хранятся в памяти? (В кусках? Могут ли быть биты нескольких размеров храниться вместе?) - PullRequest
6 голосов
/ 10 октября 2009

Раньше я думал, что каждая ячейка памяти содержит 8, 16, 32 или 64 бита. Таким образом, 0101 будет храниться на 8-битном компьютере как 00000101 (знак расширяется, если он отрицательный). Это было все прекрасно, пока я не написал программу на языке Java из любопытства, чтобы узнать больше о внутренней работе этой системы.

Рассматриваемый метод выглядит следующим образом:

public void printBinaryRep(File f){
        try{
            FileInputStream inputStream = new FileInputStream(f);
            int next = 0;
            byte b = 0;
            while((next = inputStream.read()) != -1){
                b = (byte)next;
                System.out.println((char)next + " : "+Integer.toBinaryString(next));
            }
            inputStream.close();
        }
        catch(Exception e){System.out.println(e);}
 }

Я получил этот вывод из файла с надписью Hello World

H : 1001000
e : 1100101
l : 1101100
l : 1101100
o : 1101111
  : 100000
W : 1010111
o : 1101111
r : 1110010
l : 1101100
d : 1100100

Все выглядит хорошо, за исключением места. У него 6 бит вместо 8. Теперь мне интересно, как вся эта информация хранится в памяти. Если все это было сохранено в 8-битных блоках, например

Привет: 10010001100101110110011011001101111

Затем вы можете просто посмотреть на каждый 8-битный блок и выяснить, какое число оно представляет (а затем какой код ASCII он имеет в виду). Как это работает, когда символ другого размера (например, 6-битное пространство и 4-битный / n) хранится вместе с ними? Тогда не будет ли хранение небольшого числа в большом битовом пространстве бесполезной тратой?

Я думаю, что у меня неправильное фундаментальное понимание (или, возможно, программа где-то не так ...). Извините, если вопрос звучит странно или слишком необязательно. Я просто хочу знать. Я немного погуглил, но ничего хорошего не придумал. Если вы можете сообщить мне, где я ошибся, или указать мне правильное направление, я был бы очень признателен. Спасибо!

Ответы [ 8 ]

8 голосов
/ 10 октября 2009

Вам лучше будет экспериментировать на C и / или ассемблере, а не на Java. Эти языки являются низкоуровневыми и предоставляют адресное пространство напрямую.

Раньше я думал, что каждая память местоположение содержит 8, 16, 32 или 64 биты. Таким образом, 0101 будет храниться в 8 бит машина как 00000101 (расширенный знак если бы это было отрицательно). Все было хорошо и денди, пока я не написал программу в Ява из любопытства, чтобы узнать некоторые больше внутренней работы этой системы.

Все области памяти в системах x86 содержат 8 бит (1 байт). Если значение содержит больше данных, чем может поместиться в одном байте, оно сохраняется с использованием нескольких байтов. Например, в C тип «float» хранится с использованием 4 байтов (32 бита).

Все это выглядит хорошо, за исключением пространство. У него 6 бит вместо 8. Я теперь интересно, как все это информация хранится в памяти. Если все это было сохранено в 8-битных порциях, как

Пространство также сохраняется в одном байте. Ваш печатный код забывает заполнить до 8 пробелов. 100000 == 00100000 == 0x20.

7 голосов
/ 10 октября 2009

Пробел тоже имеет 8 бит. Просто Integer.toBinaryString не печатает начальные 0 биты так, как вы его использовали.

Со всеми старшими 0 битами в памяти все выглядит так:

H : 01001000
e : 01100101
l : 01101100
l : 01101100
o : 01101111
  : 00100000
W : 01010111
o : 01101111
r : 01110010
l : 01101100
d : 01100100
4 голосов
/ 10 октября 2009

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

Посмотрите внимательно на ваш вывод. У вас есть семь цифр во всех них, кроме пробела. Просто пробел начинается с двух нулей в его двоичном представлении, а остальные буквы начинаются с одного.

3 голосов
/ 10 октября 2009

То, как компьютеры хранят цифры, можно сравнить с одометром в автомобиле. Если одометр состоит из 4 цифр, он сохраняет номер 33 как «0033».

Если кто-то спросит , какой у вас пробег, вы не скажете "ноль тысяч ноль сто тридцать три". По умолчанию Java тоже нет. (Хотя вы можете сказать это.)

Тогда не будет ли хранить маленькое число в большом битовом пространстве много битов?

Ну, не совсем. Предположим, у вас где-то в памяти было 11000100. Как компьютер должен знать, означает ли это 11000100, или 11000, затем 100, или 1, затем 1000, затем 100 и т. Д.

На самом деле, компьютер просто следует той программе, которую ему дают (помните, что программа на Java создается частично вами, а частично людьми, которые разрабатывают Java). Если вы можете создать жизнеспособную систему для сохранения битов, вы можете заставить компьютер делать это.

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

Но позвольте мне вернуться к вашему вопросу.

Тогда не будет ли хранение небольшого числа в большом битовом пространстве много битов?

Математически говоря, нет. Раздел математики под названием Теория информации говорит нам, что количество абсолютно необходимых битов зависит от возможностей, которые вы хотите кодировать, и от того, насколько вероятен каждый из них.

Предположим, у вас есть только четырехбуквенный алфавит (A, B, C, D) и вы используете его для представления двухбитных чисел (соответственно 00, 01, 10, 11). Если каждая из этих букв одинаково вероятна, то минимальное количество бит, необходимое для каждой буквы (в среднем), равно 2. Другими словами, есть нет потраченных впустую бит, даже если A равно 00, а B равно 01.

С другой стороны, если вы используете ASCII и кодируете A, B, C, D в качестве следующих 7-битных чисел:

A: 1000001
B: 1000010
C: 1000011
D: 1000100

тогда вы «тратите» 5 бит на букву (даже если вы не «храните маленькие цифры в большом битовом пространстве»).

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

3 голосов
/ 10 октября 2009

На самом деле ваш подход неверен. Кодирование здесь очень важно.

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

Например: UTF-8 использует от одного до трех байтов (от 8 до 24 бит) для каждого символа в строке. Вот почему вы увидите перегрузку, в которой вы можете указать кодировку для объекта inputtream.

Выбор неправильного входного потока абсолютно приведет к неправильному выводу строки. Таким образом, вы должны знать кодировку файла, чтобы понять, какой бит означает что. На самом деле fileinputstream делает это для вас.

Если вы сохраните цифру в виде строки, она займет длину символа на жестком диске. Совсем как другой персонаж.

Однако, если вы сохраните 123456789 как строку с кодировкой ASCII, потребуется 9 * 8 бит = 72 бита.

Если вы сохраните это как целое число (обратите внимание, что целочисленная ширина данных отличается в разных средах), это займет всего 16 бит.

Также вы не можете быть уверены, что

H : 01001000
e : 01100101
l : 01101100
l : 01101100
o : 01101111
  : 00100000
W : 01010111
o : 01101111
r : 01110010
l : 01101100
d : 01100100
\n: 00001010

хранится на жестком диске как H: 01001000 е: 01100101 л: 01101100 л: 01101100 o: 01101111 : 00100000 W: 01010111 o: 01101111 r: 01110010 л: 01101100 д: 01100100 \ n: 00001010

Вы не можете быть уверены в этом. Файловая система не так проста. Может быть, Hello успешно, но строка World находится в конце диска. Вот почему есть команда дефрагментации.

Но если мы говорим об основной памяти (RAM), когда вы определяете строку, я ожидаю, что биты будут последовательными. По крайней мере, в C это так. Вы определяете строку как это.

char[100] value; // c is a char array. (there is no string type in c)

здесь значение [0] является первым символом нашей строки. И значение относится только к расположению массивов символов в памяти.

если адрес значения [0] равен 10, тогда адрес значения [1] равен 10 + 8 = 18.

2 голосов
/ 10 октября 2009

Согласно Java 4 API ,

Целочисленное значение без знака является аргументом плюс 232, если аргумент отрицательный; иначе это равно аргументу. Это значение преобразуется в строку цифр ASCII в двоичном виде (база 2) без лишних начальных 0.

На самом деле хранение данных на самом деле намного сложнее. Для повышения эффективности обработки большинство типов данных хранятся на границах слов, что означает 4 байта на 32-разрядных компьютерах или 8 байтов на 64-разрядных компьютерах. Массивы могут быть упакованы более близко, так что char [4] может использовать то же количество «фактического пространства», что и char.

Java - это виртуальная машина, и я не уверен, какую архитектуру памяти она использует.

1 голос
/ 12 октября 2009

Это проясняет. Моя главная проблема заключалась в том, что я с самого начала игнорировал нули. Я экспериментировал с этим, когда читал больше об алгоритмах сжатия (а именно, gzip) Я принимал ASCII для всего этого. Просмотр представления не был целью программы, но разное количество бит в слове отбросило меня от первоначальной цели - реализовать базовое сжатие на основе индекса для типа файла, над которым я работаю. Я постараюсь переписать его на C, как только у меня появится подтверждение концепции на Java.

Спасибо!

0 голосов
/ 03 августа 2012

http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Integer.html#toBinaryString%28int%29
спецификация Integer.ToBinarys гласит:

"Это значение преобразуется в строку цифр ASCII в двоичном формате (база 2) без лишних начальных 0s "

То, что вы упустили этот факт, привело вас в замешательство.

...