แปลงจำนวนเต็มเป็น Matlab ฐานทั่วไป

ฉันกำลังพยายามแปลงจำนวนเต็มฐาน 10 k เป็นจำนวนเต็มฐาน q แต่ไม่ใช่ด้วยวิธีมาตรฐาน ประการแรก ฉันต้องการให้ผลลัพธ์ของฉันเป็นเวกเตอร์ (หรือสตริง 'a,b,c,...' เพื่อให้สามารถแปลงเป็นเวกเตอร์ได้ แต่ไม่ใช่ 'abc...') สิ่งสำคัญที่สุดคือ ฉันต้องการให้ 'หลัก' แต่ละหลักอยู่ในฐาน 10 ตามตัวอย่าง สมมติว่าฉันมีเลข 23 (อยู่ในฐาน 10) และฉันต้องการแปลงเป็นฐาน 12 นี่จะเป็น 1B ในรูปแบบมาตรฐาน 1,...,9,A,B; แต่ฉันอยากให้มันออกมาเป็น [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-loop -- กำลังดิ้นรนเพื่อให้ได้สูตรที่แน่นอนในขณะนี้! -- แต่ฉันอยากทำแบบเวกเตอร์ หรือมีฟังก์ชันภายในที่รวดเร็ว

อย่างไรก็ตามผมอยากให้ n มีขนาดใหญ่ได้ ดังนั้นอยากได้วิธีที่เร็วกว่านี้ (แน่นอน ฉันสามารถเปลี่ยนสิ่งนี้เป็น parfor-loop หรือทำบน GPU ได้ สิ่งเหล่านี้ไม่เหมาะกับสถานการณ์ปัจจุบันของฉัน ดังนั้นฉันต้องการเวอร์ชันที่ตรงกว่า)

ฉันได้ดูสิ่งต่าง ๆ เช่น dec2base, num2str, str2num, base2dec และอื่น ๆ แต่ก็ไม่มีโชค ข้อเสนอแนะใด ๆ ที่จะได้รับการชื่นชมมากที่สุด

เกี่ยวกับความเร็วและพื้นที่ การจัดสรรล่วงหน้าสำหรับจำนวนเต็มในช่วง [0, q-1] หรือที่คล้ายกันก็น่าจะดีเช่นกัน

เพื่อความชัดเจน ฉันกำลังมองหาอัลกอริทึมที่เหมาะกับ q และ n ใดๆ โดยแปลงตัวเลขใดๆ ในช่วง [0,q^n - 1]


person Sam OT    schedule 18.11.2016    source แหล่งที่มา
comment
floor, ^ และ / เป็นเวกเตอร์อยู่แล้ว ไม่จำเป็นต้องวนซ้ำ   -  person excaza    schedule 18.11.2016
comment
อา แน่นอนพวกเขาเป็น! แน่นอนว่า for-loop ของฉันมันขยะแขยงและไม่ได้ให้สิ่งที่ฉันต้องการเลย =P -- ขอฉันเปลี่ยนหน่อยเถอะ...   -  person Sam OT    schedule 18.11.2016


คำตอบ (1)


คุณสามารถใช้ dec2base และแทนที่อักขระด้วยตัวเลข:

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

ให้

>> result
result =
     1    11

ใช้งานได้กับ ฐานสูงสุด 36 เท่านั้น เนื่องจาก dec2base ข้อจำกัด


สำหรับ ฐานใดๆ (อาจมากกว่า 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

แก้ไข (15 สิงหาคม 2017): แก้ไขข้อบกพร่องสองประการ: การจัดการอินพุตที่ประกอบด้วย "ศูนย์" ทั้งหมด (ขอบคุณ @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);
person Luis Mendo    schedule 18.11.2016
comment
ขออภัย ฉันต้องการทำเช่นนี้กับ q ทั่วไป ดังนั้นจึงใช้ไม่ได้สำหรับฉัน ฉันจะทำให้คำถามชัดเจนยิ่งขึ้น - person Sam OT; 18.11.2016
comment
นอกจากนี้การใช้อัลกอริทึมของคุณกับ x = 125 และ q = 16 (ฉันคิดว่าคุณหมายถึงใช้งานได้เพียง q สูงสุด 36; x สามารถเป็นอะไรก็ได้) ให้ผลลัพธ์ [7, -1] เมื่อควรเป็น [7, 13]... - person Sam OT; 18.11.2016
comment
@SamT ขออภัย มีการพิมพ์ผิด แก้ไขแล้ว. สำหรับฐานที่สูงกว่า 36 คุณต้องทำด้วยตนเอง (โดยพื้นฐานแล้วเป็นการหารยาว) ครั้งหนึ่งฉันเคยเขียนฟังก์ชันสำหรับสิ่งนั้น ให้ฉันได้หามัน - person Luis Mendo; 18.11.2016
comment
แก้ไขด้วยฟังก์ชัน base2base ของฉัน - person Luis Mendo; 18.11.2016
comment
ยอดเยี่ยม ขอบคุณ ฉันจะใช้สิ่งนั้นในวันจันทร์ :) -- ดูเหมือนว่าจะค่อนข้างเร็วเช่นกัน: ไม่ต้องวนซ้ำนานมาก - person Sam OT; 18.11.2016
comment
@SamT เมื่อฉันเขียนฉันไม่มีความเร็วของโค้ดอยู่ในใจ ฉันไม่คาดหวังว่ามันจะเร็วเป็นพิเศษด้วย while ลูปสองตัวที่ซ้อนกัน คุณอาจได้รับความเร็วเพิ่มขึ้นในการลบส่วนที่ไม่จำเป็นบางส่วน เช่น การรองรับอาร์เรย์เซลล์ - person Luis Mendo; 18.11.2016
comment
ฉันไม่กังวลเกี่ยวกับความเร็วมากเกินไป เนื่องจากเรากำลังพูดถึง n^q ฉันจึงไม่อาจถือว่า n มีขนาดใหญ่มากอยู่แล้ว! - person Sam OT; 18.11.2016
comment
อ่า น่าเสียดายที่สิ่งนี้ใช้ไม่ได้สำหรับฉัน ฉันต้องมี 0 ตอนเริ่มต้น ตัวอย่างเช่น 1 ต้องเป็น (0,0,...,0,1) ฉันรู้ว่าฉันไม่ได้ทำให้เรื่องนี้ชัดเจน ด้วย dec2base (ซึ่งฉันใช้ได้เฉพาะกับ q ‹= 10) ฉันสามารถใช้ dec2base(x,q,n) เพื่อบังคับให้สตริงมีรายการ n โดยเพิ่ม 0 ที่จุดเริ่มต้นตามความจำเป็น ขอบคุณสำหรับความช่วยเหลือของคุณต่อไป - person Sam OT; 21.11.2016
comment
@SamT ฟังก์ชั่นของฉันมีพารามิเตอร์ทางเลือกตัวที่สี่ที่ทำสิ่งนั้น ฉันได้เพิ่มตัวอย่าง - person Luis Mendo; 21.11.2016