Konversi Integer ke Matlab Basis Generik

Saya mencoba mengubah bilangan bulat basis-10 k menjadi bilangan bulat basis-q, tetapi tidak dengan cara standar. Pertama, saya ingin hasil saya berupa vektor (atau string 'a,b,c,...' sehingga dapat diubah menjadi vektor, tetapi bukan 'abc...'). Yang terpenting, saya ingin setiap 'digit' berada di basis 10. Sebagai contoh, misalkan saya memiliki angka 23 (dalam basis-10) dan saya ingin mengubahnya menjadi basis-12. Ini akan menjadi 1B dalam notasi standar 1,...,9,A,B; namun, saya ingin hasilnya menjadi [1, 11]. Saya hanya tertarik pada angka k dengan 0 \le k \le n^q - 1, di mana n sudah diperbaiki terlebih dahulu.

Dengan kata lain, saya ingin mencari koefisien a(r) sedemikian rupa sehingga k = \sum_{r=0}^{n-1} a(r) q^r di mana setiap a(r) berada di basis-10. (Perhatikan bahwa 0 \le a(r) \le q-1.)

Saya tahu saya bisa melakukan ini dengan for-loop -- saat ini sedang berjuang untuk mendapatkan rumus yang tepat! -- tapi saya ingin melakukannya dalam vektor, atau dengan fungsi internal yang cepat.

Namun, saya ingin menjadikan n menjadi besar, jadi saya lebih memilih cara yang lebih cepat daripada ini. (Tentu saja, saya dapat mengubahnya menjadi parfor-loop atau melakukannya di GPU; ini tidak praktis untuk situasi saya saat ini, jadi saya lebih memilih versi yang lebih langsung.)

Saya telah melihat hal-hal seperti dec2base, num2str, str2num, base2dec dan seterusnya, tetapi tidak berhasil. Setiap saran akan sangat dihargai.

Mengenai kecepatan dan ruang, praalokasi apa pun untuk bilangan bulat dalam rentang [0, q-1] atau serupa juga bagus.

Untuk lebih jelasnya, saya mencari algoritme yang berfungsi untuk q dan n apa pun, mengonversi bilangan apa pun dalam rentang [0,q^n - 1].


person Sam OT    schedule 18.11.2016    source sumber
comment
floor, ^, dan / sudah di-vektorisasi. Perulangan tidak diperlukan.   -  person excaza    schedule 18.11.2016
comment
Ah, tentu saja! Tentu saja, for-loop saya adalah sampah dan tidak memberikan apa yang saya inginkan sama sekali =P -- izinkan saya mengubahnya...   -  person Sam OT    schedule 18.11.2016


Jawaban (1)


Anda dapat menggunakan dec2base dan mengganti karakter dengan angka:

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

memberi

>> result
result =
     1    11

Ini berfungsi untuk basis hingga 36 saja, karena dec2base batasan.


Untuk basis apa pun (mungkin di atas 36) Anda perlu melakukan konversi secara manual. Saya pernah menulis fungsi base2base untuk melakukan itu (pada dasarnya pembagian panjang). Angka tersebut harus dimasukkan sebagai vektor digit pada basis asal, jadi Anda memerlukan dec2base(...,10) terlebih dahulu. Misalnya:

x = 125;
b = 6;
result = base2base(dec2base(x,10), '0':'9', b); % origin nunber, origin base, target base

memberi

result =
     3     2     5

Atau jika Anda perlu menentukan jumlah digit:

x = 125;
b = 6;
d = 5;
result = base2base(dec2base(x,10), '0':'9', b, d)
result =
     0     0     3     2     5

EDIT (15 Agustus 2017): Memperbaiki dua bug: penanganan input yang terdiri dari semua "nol" (terima kasih kepada @Sanchises untuk memperhatikan), dan mengisi output dengan "nol" dengan benar jika diperlukan.

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);
person Luis Mendo    schedule 18.11.2016
comment
Maaf, saya ingin melakukan ini untuk q generik, jadi ini tidak berhasil untuk saya. Saya akan memperjelasnya di pertanyaan. - person Sam OT; 18.11.2016
comment
Selain itu, menggunakan algoritme Anda dengan x = 125 dan q = 16 (saya berasumsi maksud Anda hanya berfungsi untuk q hingga 36; x bisa berupa apa saja) memberikan hasil [7, -1], padahal seharusnya [7, 13]... - person Sam OT; 18.11.2016
comment
@SamT Maaf, ada kesalahan ketik. Diperbaiki sekarang. Untuk basis di atas 36 Anda perlu melakukannya secara manual (pada dasarnya ini adalah pembagian panjang). Saya pernah menulis sebuah fungsi untuk itu; biarkan aku menemukannya - person Luis Mendo; 18.11.2016
comment
Diedit dengan fungsi base2base saya - person Luis Mendo; 18.11.2016
comment
Luar biasa, terima kasih. Saya akan menerapkannya pada hari Senin :) -- sepertinya ini juga akan cukup cepat: tidak ada perulangan yang terlalu lama. - person Sam OT; 18.11.2016
comment
@SamT Ketika saya menulisnya, saya tidak memikirkan kecepatan kode. Saya tidak berharap ini menjadi terlalu cepat, dengan dua loop while yang bersarang. Anda mungkin dapat memperoleh kecepatan dengan menghapus beberapa bagian yang tidak diperlukan, seperti dukungan susunan sel - person Luis Mendo; 18.11.2016
comment
Saya tidak terlalu khawatir tentang kecepatan. Karena kita sedang membicarakan n^q, saya tidak bisa menganggap n menjadi sangat besar! - person Sam OT; 18.11.2016
comment
Ah, sayangnya ini tidak berhasil untuk saya: Saya harus memiliki angka 0 di awal. Misalnya, 1 harus (0,0,...,0,1). Saya sadar saya tidak menjelaskannya. Dengan dec2base (yang hanya dapat saya gunakan untuk q ‹= 10), saya dapat menggunakan dec2base(x,q,n) untuk memaksa string memiliki n entri, menambahkan 0 di awal jika diperlukan. Terima kasih atas bantuan Anda - person Sam OT; 21.11.2016
comment
@SamT Fungsi saya memiliki parameter opsional keempat yang melakukan itu. Saya telah menambahkan sebuah contoh - person Luis Mendo; 21.11.2016