Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум «Всё о Паскале» _ Задачи _ Работа с битами

Автор: sheka 7.07.2011 18:07

Хочется видите ли с битами работать. Но даже в тот же Longint они не влазят.
Вот такой маразм не прокатывает:

program Project1;

{$APPTYPE CONSOLE}

uses
SysUtils;

var
p: pointer;
pSize: integer;
i: integer;

begin
pSize := SizeOf(longint)*8+1;
WriteLn(pSize);
GetMem(p,pSize);
FillChar(p^,pSize,0);
Integer(p^) := 4294967296;
for i := pSize-1 downto 0 do
Write((Integer(p^) shr i)and $1);
WriteLn;
FreeMem(p,pSize);
readln;
end.

Объявлять массив Байтов и делать перегрузку +- не интересно.

Автор: IUnknown 7.07.2011 18:18

Ну, с таким-то значением ничего перегружать не надо:

type
PInt64 = ^Int64; // Можно работать и с QWord, причем безо всяких извращений с выделением памяти...
var
p : pointer;
pSize : integer;
i : integer;
begin
pSize := SizeOf(longint)*8+1;
WriteLn(pSize);
GetMem(p,pSize);
FillChar(p^,pSize,0);
PInt64(p)^ := 4294967296;
for i := pSize-1 downto 0 do
Write((PInt64(p)^ shr i)and $1);
WriteLn;
FreeMem(p,pSize);
readln;
end.
, а вот если значение будет больше 18446744073709551615 (максимум для QWord - вот тогда точно придется принимать меры)

P.S. Вопрос на засыпку: на кой ты выделяешь 33 байта, если тебе достаточно 33 битов для хранения значения?

Автор: sheka 7.07.2011 19:32

Ну 512бит это уже лучше, но все равно не много smile.gif

Когда игрался с типами забыл 8 убрать.

А есть какой-то битовый тип кроме boolean?

Автор: IUnknown 7.07.2011 20:14

512 бит - это 64 байта, а тип Int64 - это 64 бита...

Цитата
А есть какой-то битовый тип кроме boolean?
Нет. Ко всему прочему, Boolean - ни разу не битовый. То, что он может хранить только 2 значения - еще ни о чем не говорит... Ты задачу-то озвучь, может что-то кроме таких извращений можно будет придумать. Чего ты привязался к битам?

... (Показать/Скрыть)

Автор: sheka 8.07.2011 2:22

Что-то я лишний раз на 8 умножил (логарифм от того большого числа брал).
Но если массив booleanoв, то можно делать приведение типов word(a[i]) и будет выдавать нужный результат при той же занимаемой памяти что и у битов.
Задачу не помню, сродни вот этой http://forum.pascal.net.ru/index.php?showtopic=28555, но там надо было как-то передвигать штуки типа японского кроссворда. Обычно из-за того, что не хватает разрядной сетки пользуюсь рекурсией, хотя очень бы хотелось пользоваться такими штуками

Автор: IUnknown 8.07.2011 18:01

Цитата
Но если массив booleanoв, то можно делать приведение типов word(a[i]) и будет выдавать нужный результат при той же занимаемой памяти что и у битов.
Не будет. Либо тебе очень повезло и ты натолкнулся на простое совпадение, либо результат будет, но неправильный. Массив Boolean-ов никогда не занимает в памяти места меньше, чем по 1 байту на значение...

Попробуй показать тестовый код, скажем, который вот так же, как мой напечатает содержимое Integer-а через массив Boolean-ов, при этом места этот самый массив будет занимать ровно 2 байта (как и сам Integer) smile.gif

Автор: sheka 9.07.2011 3:01

Цитата
Не будет. Либо тебе очень повезло и ты натолкнулся на простое совпадение, либо результат будет, но неправильный. Массив Boolean-ов никогда не занимает в памяти места меньше, чем по 1 байту на значение...
Не ожидал. Совсем не ожидал. А почему Boolean занимает ВСЕГДА 1 байт? Зачем оно так?

