将整数转换为通用基础 Matlab
Convert Integer to Generic Base Matlab
我正在尝试将以 10 为底的整数 k 转换为以 q 为底的整数,但不是以标准方式。首先,我希望我的结果是一个向量(或一个字符串 'a,b,c,...' 以便它可以转换为一个向量,而不是 'abc...')。最重要的是,我希望每个 'digit' 都以 10 为底。例如,假设我有数字 23(以 10 为基数),我想将其转换为 12 进制数。这将是标准 1,...,9,A,B 表示法中的 1B;但是,我希望它显示为 [1, 11]。我只对 0 \le k \le n^q - 1 的数字 k 感兴趣,其中 n 是预先固定的。
换句话说,我希望找到系数 a(r) 使得
k = \sum_{r=0}^{n-1} a(r) q^r
其中每个 a(r) 都以 10 为底。 (注意 0 \le a(r) \le q-1。)
我知道我可以用 for 循环来做到这一点——目前正在努力获得准确的公式! -- 但我想将其矢量化,或使用快速内部函数。
但是,我希望能够使 n 变大,所以我更喜欢比这更快的方法。 (当然,我可以将其更改为 parfor 循环或在 GPU 上执行;这些对我目前的情况不实用,所以我更喜欢更直接的版本。)
我看过 dec2base、num2str、str2num、base2dec 等等,但没有成功。任何建议将不胜感激。
关于速度和 space,对 [0, q-1] 或类似范围内的整数进行任何预分配也是好的。
明确地说,我正在寻找一种适用于任何 q 和 n 的算法,转换 [0,q^n - 1] 范围内的任何数字。
您可以使用 dec2base
并用数字替换字符:
x = 23;
b = 12;
[~, result] = ismember(dec2base(x,b), ['0':'9' 'A':'Z']);
result = result -1;
给予
>> result
result =
1 11
由于 dec2base
限制,这仅适用于 最多 36 个基数。
对于任何基数(可能大于 36),您需要手动进行转换。我曾经写过一个 base2base
函数来做到这一点(它本质上是长除法)。该数字应作为原始基数中的数字向量输入,因此您首先需要 dec2base(...,10)
。例如:
x = 125;
b = 6;
result = base2base(dec2base(x,10), '0':'9', b); % origin nunber, origin base, target base
给予
result =
3 2 5
或者如果需要指定位数:
x = 125;
b = 6;
d = 5;
result = base2base(dec2base(x,10), '0':'9', b, d)
result =
0 0 3 2 5
编辑(2017 年 8 月 15 日):更正了两个错误:处理由所有 "zeros" 组成的输入(感谢 @Sanchises 的注意),以及适当的左填充如果需要,输出带有 "zeros"。
function Z = base2base(varargin)
% Three inputs: origin array, origin base, target base
% If a base is specified by a number, say b, the digits are [0,1,...,d-1].
% The base can also be directly an array with the digits
% Fourth input, optional: how many digits the output should have as a
% minimum (padding with leading zeros, i.e with the first digit)
% Non-valid digits in origin array are discarded.
% It works with cell arrays. In this case it gives a matrix in which each
% row is padded with leading zeros if needed
% If the base is specified as a number, digits are numbers, not
% characters as in `dec2base` and `base2dec`
if ~iscell(varargin{1}), varargin{1} = varargin(1); end
if numel(varargin{2})>1, ax = varargin{2}; bx=numel(ax); else bx = varargin{2}; ax = 0:bx-1; end
if numel(varargin{3})>1, az = varargin{3}; bz=numel(az); else bz = varargin{3}; az = 0:bz-1; end
Z = cell(size(varargin{1}));
for c = 1:numel(varargin{1})
x = varargin{1}{c}; [valid, x] = ismember(x,ax); x = x(valid)-1;
if ~isempty(x) && ~any(x) % Non-empty input, all zeros
z = 0;
elseif ~isempty(x) % Non-empty input, at least a nonzero
z = NaN(1,ceil(numel(x)*log2(bx)/log2(bz))); done_outer = false;
n = 0;
while ~done_outer
n = n + 1;
x = [0 x(find(x,1):end)];
y = NaN(size(x)); done_inner = false;
m = 0;
while ~done_inner
m = m + 1;
t = x(1)*bx+x(2);
r = mod(t, bz); q = (t-r)/bz;
y(m) = q; x = [r x(3:end)];
done_inner = numel(x) < 2;
end
y = y(1:m);
z(n) = r; x = y; done_outer = ~any(x);
end
z = z(n:-1:1);
else % Empty input
z = []; % output will be empty (unless user has required left-padding) with the
% appropriate class
end
if numel(varargin)>=4 && numel(z)<varargin{4}, z = [zeros(1,varargin{4}-numel(z)) z]; end
% left-pad if required by user
Z{c} = z;
end
L = max(cellfun(@numel, Z));
Z = cellfun(@(x) [zeros(1, L-numel(x)) x], Z, 'uniformoutput', false); % left-pad so that
% result will be a matrix
Z = vertcat(Z{:});
Z = az(Z+1);
Matlab 的内部 dec2base
命令基本上包含您所要求的内容。
它实际上创建了一个 base-10 数字数组,然后将它们转换为 '0'-'9' 和 'A'-'Z' 的字符数组,这就是它限制为 bases <= 36 的原因.
因此,在从 dec2base
中删除字符转换的最后一步并相应地修改错误检查后,将提供您所要求的功能 dec2basevect
。
结果将是一个以 10 为基数的向量,您不再局限于基数 <= 36。最高有效数字将位于该向量的索引 1 中。如果您需要相反的方式,即索引 1 中的最低有效位,只需对结果执行 fliplr
。
由于 MathWorks 的版权,您必须自行对 dec2base
进行必要的修改。
我正在尝试将以 10 为底的整数 k 转换为以 q 为底的整数,但不是以标准方式。首先,我希望我的结果是一个向量(或一个字符串 'a,b,c,...' 以便它可以转换为一个向量,而不是 'abc...')。最重要的是,我希望每个 'digit' 都以 10 为底。例如,假设我有数字 23(以 10 为基数),我想将其转换为 12 进制数。这将是标准 1,...,9,A,B 表示法中的 1B;但是,我希望它显示为 [1, 11]。我只对 0 \le k \le n^q - 1 的数字 k 感兴趣,其中 n 是预先固定的。
换句话说,我希望找到系数 a(r) 使得
k = \sum_{r=0}^{n-1} a(r) q^r
其中每个 a(r) 都以 10 为底。 (注意 0 \le a(r) \le q-1。)
我知道我可以用 for 循环来做到这一点——目前正在努力获得准确的公式! -- 但我想将其矢量化,或使用快速内部函数。
但是,我希望能够使 n 变大,所以我更喜欢比这更快的方法。 (当然,我可以将其更改为 parfor 循环或在 GPU 上执行;这些对我目前的情况不实用,所以我更喜欢更直接的版本。)
我看过 dec2base、num2str、str2num、base2dec 等等,但没有成功。任何建议将不胜感激。
关于速度和 space,对 [0, q-1] 或类似范围内的整数进行任何预分配也是好的。
明确地说,我正在寻找一种适用于任何 q 和 n 的算法,转换 [0,q^n - 1] 范围内的任何数字。
您可以使用 dec2base
并用数字替换字符:
x = 23;
b = 12;
[~, result] = ismember(dec2base(x,b), ['0':'9' 'A':'Z']);
result = result -1;
给予
>> result
result =
1 11
由于 dec2base
限制,这仅适用于 最多 36 个基数。
对于任何基数(可能大于 36),您需要手动进行转换。我曾经写过一个 base2base
函数来做到这一点(它本质上是长除法)。该数字应作为原始基数中的数字向量输入,因此您首先需要 dec2base(...,10)
。例如:
x = 125;
b = 6;
result = base2base(dec2base(x,10), '0':'9', b); % origin nunber, origin base, target base
给予
result =
3 2 5
或者如果需要指定位数:
x = 125;
b = 6;
d = 5;
result = base2base(dec2base(x,10), '0':'9', b, d)
result =
0 0 3 2 5
编辑(2017 年 8 月 15 日):更正了两个错误:处理由所有 "zeros" 组成的输入(感谢 @Sanchises 的注意),以及适当的左填充如果需要,输出带有 "zeros"。
function Z = base2base(varargin)
% Three inputs: origin array, origin base, target base
% If a base is specified by a number, say b, the digits are [0,1,...,d-1].
% The base can also be directly an array with the digits
% Fourth input, optional: how many digits the output should have as a
% minimum (padding with leading zeros, i.e with the first digit)
% Non-valid digits in origin array are discarded.
% It works with cell arrays. In this case it gives a matrix in which each
% row is padded with leading zeros if needed
% If the base is specified as a number, digits are numbers, not
% characters as in `dec2base` and `base2dec`
if ~iscell(varargin{1}), varargin{1} = varargin(1); end
if numel(varargin{2})>1, ax = varargin{2}; bx=numel(ax); else bx = varargin{2}; ax = 0:bx-1; end
if numel(varargin{3})>1, az = varargin{3}; bz=numel(az); else bz = varargin{3}; az = 0:bz-1; end
Z = cell(size(varargin{1}));
for c = 1:numel(varargin{1})
x = varargin{1}{c}; [valid, x] = ismember(x,ax); x = x(valid)-1;
if ~isempty(x) && ~any(x) % Non-empty input, all zeros
z = 0;
elseif ~isempty(x) % Non-empty input, at least a nonzero
z = NaN(1,ceil(numel(x)*log2(bx)/log2(bz))); done_outer = false;
n = 0;
while ~done_outer
n = n + 1;
x = [0 x(find(x,1):end)];
y = NaN(size(x)); done_inner = false;
m = 0;
while ~done_inner
m = m + 1;
t = x(1)*bx+x(2);
r = mod(t, bz); q = (t-r)/bz;
y(m) = q; x = [r x(3:end)];
done_inner = numel(x) < 2;
end
y = y(1:m);
z(n) = r; x = y; done_outer = ~any(x);
end
z = z(n:-1:1);
else % Empty input
z = []; % output will be empty (unless user has required left-padding) with the
% appropriate class
end
if numel(varargin)>=4 && numel(z)<varargin{4}, z = [zeros(1,varargin{4}-numel(z)) z]; end
% left-pad if required by user
Z{c} = z;
end
L = max(cellfun(@numel, Z));
Z = cellfun(@(x) [zeros(1, L-numel(x)) x], Z, 'uniformoutput', false); % left-pad so that
% result will be a matrix
Z = vertcat(Z{:});
Z = az(Z+1);
Matlab 的内部 dec2base
命令基本上包含您所要求的内容。
它实际上创建了一个 base-10 数字数组,然后将它们转换为 '0'-'9' 和 'A'-'Z' 的字符数组,这就是它限制为 bases <= 36 的原因.
因此,在从 dec2base
中删除字符转换的最后一步并相应地修改错误检查后,将提供您所要求的功能 dec2basevect
。
结果将是一个以 10 为基数的向量,您不再局限于基数 <= 36。最高有效数字将位于该向量的索引 1 中。如果您需要相反的方式,即索引 1 中的最低有效位,只需对结果执行 fliplr
。
由于 MathWorks 的版权,您必须自行对 dec2base
进行必要的修改。