HE/bit2int.m

224 lines
7.8 KiB
Mathematica
Raw Normal View History

2024-03-30 16:35:40 +08:00
function y = bit2int(x, N, varargin)
%BIT2INT Convert bits to integers
%
% Y = BIT2INT(X,N) converts N column-wise bit elements in X to
% nonnegative integer values, with the first or the top-most bit
% being the MSB (most significant bit). X can be a column vector,
% matrix or an array with 3 dimensions. Number of rows in X must be
% an integer multiple of N. Y has same dimensions as X, except that
% the number of rows in Y are N times less than the number of rows in
% X. The datatype of X can be any of the built-in numeric types or
% logical. When the datatype of X is -
% - double or logical, datatype of Y is double.
% - single, datatype of Y is single.
% - a built-in integer type, Y has the same datatype as X unless the
% values in Y cannot be represented in that datatype without loss of
% data. If values in Y are larger than the intmax of the datatype of
% X, then Y is of the smallest datatype that can fit the values
% without loss of data. The datatype of Y has same signedness as that
% of X.
% - double or logical, N must be no larger than 53.
% - single, N must be no larger than 24.
% - a built-in signed integer type, N must be no larger than 63.
% - a built-in unsigned integer type, N must be no larger than 64.
%
% Y = BIT2INT(X,N,MSBFIRST) specifies MSB orientation in MSBFIRST.
% When MSBFIRST is true, the first bit in each set of N column-wise
% bits in X is the MSB; when MSBFIRST is false, the first bit in each
% set of N column-wise bits in X is the LSB (least significant bit).
%
% Y = BIT2INT(___,IsSigned=TF) specifies TF as a logical which can be
% either true or false to indicate the signed-ness of the integer.
% Default is false. When TF is true, then the first bit in each block
% of N bits is considered to be a signed bit and the output may
% contain negative values. If the datatype of X is any of the
% unsigned integer types with TF set to true, then the datatype of Y
% is the smallest signed integer type that can support the number of
% input bits.
%
% Examples:
%
% A1 = [1 0 1 0 1 0 1 0]';
% N1 = 8;
% B1 = bit2int(A1, N1);
%
% A2 = int8([1 1 0; 0 1 1]');
% N2 = 3;
% msbFirst = false;
% B2 = bit2int(A2, N2, msbFirst);
%
% A3 = randi([0,1], 32, 2, 2, 'uint8');
% N3 = 16;
% B3 = bit2int(A3, N3);
%
% A4 = [-110, 103, -103, 99];
% C4 = int2bit(A4,8);
% B4 = bit2int(C4,8,IsSigned=true);
%
% See also INT2BIT.
% Copyright 2021-2022 The MathWorks, Inc.
%#codegen
narginchk(2,5);
validateattributes(x, {'numeric','logical'}, {'3d','nonempty','binary'}, '', 'X');
if nargin == 2
MSBFirst = true;
IsSigned = false;
elseif nargin == 3
% If 3 inputs, then third argument must be MSBFirst option
IsSigned = false;
MSBFirst = varargin{1};
validateattributes(MSBFirst, {'logical','numeric'}, {'scalar','binary'}, '', 'MSBFirst');
else
% Then either 4 inputs with name-value is possible or 5 inputs with
% MSBFirst option and name-value of IsSigned is possible
if nargin == 4
signedOption = {varargin{1:2}}; % Codegen does not support cellarray(...). So use curly braces
MSBFirst = true;
else % nargin == 5
MSBFirst = varargin{1};
signedOption = {varargin{2:3}};
validateattributes(MSBFirst, {'logical','numeric'}, {'scalar','binary'}, '', 'MSBFirst');
end
defaults = struct("IsSigned",false);
res = comm.internal.utilities.nvParser(defaults, signedOption{:});
IsSigned = res.IsSigned;
validateattributes(IsSigned, {'logical','numeric'}, {'scalar','binary'}, '', 'IsSigned');
end
isSim = comm.internal.utilities.isSim();
if ~isSim
coder.internal.prefer_const(N);
end
isInputLogical = islogical(x);
% When N is equal to the max int supported (for example, N==8 for
% int8), -2^N calculation gives us -2^N + 1 because first 2^N gets
% calculated which cannot be fit into its native integer type (for
% example, int8 for N=8). To handle this corner case, subtract one
% after calculating negative value.
subone = false;
if isfloat(x) || isInputLogical
if isa(x, 'single')
maxN = 24;
else
maxN = 53;
end
validateattributes(N, {'numeric'}, {'scalar','positive','integer','<=',maxN}, '', 'N');
if isInputLogical
xNew = double(x);
isInputFloat = false;
else
xNew = x;
isInputFloat = true;
end
prototype = xNew(1);
else
% built-in integers
bitClass = class(x);
if bitClass(1) == 'u'
maxN = 64;
else
maxN = 63;
end
validateattributes(N, {'numeric'}, {'scalar','positive','integer','<=',maxN}, '', 'N');
coder.internal.errorIf(~isSim && ~coder.internal.isConst(N), ...
'comm:bit2int:NNotConst');
if bitClass(1) == 'u' && IsSigned
bitClassMax = intmax(bitClass(2:end));
else
bitClassMax = intmax(bitClass);
end
if IsSigned
c = '';
else
c = 'u';
end
if bitClass(1) == 'u' || IsSigned
if N <= 8
typeMax = intmax([c 'int8']);
subone = N==8;
elseif N <= 16
typeMax = intmax([c 'int16']);
subone = N==16;
elseif N <= 32
typeMax = intmax([c 'int32']);
subone = N==32;
else
typeMax = intmax([c 'int64']);
subone = N==64;
end
else
if N <= 7
typeMax = intmax('int8');
elseif N <= 15
typeMax = intmax('int16');
elseif N <= 31
typeMax = intmax('int32');
else
typeMax = intmax('int64');
end
end
if bitClassMax > typeMax
prototype = bitClassMax;
subone = false;
else
prototype = typeMax;
end
xNew = x;
isInputFloat = false;
end
useN = cast(N,'like',prototype);
if isInputFloat || (isSim && isInputLogical)
inSize = size(xNew);
nIntsPerCol = inSize(1)/double(N);
coder.internal.errorIf(nIntsPerCol ~= floor(nIntsPerCol), 'comm:bit2int:InvalidInputDims');
outSize = inSize;
outSize(1) = nIntsPerCol;
xMat = reshape(xNew, useN, []);
if MSBFirst
powOf2 = pow2(useN-1:-1:0);
powOf2(1) = (1-2*IsSigned)*powOf2(1);
else
powOf2 = pow2(0:useN-1);
powOf2(end) = (1-2*IsSigned)*powOf2(end);
end
y = reshape(powOf2 * xMat, outSize);
else
Nidx = coder.internal.indexInt(useN);
[nRows,nCols,nPages] = size(xNew);
nIntsPerCol = idivide(nRows, Nidx);
coder.internal.errorIf(Nidx*nIntsPerCol ~= nRows, ...
'comm:bit2int:InvalidInputDims');
y = coder.nullcopy(zeros(nIntsPerCol, nCols, nPages, 'like', prototype));
powOf2 = cast(2, 'like', y) .^ (useN-1:-1:0)';
powOf2(1) = (1-2*IsSigned)*powOf2(1)-1*subone*IsSigned;
xTmp = cast(xNew, 'like', y);
nInts = nIntsPerCol * coder.internal.indexInt(nCols) * coder.internal.indexInt(nPages);
if MSBFirst
idx = 1:Nidx;
else
idx = Nidx:-1:1;
end
for k=1:nInts
bits = xTmp(Nidx*(k-1) + idx);
y(k) = sum(bits(:) .* powOf2, 'native');
end
end
end