Это АДА?

Автор: Lapp 9.07.2011 3:29

Цитата(sheka @ 9.07.2011 0:01) *
Не ожидал. Совсем не ожидал. А почему Boolean занимает ВСЕГДА 1 байт? Зачем оно так?

А чего тут ожидать/не_ожидать? Берешь проверяешь, sizeof всегда под рукой.

Идеология простая.
1. Архитектура памяти - байтовая. То есть невозможно адресовать бит в системе команд.
2. Каждая переменная должна иметь свой адрес.

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

У меня когда-то был модуль для побитового доступа к памяти. Сделать его нетрудно. Скорость в те времена падала заметно, сейчас ситуация может быть лучше. Все зависит от того, КАК реализовать )).

Автор: sheka 9.07.2011 3:38

Да это понятно, что sizeof все прекрасно выдает, так и проверял, но почему-то на подсознании думал раз 2 значения, значит бит.
Идеология кого?
Архитектура языка?
И в какую сторону его реализовывать? smile.gif

Автор: IUnknown 9.07.2011 3:38

Цитата
А почему Boolean занимает ВСЕГДА 1 байт? Зачем оно так?
Стоп... Похоже, FPC умеет-таки упаковывать биты (в Дельфи, однако, этого нет до сих пор, http://qc.embarcadero.com/wc/qcmain.aspx?d=56480):

type
bit = 0 .. 1;
bitarr = bitpacked array[1 .. 16] of bit;

var
X : word;
i : integer;
ba : bitarr absolute X;
begin
writeln(sizeof(ba));
X := 5458;
for i := 16 downto 1 do //
write(ba[i]);
writeln;
end.
=>
2
0001010101010010



Цитата
Это АДА?
ADA - это Ассоциация Дантистов Америки, а это - Ada smile.gif

Автор: Lapp 9.07.2011 3:51

Цитата(sheka @ 9.07.2011 0:38) *
Идеология кого?
Программирования.

Цитата
Архитектура языка?
Компьютера.

Цитата
И в какую сторону его реализовывать? smile.gif
Ну как.. Нужно тебе 100 бит. Вызываешь процедуру (свою) MakeBitArray(A,100). Она реально заводит массив из 13 байт. Потом ты обращаешья к нему функцией GetBit(A,55): integer, которая дает тебе 55-ое значение из того массива (используя всякие маски).

Но погоди мутить, volvo877 что-то нарыл, похоже..

Автор: sheka 9.07.2011 3:59

Стремный метод однако.
Лучше ничего нет?

Дык получается, что первые 7 бит booleana - вечные 0 ?

Автор: Lapp 9.07.2011 4:09

Цитата(sheka @ 9.07.2011 0:59) *
Дык получается, что первые 7 бит booleana - вечные 0 ?

Это почему?? никто не гарантировал..

Автор: IUnknown 9.07.2011 4:09

Цитата
Дык получается, что первые 7 бит booleana - вечные 0 ?
Кто тебе сказал, что Boolean - это только 0 и 1? Не было такого уговора. False - да, это 0. А вот насчет True ограничений не было:

var
b : boolean;
begin
b := boolean(255);
writeln(b);
writeln(byte(b));
end.

Все, что не 0 - True... Так что не вечные нули. Смотря ка используешь Boolean...

Цитата
Стремный метод однако.
Хм... Тебя не поймешь. То тебе не так, это - не этак. Скажи, что нужно... Лучше bitpacked все равно вряд ли сделаешь...

Автор: Lapp 9.07.2011 4:15

Кроме прочего, если заводишь boolean переменную динамически, в первый момент там все, что угодно. И, как сказал IU (сорри, очень длинно..)), трактуется так: 0 - ложь, не 0 - правда.

Автор: sheka 9.07.2011 4:18

Делфи на такую штуку иероглифы выводит. Не нравится ему писать TRUE если не 00000001 smile.gif

