【问题标题】:Convert Integer to Generic Base Matlab将整数转换为通用基础 Matlab
【发布时间】:2017-04-02 16:04:19
【问题描述】:

我正在尝试将基数为 10 的整数 k 转换为基数为 q 的整数,但不是以标准方式。首先,我希望我的结果是一个向量(或一个字符串'a,b,c,...',以便它可以转换为一个向量,但不是'abc ...')。最重要的是,我希望每个“数字”都以 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 等东西,但没有运气。任何建议将不胜感激。

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

明确地说,我正在寻找一种适用于任何 q 和 n 的算法,可以转换 [0,q^n - 1] 范围内的任何数字。

【问题讨论】:

  • floor^/ 已经矢量化。循环不是必需的。
  • 啊,他们当然是!当然,我的 for 循环很垃圾,根本没有提供我想要的东西 =P - 让我改变一下......

标签: algorithm matlab decimal base base-conversion


【解决方案1】:

Matlab 的内部dec2base 命令基本上包含您所要求的内容。 它实际上创建了一个以 10 为基数的数组,然后将它们转换为 '0'-'9' 和 'A'-'Z' 的字符数组,这就是它限制基数

因此,在从dec2base 中删除字符转换的最后一步并相应地修改错误检查后,即可得到您所要求的函数dec2basevect

结果将是一个基数为 10 的向量,您不再局限于基数 fliplr

由于 MathWorks 的版权,您必须自行对dec2base进行必要的修改。

【讨论】:

  • 你已经包含了归属,这很好而且正确。但不幸的是,这并不能改变您违反版权法的事实。这是专有的、按使用付费的代码。通过在此处发布它,您将根据 CC 许可对其进行重新许可,由于您不是版权所有者,因此您无权这样做。
  • 好的,谢谢。我将删除代码。所以任何想要使用它的人都必须自己做这个修改。
  • 我认为这是个好主意。
【解决方案2】:

您可以使用dec2base 并将字符替换为数字:

x = 23;
b = 12;
[~, result] = ismember(dec2base(x,b), ['0':'9' 'A':'Z']);
result = result -1;

给予

>> result
result =
     1    11

由于dec2base 的限制,这适用于base up to 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 日):更正了两个错误:处理由所有“零”组成的输入(感谢 @Sanchises 的注意),并在需要时用“零”正确填充输出.

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

【讨论】:

  • 抱歉,我希望为通用 q 执行此操作,所以这对我不起作用。我会在问题中更清楚地说明这一点。
  • 另外,使用 x = 125q = 16 的算法(我假设你的意思是只适用于 q 最多 36;x 可以是任何东西)给出结果 [7, -1] , 什么时候应该是 [7, 13]...
  • @SamT 抱歉,有错字。现已更正。对于 36 以上的基数,您需要手动进行(本质上是长除法)。我曾经为此写过一个函数;让我找到它
  • 用我的base2base函数编辑
  • 太好了,谢谢。我将在星期一实现它:)——看起来它也应该很快:没有很长的 for 循环。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多