Search code examples
algorithmmatlaboctavenumericradix

dec2base with independent bits/digits calculation


Need MATLAB/Octave dec2base functionality function with independent bits/digits calculation algorithm (within integer logic, with no divisions, using modular arithmetic).

Would be nice to have as well:

  1. anonymous function

NB! floating logic and division could be used only one time for scalar to define the maximal amount of digits in converted numbers array:

ceil( log2(max(dec(:)))/log2(base)) )

The best answers:

  1. Anonymous function solution
  2. Regular Function solution

P.S.

  1. Solution for simplified dec2bin case listed here.
  2. Solution for bitget provided in this post: Matlab/Octave bitget function for any base

Solution

    1. In MATLAB / OCTAVE:

      % For Matlab/Octave: 
      de2bs = @(dec,base) base.^([(1+floor( log2(max(dec(:)))/log2(base)) ):-1:1]-1); % an array of powers of a base
      de2bs = @(dec,base) sum(rem(dec(:)                                ...
                                 ,base.*de2bs(dec,base)                 ...
                                 )                                      ...
                              >=permute((1:base-1)'*(de2bs(dec,base))   ...
                                       ,[3,2,1]                         ...
                                       )                                ...
                              ,3                                        ...
                              );          
      

      Example:

      x=0:9; base=3; de2bs(x,base)
      
      ans =
      
      0   0   0
      0   0   1
      0   0   2
      0   1   0
      0   1   1
      0   1   2           
      0   2   0
      0   2   1
      0   2   2
      1   0   0
      
    2. In OCTAVE only: as far as Octave supports default values for anonymous functions, there is a more interesting overloaded function implementation:

      % OCTAVE only (Matlab do not support default values for parameters)
      
      % Anonymous function de2bs
      % dig = digget(dec, base, isoutputasstring, pos)                
      %   dig  - returns the value of the digits in positions (pos) for numbers (dec)
      %          coverted to the defined base (for base=2 behaves similar to bitget) 
      %   dec  - mandatory, initial decimal numbers vector
      %   base - optional (by default base = 2),
      %          base to convert (for binary base = 2 )
      %   isoutputasstring - optional (by default isoutputasstring = true), 
      %          example: de2bs(26,16,0) -> '1A'
      %          example: de2bs(26,16,1) -> [1 10]%   
      %   pos  - optional (by default pos = (ceil( log2(max(dec(:)))/log2(base)) ):-1:1 ) 
      %          array of positions (like in bitget function)
      
      de2bs = @(dec
              ,base = [2]                                                  ... % Base of numbers you want to get
              ,isoutputinstringformat = [true]                             ... % output format 0/1 - integer/string 
              ,pos  = [(ceil( log2(max(dec(:)))/log2(base)) ):-1:1]        ... % Bits/digits positions to return (similar to bitget function)
          ... % temporary variables listed below (NOT parameters)          ...
              ,pbs  = [base.^(pos-1)]                                      ... % pbs - powers of base
              ,num  = [sum(rem(dec(:)                                      ... % conversion to defined base
                              ,base.*pbs                                   ...
                              )                                            ...
                          >= permute((1:base-1)'*pbs                       ...
                                    ,[3,2,1]                               ...
                                    )                                      ...
                          ,3                                               ...
                          )                                                ...
                      ]                                                    ...
              )                                                            ...
              ifelse(isoutputinstringformat                                ... % Convert digits to chars if necessary
                    ,char(ifelse(num>9,num+55, num+48))                    ... % like 9->'9', 10->'A', 11->'B';
                    ,num                                                   ... 
                    );
      

      Examples:

      x=25:28;
      base=16;
      
      
      de2bs(x)        % behaves as dec2bin(x)
      
      ans =
      
      11001
      11010
      11011
      11100        
      
      
      de2bs(x,base)   % behaves as dec2base(x,base)
      
      ans =
      
      19
      1A
      1B
      1C
      
      
      de2bs(x,base,0) % behaves as dec2base(x,base) without converting/mapping to string/char format
      
      ans =
      
      1    9
      1   10
      1   11
      1   12
      
      
      de2bs(x,base,1,[3 2 1])   % behaves as dec2base(x,base), but returns mentioned digits in number (like in bitget function)
      
      ans =
      
      019
      01A
      01B
      01C