diff scripts/strings/dec2hex.m @ 31848:1f3f7e874203

dec2base.m: Accept negative and fractional inputs (bug #63282) Previously only dec2bin and dec2hex accepted negative inputs but not dec2base, which led to inconsistency and repeated code. This changeset centralizes the negative input functionality in dec2base, and eliminates that code in the other functions. It also adds the ability to accept fractional inputs in dec2base. dec2base.m: Add new functionality to handle negative inputs and fractional inputs. Update BISTs. Add documentation. dec2bin.m: Remove code to handle negative inputs. Pass through to dec2base. Add code for padding the output to Matlab-compatible sizes. Update BISTs. Add documentation. dec2base.m: Remove a matrix indexing bug. Pass through to dec2bin. Update BISTs. Add documentation. NEWS.9.md: Add note about new functionality.
author Arun Giridhar <arungiridhar@gmail.com>
date Fri, 24 Feb 2023 12:45:21 -0500
parents 597f3ee61a48
children a098cc74d9a5
line wrap: on
line diff
--- a/scripts/strings/dec2hex.m	Fri Feb 24 09:36:30 2023 -0500
+++ b/scripts/strings/dec2hex.m	Fri Feb 24 12:45:21 2023 -0500
@@ -29,8 +29,8 @@
 ## Return a string representing the conversion of the integer @var{d} to a
 ## hexadecimal (base16) number.
 ##
-## If @var{d} is negative, return the hexadecimal equivalent of the two's
-## complement binary value of @var{d}.
+## If @var{d} is negative, return the hexadecimal complement of @var{d}.
+##
 ## If @var{d} is a matrix or cell array, return a string matrix with one row
 ## for each element in @var{d}, padded with leading zeros to the width of the
 ## largest value.
@@ -50,6 +50,11 @@
 ## @end group
 ## @end example
 ##
+## Programming tip: @code{dec2hex} discards any fractional part of the input.
+## If you need the fractional part to be converted too, call @code{dec2base}
+## with a non-zero number of decimal places.  You can also use @code{fix} or
+## @code{round} on fractional inputs to ensure predictable rounding behavior.
+##
 ## @seealso{hex2dec, dec2base, dec2bin}
 ## @end deftypefn
 
@@ -59,24 +64,40 @@
     print_usage ();
   endif
 
-  ## To avoid repeating a lot of code, including input validation, we call dec2bin.
+  if (iscell (d))
+    d = cell2mat (d);
+  endif
+  d = d(:);
+
+  neg = (d < 0);
+
   if (nargin == 2)
     d = dec2bin (d, len*4);
   else
     d = dec2bin (d);
   endif
 
-  ## Left-pad with zeros to make the number of columns divisible by 4
+  ## Left-pad to a multiple of 4 columns.
   n = mod (columns (d), 4);
   if (n > 0)
-    d = [repmat("0", rows(d), 4-n), d];
+    tmp = "01"(neg + 1);  # leftpad with "0" for positive, "1" for negative
+    d = [repmat(tmp(:), 1, 4 - n), d];
   endif
 
-  d -= "0"; # convert to numeric
+  d -= '0';  # convert to numeric
   d = d(:, 1:4:end) * 8 + d(:, 2:4:end) * 4 + d(:, 3:4:end) * 2 + d(:, 4:4:end);
-  ## Elements of d are now in the range 0 to 15
+  ## Elements of d are now in the range 0 to 15.
 
-  hstr = "0123456789ABCDEF"(d+1); # convert to char and return
+  ## Convert to char matrix and return.
+  ## We used to return this in a single line:
+  ##    hstr = ("0123456789ABCDEF")(d+1);
+  ## But there are edge cases governing the sizes of row and column vectors
+  ## that cause problems with output size, so we use a loop instead.
+  hstr = repmat (' ', size (d));
+  v = "0123456789ABCDEF";
+  for t = 0:15
+    hstr(d == t) = v(t + 1);
+  endfor
 
 endfunction
 
@@ -90,7 +111,7 @@
 ## Test negative inputs
 %!assert (dec2hex (-3), "FD")
 %!assert (dec2hex (-3, 1), "FD")
-%!assert (dec2hex (-3, 3), "0FD")
+%!assert (dec2hex (-3, 3), "FFD")
 %!assert (dec2hex (-2^7 - 1), "FF7F")
 %!assert (dec2hex (-2^15 - 1), "FFFF7FFF")
 %!assert (dec2hex (-2^31 - 1), "FFFFFFFF7FFFFFFF")
@@ -103,6 +124,12 @@
 %!assert (dec2hex ([1, 2; 3, -4]), ["01"; "03"; "02"; "FC"])
 %!assert (dec2hex ({1, 2; 3, -4}), ["01"; "03"; "02"; "FC"])
 
+## Test that the output is of the correct size.
+## Next line should return a column vector:
+%!assert (dec2hex (0:15), "0123456789ABCDEF"(:))
+## Next line should return a row vector:
+%!assert (dec2hex (uint64 (18364758544493064720)), "FEDCBA9876543210")
+
 ## Test input validation
 %!error <Invalid call> dec2hex ()