Преобразовать двоичную строку длиной более 52 бит в одну в Matlab?

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

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

Есть ли способ обойти это ограничение по размеру?


person mac389    schedule 10.09.2012    source источник
comment
Какая точность вам нужна? И какое максимальное количество бит?   -  person Paul R    schedule 10.09.2012
comment
Это неизвестно. Это часть исследовательского проекта. В любом случае, по моим оценкам, мне потребуется преобразовать двоичные строки длиной не более 1e6. Было бы здорово подобраться к этому как можно ближе. Возможно, я что-то упускаю, потому что заметил, что ceil(log2(1e6)) всего 20.   -  person mac389    schedule 10.09.2012
comment
1e6 бит представляет собой значение pow(2,1e6), которое представляет собой десятичное значение около 10^300000. Вы уверены, что вам нужно работать с такими большими числами (т. е. намного большими, чем число элементарных частиц во Вселенной)?   -  person Paul R    schedule 10.09.2012
comment
Длина строки, которую я бы передал такой функции, как dec2bin, может достигать 1e6. Это происходит из-за выборки процесса 1e4 раза в секунду, и я ожидаю, что шаблоны будут длиться около 100 с. Я использую десятичное значение двоичной строки в качестве хэша для построения таблицы поиска для расчета сложности LZ.   -  person mac389    schedule 10.09.2012
comment
Вы уверены, что используете dec2bin, а не bin2dec? dec2bin преобразует число в двоичное, а не двоичную строку в число...   -  person aardvarkk    schedule 10.09.2012
comment
@aardvarkk: Ты прав. Я использую бин2дек. Я исправил вопрос. Спасибо.   -  person mac389    schedule 10.09.2012


Ответы (3)


dec2bin выдает эту ошибку, потому что single не может хранить такую ​​точность. Сам ваш вопрос задает невозможное. У вас есть два варианта: сохранить значение в чем-то другом, кроме значения с плавающей запятой, или отказаться от некоторой точности перед преобразованием.

Или более подробно опишите, чего вы пытаетесь достичь.

РЕДАКТИРОВАНИЕ:

Основываясь на вашей дополнительной информации, я еще более уверен, что преобразование в числа с плавающей запятой - это не то, что вы хотите делать. Если вы хотите уменьшить размер хранилища до чего-то более эффективного, преобразуйте его в вектор байтов (uint8), максимально плотный. Просто разделите двоичную строку на N строк по 8 цифр в каждой, используя изменение формы. Это кажется общепринятым подходом к биологическим данным.

str = char((rand(1, 100)>0.5) + '0');    % test data
data = uint8(bin2dec(reshape(str(1:end-mod(end,8)), [], 8)));

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

person Peter    schedule 10.09.2012
comment
Я попросил помочь найти способ обойти это. - person mac389; 10.09.2012
comment
Ваши дополнительные комментарии помогли прояснить вашу цель. См. редактирование. - person Peter; 10.09.2012

Вы можете свернуть свою собственную реализацию:

len = 60;

string = [];
for i = 1:len
  string = [string sprintf('%d', randi([0 1]))];
end

% error
% bin2dec(string);

% roll your own...
value = 0;
for i = length(string):-1:1
  value = value + str2num(string(i))*2^(length(string)-i);
end

Я просто перебираю строку и добавляю к некоторому значению. В конце value будет содержать десятичное значение строки. Это работает для вас?

Примечание. Это решение медленное. Вы можете немного ускорить его, предварительно выделив строку, что я и сделал на своей машине. Кроме того, у него будут проблемы, если ваш номер будет содержать до 1e6 цифр. В этот момент вам нужна арифметика с переменной точностью, чтобы отслеживать это. И добавление этого к расчету действительно замедлило процесс. На вашем месте я бы настоятельно рекомендовал скомпилировать это из файла .mex, если вам нужна функциональность MATLAB.

person aardvarkk    schedule 10.09.2012

спасибо @aardvarkk, но вот ускоренная версия его алгоритма (+- в 100 раз быстрее):

N=100;
strbin = char(randi(2,1,N)+'0'-1);

pows2 = 2.^(N-1:-1:0);
value=pows2*(strbin-'0')';

Диапазон double идет только до 1.79769e+308, что 2^1024 плюс-минус. С этого момента value будет Inf или NaN. Так что вам все равно нужно найти другой способ сохранения полученного числа.

Последнее преимущество этого алгоритма: вы можете кэшировать pows2 для большого числа, а затем использовать его часть для любого нового strbin длины N:

Nmax = 1e8; % already 700MB for pows2, watch out!
pows2 = 2.^(Nmax-1:-1:0);

а затем использовать

value = pows2(Nmax-N+1:end)*(strbin-'0')';

Решение числовой верхней границы Matlab

В File Exchange есть инструмент под названием vpi: http://www.mathworks.com/matlabcentral/fileexchange/22725

Это позволяет вам использовать действительно большие целые числа (2^5000? нет проблем). Это только медленнее (намного) при расчете всего, я не предлагаю использовать мой метод выше с этим. Но эй, вы не можете иметь все!

Загрузите пакет, addpath его, и следующее может работать:

N=3000;
strbin = char(randi(2,1,N)+'0'-1);

binvals=strbin-'0';
val=0;
twopow=vpi(1);
for ii=1:N
    val=val+twopow*binvals(N-ii+1);
    twopow=twopow*2;
end
person Gunther Struyf    schedule 10.09.2012
comment
Обратите внимание, что double имеет только 52-битную точность (вероятно, отсюда и ограничение в 52 бита в bin2dec). - person Paul R; 10.09.2012