changeset 28242:f618edac2a29

dec2hex.m: Implement support for negative number inputs (bug #58147). * dec2hex.m: Update documentation to mention support for negative numbers. Copy algorithm from dec2bin.m, but replace final call to dec2base (d,2) with dec2base (d, 16). Add new BIST tests.
author Rik <rik@octave.org>
date Sat, 25 Apr 2020 14:31:09 -0700
parents ef7bc64a604b
children 7739d3eb952b
files scripts/strings/dec2hex.m
diffstat 1 files changed, 72 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/strings/dec2hex.m	Sat Apr 25 11:45:03 2020 -0700
+++ b/scripts/strings/dec2hex.m	Sat Apr 25 14:31:09 2020 -0700
@@ -24,36 +24,66 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn {} {} dec2hex (@var{d}, @var{len})
-## Return the hexadecimal string corresponding to the non-negative integer
-## @var{d}.
+## @deftypefn  {} {} dec2hex (@var{d})
+## @deftypefnx {} {} dec2hex (@var{d}, @var{len})
+## Return a string representing the conversion of the integer @var{d} to a
+## hexadecimal (base16) number.
 ##
-## For example:
+## If @var{d} is negative, return the two's complement binary value 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.
+##
+## The optional second argument, @var{len}, specifies the minimum number of
+## digits in the result.
+##
+## Examples:
 ##
 ## @example
 ## @group
 ## dec2hex (2748)
 ##      @result{} "ABC"
+##
+## dec2hex (-2)
+##      @result{} "FE"
 ## @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.
-##
-## The optional second argument, @var{len}, specifies the minimum number of
-## digits in the result.
 ## @seealso{hex2dec, dec2base, dec2bin}
 ## @end deftypefn
 
 function h = dec2hex (d, len)
 
+  if (nargin == 0 || nargin > 2)
+    print_usage ();
+  endif
+
+  if (iscell (d))
+    d = cell2mat (d);
+  endif
+  ## Create column vector for algorithm (output is always col. vector anyways)
+  d = d(:);
+  
+  lt_zero_idx = (d < 0);
+  if (any (lt_zero_idx))
+    ## FIXME: Need an algorithm that works with larger values such as int64.
+    if (any (d(lt_zero_idx) < -2^52))
+      error ("dec2hex: negative inputs cannot be less than -flintmax () / 2");
+    elseif (any (d(lt_zero_idx) < intmin ("int32")))
+      d(lt_zero_idx) += flintmax ();
+    elseif (any (d < intmin ("int16")))
+      d(lt_zero_idx) += double (intmax ("uint32")) + 1;
+    elseif (any (d < intmin ("int8")))
+      d(lt_zero_idx) += double (intmax ("uint16"))+ 1;
+    else
+      d(lt_zero_idx) += double (intmax ("uint8")) + 1;
+    endif
+  endif
+
   if (nargin == 1)
     h = dec2base (d, 16);
-  elseif (nargin == 2)
+  else
     h = dec2base (d, 16, len);
-  else
-    print_usage ();
   endif
 
 endfunction
@@ -61,8 +91,37 @@
 
 %!assert (dec2hex (2748), "ABC")
 %!assert (dec2hex (2748, 5), "00ABC")
+%!assert (dec2hex ([2748, 2746]), ["ABC"; "ABA"])
 %!assert (dec2hex ({2748, 2746}), ["ABC"; "ABA"])
+%!assert (dec2hex ({2748, 2746}, 4), ["0ABC"; "0ABA"])
+
+## Test negative inputs
+%!assert (dec2hex (-3), "FD")
+%!assert (dec2hex (-3, 1), "FD")
+%!assert (dec2hex (-3, 3), "0FD")
+%!assert (dec2hex (-2^7 -1), "FF7F")
+%!assert (dec2hex (-2^15 -1), "FFFF7FFF")
+## FIXME: Matlab returns longer string that begins with 'F'
+%!assert (dec2hex (-2^31 -1), "1FFFFF7FFFFFFF")
+## FIXME: Matlab returns longer string that begins with 'FFF'
+%!assert (dec2hex (-2^52), "10000000000000")
+## FIXME: Uncomment when support for int64 is added
+%!#assert (dec2hex (-2^63),
+%!        "1000000000000000000000000000000000000000000000000000000000000000")
+%!#test
+%! assert (dec2hex (int64 (-2^63)),
+%!        "1000000000000000000000000000000000000000000000000000000000000000");
+%!#test
+%! assert (dec2hex (int64 (-2^63) -1),
+%!        "1000000000000000000000000000000000000000000000000000000000000000");
+%!#test
+%! assert (dec2hex (int64 (-2^63) +1),
+%!        "1000000000000000000000000000000000000000000000000000000000000001");
+%!assert (dec2hex ([-1, -2; -3, -4]), ["FF"; "FD"; "FE"; "FC"])
+%!assert (dec2hex ([1, 2; 3, -4]), ["01"; "03"; "02"; "FC"])
+%!assert (dec2hex ({1, 2; 3, -4}), ["01"; "03"; "02"; "FC"])
 
 ## Test input validation
 %!error dec2hex ()
 %!error dec2hex (1, 2, 3)
+%!error <negative inputs cannot be less than> dec2hex (- flintmax ())