将整数转换为通用基础 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 进行必要的修改。