Это-то и нужно, просто это не интересно, до этого даже я додумался smile.gif
Лучше и не надо, меня именно и интересуют извращения, т. е. посмотреть что можно вытащить из возможностей.

Ну как бы в Си такое же понятие True и False, и именно поэтому как зарезервированные слова они появились позже и то в библиотеках, если не ошибаюсь. Зачем тогда было выдумывать boolean? для простой смены True = not False ?

Автор: Lapp 9.07.2011 4:50

Цитата(sheka @ 9.07.2011 1:18) *
Ну как бы в Си такое же понятие True и False, и именно поэтому как зарезервированные слова они появились позже и то в библиотеках, если не ошибаюсь. Зачем тогда было выдумывать boolean? для простой смены True = not False ?
В Си это не понятие, а интерпретация.
Для лучшей типизации.

Автор: IUnknown 9.07.2011 16:56

Цитата
Лучше и не надо, меня именно и интересуют извращения, т. е. посмотреть что можно вытащить из возможностей.
Я б не рекомендовал тебе заниматься подобными извращениями. По той простой причине, что такие вот "финты ушами" мало того, что малопереносимы между разными компиляторами (как ты уже успел убедиться, код, работающий под FPC, не работает при использовании Дельфи), так еще и при выходе новой версии того же компилятора могут быть проблемы (да, достаточно вспомнить те ужесточения, которые были сделаны при переходе от FPC 2.2.x к 2.4.0, многое из того, что было разрешено в ветке 2.2, в ветке 2.4 делать нельзя). Так что тут игра не стоит свеч. Или будешь переписывать код под каждую версию компилятора smile.gif

Цитата
Зачем тогда было выдумывать boolean? для простой смены True = not False ?
Знаешь, в том виде, в котором оно есть в FPC/Дельфи - лучше б этого типа вообще не было. Изначально это задумывалось совсем в другом виде. Вот в Турбо-Паскале более правильная реализация типа Boolean. Тот код, который я приводил в 14-ом сообщении там тоже будет компилироваться, но writeln(byte(b)) выведет не 255, а 1. И любое ненулевое значение, преобразованное к Boolean, также вернется как 1.

Но в Модуле, Haskell-е и Аде еще более корректная реализация: там это именно перечисление, и преобразовать Integer -> Boolean и обратно обычным тайпкастом просто нельзя. Вот именно так это и задумывалось. Хаки - они для программ смертельны...

Автор: sheka 10.07.2011 1:42

Цитата
Но в Модуле, Haskell-е и Аде еще более корректная реализация: там это именно перечисление

Расскажите о перечислениях более подробно: их представление, размер, кол-во элементов.
SizeOf выдает 4байта. Значит кол-во 232?

Интервальный тип округляется к большему целому кол-ву байт, но не больше 8ми?

Автор: IUnknown 10.07.2011 2:43

Цитата
SizeOf выдает 4байта
Ты опять совершаешь ту же самую ошибку. Пойми, что на SizeOf нельзя полагаться, он будет выдавать разные значения в зависимости от
1) режима, в котором происходит компиляция;
2) использования настроек компилятора или директив.

В частности, на размер типа-перечисления влияет использование директивы $PACKENUM (минимальное количество байт, используемое для хранения перечислимых типов) : в режиме совместимости с Дельфи и ТП по умолчанию принимается {$PACKENUM 1}, в режиме MacPas - {$PACKENUM 2}, в остальных режимах - 4 байта...

Да, максимально теперь поддерживается 232 элементов перечисления (значения хранятся как Byte/Word/Longword в зависимости от количества элементов, и от установленного значения PACKENUM, об этом можно почитать в файле prog.pdf: "8.2.4 Enumeration types")

Цитата
Интервальный тип округляется к большему целому кол-ву байт, но не больше 8ми?
Угу. Ибо самый емкий целочисленный тип имеет размер в 8 байт (Int64 или QWord), больше нет смысла выделять под интервал, границы интервала всегда целочисленные (емкость всех остальных перечислимых типов типов все равно меньше, так что их здесь не принимаем во внимание)