将Integer转换为Generic Base Matlab

时间:2016-11-18 17:56:28

标签: algorithm matlab decimal base base-conversion

我正在尝试将基数为10的整数k转换为基数为q的整数,但不是标准方式。首先,我希望我的结果是一个向量(或一个字符串'a,b,c,......',以便它可以转换为向量,但不是'abc ......')。最重要的是,我希望每个“数字”都在基数为10。举个例子,假设我有23号(基数为10),我想将它转换为base-12。这将是标准1,...,9,A,B表示法中的1B;但是,我希望它以[1,11]的形式出现。我只对数字k感兴趣,其中0 \ le k \ le n ^ q - 1,其中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-loop或在GPU上执行;这些对我目前的情况不实用,所以我更喜欢更直接的版本。)

我看过像dec2base,num2str,str2num,base2dec等东西,但没有运气。任何建议都会受到最高的赞赏。

关于速度和空间,[0,q-1]或类似范围内整数的任何预分配也都是好的。

要清楚,我正在寻找适用于任何q和n的算法,转换[0,q ^ n - 1]范围内的任何数字。

1 个答案:

答案 0 :(得分:4)

您可以使用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日):更正了两个错误:处理包含所有&#34;零&#34; (感谢@Sanchises注意),并使用&#34; 0&#34;正确地左键填充输出。如果需要的话。

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);