diff -r a87fa9132b72 scripts/strings/base2dec.m
--- a/scripts/strings/base2dec.m Sat Aug 11 17:32:42 2012 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,136 +0,0 @@
-## Copyright (C) 2000-2012 Daniel Calvelo
-##
-## This file is part of Octave.
-##
-## Octave is free software; you can redistribute it and/or modify it
-## under the terms of the GNU General Public License as published by
-## the Free Software Foundation; either version 3 of the License, or (at
-## your option) any later version.
-##
-## Octave is distributed in the hope that it will be useful, but
-## WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-## General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with Octave; see the file COPYING. If not, see
-## .
-
-## -*- texinfo -*-
-## @deftypefn {Function File} {} base2dec (@var{s}, @var{base})
-## Convert @var{s} from a string of digits in base @var{base} to a decimal
-## integer (base 10).
-##
-## @example
-## @group
-## base2dec ("11120", 3)
-## @result{} 123
-## @end group
-## @end example
-##
-## If @var{s} is a string matrix, return a column vector with one value per
-## row of @var{s}. If a row contains invalid symbols then the
-## corresponding value will be NaN@.
-##
-## If @var{s} is a cell array of strings, return a column vector with one
-## value per cell element in @var{s}.
-##
-## If @var{base} is a string, the characters of @var{base} are used as the
-## symbols for the digits of @var{s}. Space (' ') may not be used as a
-## symbol.
-##
-## @example
-## @group
-## base2dec ("yyyzx", "xyz")
-## @result{} 123
-## @end group
-## @end example
-## @seealso{dec2base, bin2dec, hex2dec}
-## @end deftypefn
-
-## Author: Daniel Calvelo
-## Adapted-by: Paul Kienzle
-
-function out = base2dec (s, base)
-
- if (nargin != 2)
- print_usage ();
- endif
-
- if (iscellstr (s))
- s = char (s);
- elseif (! ischar (s))
- error ("base2dec: S must be a string or cellstring");
- endif
-
- symbols = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- if (ischar (base))
- symbols = base;
- base = length (symbols);
- if (length (unique (symbols)) != base)
- error ("base2dec: symbols representing digits must be unique");
- endif
- if (any (isspace (symbols)))
- error ("base2dec: whitespace characters are not valid symbols");
- endif
- elseif (! isscalar (base))
- error ("base2dec: cannot convert from several bases at once");
- elseif (base < 2 || base > length (symbols))
- error ("base2dec: BASE must be between 2 and 36, or a string of symbols");
- else
- s = toupper (s);
- endif
-
- ## Right justify the values and squeeze out any spaces.
- ## This looks complicated, but indexing solution is very fast
- ## compared to alternatives which use cellstr or cellfun or looping.
- [nr, nc] = size (s);
- if (nc > 1) # Bug #35621
- s = s.';
- nonbl = s != " ";
- num_nonbl = sum (nonbl);
- nc = max (num_nonbl);
- num_blank = nc - num_nonbl;
- R = repmat ([1 2; 0 0], 1, nr);
- R(2, 1:2:2*nr) = num_blank;
- R(2, 2:2:2*nr) = num_nonbl;
- idx = repelems ([false, true], R);
- idx = reshape (idx, nc, nr);
-
- ## Create a blank matrix and position the nonblank characters.
- s2 = repmat (" ", nc, nr);
- s2(idx) = s(nonbl);
- s = s2.';
- endif
-
- ## Lookup value of symbols in symbol table, with invalid symbols
- ## evaluating to NaN and space evaluating to 0.
- table = NaN (1, 256);
- table(toascii (symbols(1:base))) = 0 : base-1;
- table(toascii (" ")) = 0;
- s = reshape (table(toascii (s)), size (s));
-
- ## Multiply the resulting digits by the appropriate power
- ## and sum the rows.
- out = s * (base .^ (columns(s)-1 : -1 : 0)');
-
-endfunction
-
-
-%!assert (base2dec ("11120", 3), 123)
-%!assert (base2dec ("yyyzx", "xyz"), 123)
-%!assert (base2dec ("-1", 2), NaN)
-%!assert (base2dec ({"A1", "1A"}, 16), [161; 26])
-
-%% Bug #35621
-%!assert (base2dec (["0"; "1"], 2), [0; 1])
-
-%%Test input validation
-%!error base2dec ()
-%!error base2dec ("11120")
-%!error base2dec ("11120", 3, 4)
-%!error base2dec ("11120", "1231")
-%!error base2dec ("11120", "12 3")
-%!error base2dec ("11120", ones (2))
-%!error base2dec ("11120", 37)
-
diff -r a87fa9132b72 scripts/strings/dec2base.m
--- a/scripts/strings/dec2base.m Sat Aug 11 17:32:42 2012 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,167 +0,0 @@
-## Copyright (C) 2000-2012 Daniel Calvelo
-##
-## This file is part of Octave.
-##
-## Octave is free software; you can redistribute it and/or modify it
-## under the terms of the GNU General Public License as published by
-## the Free Software Foundation; either version 3 of the License, or (at
-## your option) any later version.
-##
-## Octave is distributed in the hope that it will be useful, but
-## WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-## General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with Octave; see the file COPYING. If not, see
-## .
-
-## -*- texinfo -*-
-## @deftypefn {Function File} {} dec2base (@var{d}, @var{base})
-## @deftypefnx {Function File} {} dec2base (@var{d}, @var{base}, @var{len})
-## Return a string of symbols in base @var{base} corresponding to
-## the non-negative integer @var{d}.
-##
-## @example
-## @group
-## dec2base (123, 3)
-## @result{} "11120"
-## @end group
-## @end example
-##
-## If @var{d} is a matrix or cell array, return a string matrix with one
-## row per element in @var{d}, padded with leading zeros to the width of
-## the largest value.
-##
-## If @var{base} is a string then the characters of @var{base} are used as
-## the symbols for the digits of @var{d}. Space (' ') may not be used
-## as a symbol.
-##
-## @example
-## @group
-## dec2base (123, "aei")
-## @result{} "eeeia"
-## @end group
-## @end example
-##
-## The optional third argument, @var{len}, specifies the minimum
-## number of digits in the result.
-## @seealso{base2dec, dec2bin, dec2hex}
-## @end deftypefn
-
-## Author: Daniel Calvelo
-## Adapted-by: Paul Kienzle
-
-function retval = dec2base (d, base, len)
-
- if (nargin < 2 || nargin > 3)
- print_usage ();
- endif
-
- if (iscell (d))
- d = cell2mat (d);
- endif
-
- # Create column vector for algorithm
- if (! iscolumn (d))
- d = d(:);
- endif
-
- if (! isnumeric (d) || iscomplex (d) || any (d < 0 | d != fix (d)))
- error ("dec2base: input must be real non-negative integers");
- endif
-
- symbols = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- if (ischar (base))
- symbols = base;
- base = length (symbols);
- if (length (unique (symbols)) != base)
- error ("dec2base: symbols representing digits must be unique");
- endif
- if (any (isspace (symbols)))
- error ("dec2base: whitespace characters are not valid symbols");
- endif
- elseif (! isscalar (base))
- error ("dec2base: cannot convert from several bases at once");
- elseif (base < 2 || base > length (symbols))
- error ("dec2base: BASE must be between 2 and 36, or a string of symbols");
- endif
-
- ## determine number of digits required to handle all numbers, can overflow
- ## by 1 digit
- max_len = round (log (max (max (d(:)), 1)) / log (base)) + 1;
-
- if (nargin == 3)
- max_len = max (max_len, len);
- endif
-
- ## determine digits for each number
- digits = zeros (length (d), max_len);
- for k = max_len:-1:1
- digits(:,k) = mod (d, base);
- d = round ((d - digits(:,k)) / base);
- endfor
-
- ## convert digits to symbols
- retval = reshape (symbols(digits+1), size (digits));
-
- ## Check if the first element is the zero symbol. It seems possible
- ## that LEN is provided, and is less than the computed MAX_LEN and
- ## MAX_LEN is computed to be one larger than necessary, so we would
- ## have a leading zero to remove. But if LEN >= MAX_LEN, we should
- ## not remove any leading zeros.
- if ((nargin == 2 || (nargin == 3 && max_len > len))
- && length (retval) != 1 && ! any (retval(:,1) != symbols(1)))
- retval = retval(:,2:end);
- endif
-
-endfunction
-
-
-%!test
-%! s0 = "";
-%! for n = 1:13
-%! for b = 2:16
-%! pp = dec2base (b^n+1, b);
-%! assert (dec2base (b^n, b), ['1',s0,'0']);
-%! assert (dec2base (b^n+1, b), ['1',s0,'1']);
-%! endfor
-%! s0 = [s0,'0'];
-%! endfor
-
-%!test
-%! digits = "0123456789ABCDEF";
-%! for n = 1:13
-%! for b = 2:16
-%! pm = dec2base (b^n-1, b);
-%! assert (length (pm), n);
-%! assert (all (pm == digits(b)));
-%! endfor
-%! endfor
-
-%!test
-%! for b = 2:16
-%! assert (dec2base (0, b), '0');
-%! endfor
-
-%!assert (dec2base (0, 2, 4), "0000")
-%!assert (dec2base (2^51-1, 2), ...
-%! "111111111111111111111111111111111111111111111111111")
-%!assert (dec2base (uint64 (2)^63-1, 16), "7FFFFFFFFFFFFFFF")
-%!assert (dec2base ([1, 2; 3, 4], 2, 3), ["001"; "011"; "010"; "100"])
-%!assert (dec2base ({1, 2; 3, 4}, 2, 3), ["001"; "011"; "010"; "100"])
-
-%%Test input validation
-%!error dec2base ()
-%!error dec2base (1)
-%!error dec2base (1, 2, 3, 4)
-%!error dec2base ("A")
-%!error dec2base (2i)
-%!error dec2base (-1)
-%!error dec2base (1.1)
-%!error dec2base (1, "ABA")
-%!error dec2base (1, "A B")
-%!error dec2base (1, ones (2))
-%!error dec2base (1, 1)
-%!error dec2base (1, 37)
-
diff -r a87fa9132b72 src/corefcn/strfns.cc
--- a/src/libinterp/corefcn/strfns.cc Sat Aug 11 17:32:42 2012 -0400
+++ b/src/libinterp/corefcn/strfns.cc Sun Aug 19 19:56:58 2012 -0500
@@ -971,3 +971,679 @@
%!error list_in_columns (["abc", "def"], 20, " ", 3)
%!error list_in_columns (["abc", "def"], "a")
*/
+
+
+// Core conversion routine. Note: Could convert BASE to ASCII string and
+// reuse code base2dec_str_str_op(), but that would require creating
+// intermediate copies which have symbols converted to either lower case
+// or upper case. Trade off code duplication in favor of efficiency.
+static long unsigned int
+base2dec_str_dbl_op (const std::string& S, const double& BASE, bool *error)
+{
+ *error = false;
+
+ // Find the start/end of string
+ const char *idx = S.c_str ();
+ const char *last = idx + S.length ();
+
+ // Compute the decimal conversion
+ long unsigned int retval = 0;
+ for (; idx < last; idx++)
+ {
+ if (*idx == ' ')
+ // Ignore space
+ continue;
+
+ unsigned int numeral = BASE;
+ if (*idx >= '0' && *idx <= '9')
+ numeral = *idx - '0';
+ else if (*idx >= 'A' && *idx <= 'Z')
+ numeral = *idx - 'A' + 10;
+ else if (*idx >= 'a' && *idx <= 'z')
+ numeral = *idx - 'a' + 10;
+
+ if (numeral >= BASE)
+ {
+ // There may be better ways to write this using C++ strings syntax
+ warning ("base2dec: symbol out of range, '%s:%c:%s'", S.substr (0, idx-S.c_str ()).c_str (), *idx, S.substr (idx+1-S.c_str(), last-idx).c_str ());
+ *error = true;
+ return 0;
+ }
+ else
+ // Do cumulative product
+ retval = retval * BASE + numeral;
+ }
+
+ return retval;
+}
+
+// Core conversion routine.
+static long unsigned int
+base2dec_str_str_op (const std::string& S, const std::string& mapstr, bool *error)
+{
+ *error = false;
+
+ unsigned int BASE = mapstr.length ();
+ long unsigned int retval = 0;
+ for (unsigned int j = 0; j < S.length (); j++)
+ {
+ if (S[j] == ' ')
+ // Ignore space
+ continue;
+
+ size_t numeral = mapstr.find_first_of(S[j]);
+ if (numeral == mapstr.npos)
+ {
+ // There may be better ways to write this using C++ strings syntax
+ warning ("base2dec: symbol out of range, '%s:%c:%s'", S.substr (0, j).c_str (), S[j], S.substr (j+1, S.length()-j).c_str ());
+ *error = true;
+ return 0;
+ }
+ else
+ // Do cumulative product
+ retval = retval * BASE + numeral;
+ }
+
+ return retval;
+}
+
+octave_value
+base2dec_matrix_dbl_op (const charMatrix& S, const double& BASE)
+{
+ // Create output column array
+ dim_vector dim_output = S.dims ();
+ dim_output.elem (1) = 1;
+ NDArray output (dim_output, false);
+
+ for (octave_idx_type i = 0; i < S.rows (); i++)
+ {
+ bool error;
+ output(i) = base2dec_str_dbl_op (S.row_as_string (i), BASE, &error);
+ if (error)
+ output(i) = NAN;
+ }
+
+ return output;
+}
+
+std::string
+check_valid_base_string (const charMatrix& BASE)
+{
+ std::string mapstr;
+
+ // Make sure base is character array
+ if (BASE.rows () > 1)
+ {
+ if (BASE.columns () > 1)
+ {
+ error ("base2dec: the base must be a string vector");
+ return mapstr;
+ }
+ else
+ {
+ charMatrix tmpmat = BASE;
+ tmpmat.transpose ();
+ mapstr = tmpmat.row_as_string (0);
+ }
+ }
+ else
+ mapstr = BASE.row_as_string (0);
+
+ // Verify base is greater than one
+ if (mapstr.length() < 2)
+ {
+ error ("base2dec: base must be greater than 1");
+ return mapstr;
+ }
+
+ // Verify no white space in base vector
+ if (mapstr.find(' ') != mapstr.npos)
+ {
+ error ("base2dec: mapping string must be free of spaces, '%s'", mapstr.c_str ());
+ return mapstr;
+ }
+
+ // Verify unique characters in base vector
+ for (unsigned int i = 0; i < mapstr.length (); i++)
+ for (unsigned int j = i+1; j < mapstr.length (); j++)
+ {
+ if (mapstr[i] == mapstr[j])
+ {
+ error ("base2dec: mapping string must have unique characters, '%s'", mapstr.c_str());
+ return mapstr;
+ }
+ }
+
+ return mapstr;
+}
+
+octave_value
+base2dec_matrix_str_op (const charMatrix& S, const charMatrix& BASE)
+{
+ // Check validity of mapping string
+ std::string mapstr = check_valid_base_string (BASE);
+
+ // Create output column array
+ dim_vector dim_output = S.dims ();
+ dim_output.elem (1) = 1;
+ NDArray output (dim_output, false);
+
+ for (octave_idx_type i = 0; i < S.rows (); i++)
+ {
+ const std::string S_row = S.row_as_string (i);
+ bool error;
+ output(i) = base2dec_str_str_op (S_row, mapstr, &error);
+ if (error)
+ output(i) = NAN;
+ }
+
+ return output;
+}
+
+octave_value
+base2dec_cell_dbl_op (const Cell& S, const double& BASE)
+{
+ // Create output column array
+ if (!S.is_vector ())
+ {
+ error ("base2dec: cell must be a row or column vector");
+ return -1;
+ }
+ ColumnVector output (S.dims ().numel (), false);
+
+ for (octave_idx_type i = 0; i < S.length (); i++)
+ {
+ if (S(i).is_string ())
+ {
+ bool error;
+ output(i) = base2dec_str_dbl_op (S(i).string_value (), BASE, &error);
+ if (error)
+ output(i) = NAN;
+ }
+ else
+ {
+ error ("base2dec: cell %d is not a string", i+1);
+ return -1;
+ }
+ }
+
+ return output;
+}
+
+octave_value
+base2dec_cell_str_op (const Cell& S, const charMatrix& BASE)
+{
+ // Check validity of mapping string
+ std::string mapstr = check_valid_base_string (BASE);
+
+ // Create output column array
+ if (!S.is_vector ())
+ {
+ error ("base2dec: cell must be a row or column vector");
+ return -1;
+ }
+ ColumnVector output (S.dims ().numel (), false);
+
+ for (octave_idx_type i = 0; i < S.length (); i++)
+ {
+ if (S(i).is_string ())
+ {
+ bool error;
+ output(i) = base2dec_str_str_op (S(i).string_value (), mapstr, &error);
+ if (error)
+ output(i) = NAN;
+ }
+ else
+ {
+ error ("base2dec: cell %d is not a string", i+1);
+ return -1;
+ }
+ }
+
+ return output;
+}
+
+static octave_value
+do_base2dec_fun (const octave_value& S, const octave_value& BASE)
+
+{
+ octave_value retval;
+
+ bool S_string = S.is_string ();
+ bool S_cell = S.is_cell ();
+ bool BASE_string = BASE.is_string ();
+ bool BASE_scalar = BASE.is_real_scalar ();
+
+ if (BASE_scalar)
+ {
+ if (BASE.double_value () < 2)
+ {
+ error ("base2dec: base must be greater than 1");
+ return false;
+ }
+ if (BASE.double_value () > 36)
+ {
+ error("base2dec: largest base via number is 36, symbol string allows higher base");
+ return false;
+ }
+ }
+
+ if (S_string && BASE_scalar)
+ retval = base2dec_matrix_dbl_op (S.char_matrix_value (), BASE.double_value ());
+ else if (S_string && BASE_string)
+ retval = base2dec_matrix_str_op (S.char_matrix_value (), BASE.char_matrix_value ());
+ else if (S_cell && BASE_scalar)
+ retval = base2dec_cell_dbl_op (S.cell_value (), BASE.double_value ());
+ else if (S_cell && BASE_string)
+ retval = base2dec_cell_str_op (S.cell_value (), BASE.char_matrix_value ());
+ else
+ {
+ error ("base2dec: incorrect input arguments");
+ retval = false;
+ }
+
+ return retval;
+}
+
+DEFUN (base2dec, args, ,
+ "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} base2dec (@var{S}, @var{BASE})\n\
+Convert S from a string of digits in base BASE to a decimal\n\
+integer (base 10).\n\
+\n\
+@example\n\
+@group\n\
+base2dec (\"11120\", 3)\n\
+ @result{} 123\n\
+@end group\n\
+@end example\n\
+\n\
+If S is a string matrix, return a column vector with one value per\n\
+row of S. If a row contains invalid symbols then the\n\
+corresponding value will be NaN.\n\
+\n\
+If S is a cell array of strings, return a column vector with one\n\
+value per cell element in S.\n\
+\n\
+If BASE is a string, the characters of BASE are used as the\n\
+symbols for the digits of S. Space (' ') may not be used as a\n\
+symbol.\n\
+\n\
+@example\n\
+@group\n\
+base2dec (\"yyyzx\", \"xyz\")\n\
+ @result{} 123\n\
+@end group\n\
+@end example\n\
+\n\
+@seealso{dec2base, bin2dec, hex2dec}\n\
+@end deftypefn")
+{
+ octave_value retval;
+
+ if (args.length () == 2)
+ retval = do_base2dec_fun (args(0), args(1));
+ else
+ print_usage ();
+
+ return retval;
+}
+
+/*
+%!assert (base2dec ("11120", 3), 123)
+%!assert (base2dec ("yyyzx", "xyz"), 123)
+%!assert (base2dec ("-1", 2), NaN)
+%!assert (base2dec ({"A1", "1A"}, 16), [161; 26])
+%!assert (base2dec (["0"; "1"], 2), [0; 1])
+
+%%Test input validation
+%!error base2dec ()
+%!error base2dec ("11120")
+%!error base2dec ("11120", 3, 4)
+%!error base2dec ("11120", "1231")
+%!error base2dec ("11120", "12 3")
+%!error base2dec ("11120", ones (2))
+%!error base2dec ("11120", 37)
+*/
+
+
+// Core conversion routine.
+template
+static std::string
+dec2base_uint_str_op (const T &D, const std::string& mapstr, const int& LEN)
+{
+ // Create a string padded with zeros
+ std::string S (LEN, '0');
+
+ unsigned int BASE = mapstr.length ();
+ T divisor = D;
+
+ for (int j = LEN-1; j >= 0; j--)
+ {
+ T quotient = divisor / BASE;
+ unsigned int remainder = divisor - quotient * BASE;
+
+ S[j] = mapstr[remainder];
+
+ divisor = quotient;
+ if (divisor == 0)
+ break;
+ }
+
+ if (divisor > 0)
+ warning("dec2base: base-10 number %lu translates wider than field width: '%s'", D, S.c_str ());
+
+ return S;
+}
+
+// Convert numeric base to a mapping string
+static std::string
+create_mapstring (const unsigned int& BASE)
+{
+ // Create a standard map string
+ std::string stdmap ("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ if (BASE > stdmap.length ())
+ {
+ error ("dec2base: the base %u is greater than allowed symbols, try symbol string", BASE);
+ return std::string ();
+ }
+ if (BASE < 2)
+ {
+ error ("base2dec: base must be greater than 1");
+ return std::string ();
+ }
+ return stdmap.substr (0, BASE);
+}
+
+octave_value
+dec2base_array_str_op (const octave_value& D, const charMatrix& BASE, int LEN)
+{
+ // Check validity of mapping string
+ std::string mapstr = check_valid_base_string (BASE.row_as_string (0));
+
+ const uint64NDArray& D_uint64 = D.uint64_array_value ();
+ const int64NDArray& D_int64 = D.int64_array_value ();
+ const Array& D_double = D.vector_value ();
+ long unsigned int D_max = 0;
+ for (int i=0; i < D_uint64.length (); i++)
+ {
+ // Check sign
+ if (static_cast (D_int64(i)) < 0)
+ {
+ error ("dec2base: element %d is negative", i+1);
+ return -1;
+ }
+ // Check fractional
+ double intpart;
+ if (modf (D_double(i), &intpart) != 0.0)
+ {
+ error ("dec2base: element %d is not integer", i+1);
+ return -1;
+ }
+ // Determine largest number
+ if (static_cast (D_uint64(i)) > D_max)
+ D_max = D_uint64(i);
+ }
+ // Determine width of largest number
+ long unsigned int D_div = D_max;
+ unsigned int BASE_len = BASE.length ();
+ int D_len = 0;
+ for (; D_div; ++D_len)
+ D_div /= BASE_len;
+
+ // Use maximum of max number width and user specified minimum length,
+ // and if no specified length there must be at least one character
+ // for case of zero
+ if (D_len > LEN)
+ LEN = D_len;
+ if (LEN == 0)
+ LEN = 1;
+
+ // Create output character matrix
+ dim_vector dim_output(D.numel (), LEN);
+ charMatrix output (dim_output, false);
+
+ // Use narrower division if possible
+ if (D_max <= UCHAR_MAX)
+ {
+ for (octave_idx_type i = 0; i < D.numel (); i++)
+ output.insert (dec2base_uint_str_op (static_cast (D_uint64(i)), mapstr, LEN).c_str (), i, 0);
+ }
+ else if (D_max <= USHRT_MAX)
+ {
+ for (octave_idx_type i = 0; i < D.numel (); i++)
+ output.insert (dec2base_uint_str_op (static_cast (D_uint64(i)), mapstr, LEN).c_str (), i, 0);
+ }
+ else if (D_max <= UINT_MAX)
+ {
+ for (octave_idx_type i = 0; i < D.numel (); i++)
+ output.insert (dec2base_uint_str_op (static_cast (D_uint64(i)), mapstr, LEN).c_str (), i, 0);
+ }
+ else
+ {
+ for (octave_idx_type i = 0; i < D.numel (); i++)
+ output.insert (dec2base_uint_str_op (D_uint64(i), mapstr, LEN).c_str (), i, 0);
+ }
+
+ return output;
+}
+
+octave_value
+dec2base_array_uint_op (const octave_value& D, const unsigned int& BASE, int LEN)
+{
+ std::string mapstr = create_mapstring (BASE);
+ if (mapstr.empty ())
+ return false;
+ else
+ return dec2base_array_str_op (D, mapstr, LEN);
+}
+
+octave_value
+dec2base_cell_str_op (const Cell& D, const charMatrix& BASE, int LEN)
+{
+ // Check validity of mapping string
+ std::string mapstr = check_valid_base_string (BASE.row_as_string (0));
+
+ long unsigned int D_max = 0;
+ for (octave_idx_type i = 0; i < D.length (); i++)
+ {
+ if (!D(i).is_numeric_type () || D(i).is_complex_type ())
+ {
+ error ("dec2base: cell %d is not non-complex numeric", i+1);
+ return -1;
+ }
+ // Check sign
+ if (static_cast (D(i).int64_scalar_value ()) < 0)
+ {
+ error ("dec2base: cell %d is negative", i+1);
+ return -1;
+ }
+ // Check fractional
+ double intpart;
+ if (modf (D(i).double_value (), &intpart) != 0.0)
+ {
+ error ("dec2base: cell %d is not integer", i+1);
+ return -1;
+ }
+ // Determine largest number
+ long unsigned int dval = D(i).uint64_scalar_value ();
+ if (dval > D_max)
+ D_max = dval;
+ }
+ // Determine width of largest number
+ long unsigned int D_div = D_max;
+ unsigned int BASE_len = BASE.length ();
+ int D_len = 0;
+ for (; D_div; ++D_len)
+ D_div /= BASE_len;
+
+ // Use maximum of max number width and user specified minimum length,
+ // and if no specified length there must be at least one character
+ // for case of zero
+ if (D_len > LEN)
+ LEN = D_len;
+ if (LEN == 0)
+ LEN = 1;
+
+ // Create output character matrix
+ dim_vector dim_output(D.numel (), LEN);
+ charMatrix output (dim_output, false);
+
+ // Use narrower division if possible
+ if (D_max <= UCHAR_MAX)
+ {
+ for (octave_idx_type i = 0; i < D.numel (); i++)
+ output.insert (dec2base_uint_str_op (static_cast (D(i).uint64_scalar_value ()), mapstr, LEN).c_str (), i, 0);
+ }
+ else if (D_max <= USHRT_MAX)
+ {
+ for (octave_idx_type i = 0; i < D.numel (); i++)
+ output.insert (dec2base_uint_str_op (static_cast (D(i).uint64_scalar_value ()), mapstr, LEN).c_str (), i, 0);
+ }
+ else if (D_max <= UINT_MAX)
+ {
+ for (octave_idx_type i = 0; i < D.numel (); i++)
+ output.insert (dec2base_uint_str_op (static_cast (D(i).uint64_scalar_value ()), mapstr, LEN).c_str (), i, 0);
+ }
+ else
+ {
+ for (octave_idx_type i = 0; i < D.numel (); i++)
+ output.insert (dec2base_uint_str_op (static_cast (D(i).uint64_scalar_value ()), mapstr, LEN).c_str (), i, 0);
+ }
+
+ return output;
+}
+
+octave_value
+dec2base_cell_uint_op (const Cell& D, const unsigned int& BASE, int LEN)
+{
+ std::string mapstr = create_mapstring (BASE);
+ if (mapstr.empty ())
+ return false;
+ else
+ return dec2base_cell_str_op (D, mapstr, LEN);
+}
+
+static octave_value
+do_dec2base_fun (const octave_value& D, const octave_value& BASE, const int LEN)
+
+{
+ octave_value retval;
+
+ bool D_numeric_notcomplex = D.is_numeric_type () && !D.is_complex_type ();
+ bool D_cell = D.is_cell ();
+ bool BASE_string = BASE.is_string ();
+ bool BASE_numeric_notcomplex = BASE.is_numeric_type () && !D.is_complex_type ();
+
+ if (D_numeric_notcomplex && BASE_string)
+ retval = dec2base_array_str_op (D, BASE.char_matrix_value (), LEN);
+ else if (D_numeric_notcomplex && BASE_numeric_notcomplex)
+ retval = dec2base_array_uint_op (D, BASE.uint_value (), LEN);
+ else if (D_cell && BASE_string)
+ retval = dec2base_cell_str_op (D.cell_value (), BASE.char_matrix_value (), LEN);
+ else if (D_cell && BASE_numeric_notcomplex)
+ retval = dec2base_cell_uint_op (D.cell_value (), BASE.uint_value (), LEN);
+ else
+ {
+ error ("dec2base: incorrect input arguments");
+ retval = false;
+ }
+
+ return retval;
+}
+
+DEFUN (dec2base, args, ,
+ "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} dec2base (@var{D}, @var{BASE})\n\
+@deftypefnx {Built-in Function} {} dec2base (@var{D}, @var{BASE}, @var{LEN})\n\
+Return a string of symbols in base BASE corresponding to the\n\
+non-negative integer D.\n\
+\n\
+@example\n\
+@group\n\
+dec2base (123, 3)\n\
+ @result{} \"11120\"\n\
+@end group\n\
+@end example\n\
+\n\
+If D is a matrix or cell array, return a string matrix with one\n\
+row per element in D, padded with leading zeros to the width of\n\
+the largest value.\n\
+\n\
+If BASE is a string then the characters of BASE are used as the\n\
+symbols for the digits of D. Space (' ') may not be used as a\n\
+symbol.\n\
+\n\
+@example\n\
+@group\n\
+dec2base (123, \"aei\")\n\
+ @result{} \"eeeia\"\n\
+@end group\n\
+@end example\n\
+\n\
+The optional third argument, LEN, specifies the minimum number of\n\
+digits in the result.\n\
+\n\
+@seealso{base2dec, dec2bin, dec2hex}\n\
+@end deftypefn")
+{
+ octave_value retval;
+
+ if (args.length () == 3)
+ retval = do_dec2base_fun (args(0), args(1), args(2).double_value ());
+ else if (args.length () == 2)
+ retval = do_dec2base_fun (args(0), args(1), 0);
+ else
+ print_usage ();
+
+ return retval;
+}
+
+/*
+%!test
+%! s0 = "";
+%! for n = 1:13
+%! for b = 2:16
+%! pp = dec2base (b^n+1, b);
+%! assert (dec2base (b^n, b), ['1',s0,'0']);
+%! assert (dec2base (b^n+1, b), ['1',s0,'1']);
+%! endfor
+%! s0 = [s0,'0'];
+%! endfor
+
+%!test
+%! digits = "0123456789ABCDEF";
+%! for n = 1:13
+%! for b = 2:16
+%! pm = dec2base (b^n-1, b);
+%! assert (length (pm), n);
+%! assert (all (pm == digits(b)));
+%! endfor
+%! endfor
+
+%!test
+%! for b = 2:16
+%! assert (dec2base (0, b), '0');
+%! endfor
+
+%!assert (dec2base (0, 2, 4), "0000")
+%!assert (dec2base (2^51-1, 2), ...
+%! "111111111111111111111111111111111111111111111111111")
+%!assert (dec2base (uint64 (2)^63-1, 16), "7FFFFFFFFFFFFFFF")
+%!assert (dec2base ([1, 2; 3, 4], 2, 3), ["001"; "011"; "010"; "100"])
+%!assert (dec2base ({1, 2; 3, 4}, 2, 3), ["001"; "011"; "010"; "100"])
+
+%%Test input validation
+%!error dec2base ()
+%!error dec2base (1)
+%!error dec2base (1, 2, 3, 4)
+%!error dec2base ("A")
+%!error dec2base (2i)
+%!error dec2base (-1)
+%!error dec2base (1.1)
+%!error dec2base (1, "ABA")
+%!error dec2base (1, "A B")
+%!error dec2base (1, ones (2))
+%!error dec2base (1, 1)
+%!error dec2base (1, 37)
+*/