Mercurial > octave
diff scripts/strings/dec2bin.m @ 28237:ac3a078e688f
dec2bin.m: Reduce number of times search for negative numbers is done (bug #58147).
* dec2bin.m: Calculate "lt_zero_idx" which is index of any values in the input
less than zero just once. Use lt_zero_idx in all further indexing.
Add 4 %!xtest for input values which should work, but don't.
author | Rik <rik@octave.org> |
---|---|
date | Wed, 22 Apr 2020 17:04:55 -0700 |
parents | 5bb1c0cbb27e |
children | ef7bc64a604b |
line wrap: on
line diff
--- a/scripts/strings/dec2bin.m Wed Apr 22 15:53:51 2020 -0700 +++ b/scripts/strings/dec2bin.m Wed Apr 22 17:04:55 2020 -0700 @@ -24,12 +24,20 @@ ######################################################################## ## -*- texinfo -*- -## @deftypefn {} {} dec2bin (@var{d}, @var{len}) -## Return a binary number corresponding to the integer @var{d} as a string of -## ones and zeros. If @var{d} is negative, return the two's complement binary -## value of @var{d}. +## @deftypefn {} {} dec2bin (@var{d}) +## @deftypefnx {} {} dec2bin (@var{d}, @var{len}) +## Return a string of ones and zeros representing the conversion of the integer +## @var{d} to a binary 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 @@ -41,49 +49,40 @@ ## @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{bin2dec, dec2base, dec2hex} ## @end deftypefn function b = dec2bin (d, len) -## dec2base does cell->mat conversion, this allows easier content comparison -if (iscell (d)) - d = cell2mat (d); -endif - -d = d(:); ## output is always a column vector, (:) simplifies value checks - -if (any (d < intmin ("int64"))) - error ("dec2bin: negative inputs cannot be less than intmin('int64')"); -endif + if (nargin == 0 || nargin > 2) + print_usage (); + endif -if (any (d < 0)) - if (any (d < intmin ("int64"))) - error ("out of range"); - elseif (any (d < intmin ("int32"))) - d(d < 0) += double (intmax ("uint64")) + 1 ; - elseif (any (d < intmin ("int16"))) - d(d < 0) += double (intmax ("uint32")) + 1; - elseif (any (d < intmin ("int8"))) - d(d < 0) += double (intmax ("uint16"))+ 1; - else - d(d < 0) += double (intmax ("uint8")) +1; + if (iscell (d)) + d = cell2mat (d); endif -endif + ## Create column vector for algorithm (output is always col. vector anyways) + d = d(:); + + lt_zero_idx = (d < 0); + if (any (lt_zero_idx)) + if (any (d(lt_zero_idx) < intmin ("int64"))) + error ('dec2bin: negative inputs cannot be less than intmin ("int64")'); + elseif (any (d(lt_zero_idx) < intmin ("int32"))) + d(lt_zero_idx) += double (intmax ("uint64")) + 1; + 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) b = dec2base (d, 2); - elseif (nargin == 2) + else b = dec2base (d, 2, len); - else - print_usage (); endif endfunction @@ -100,16 +99,33 @@ %!assert (dec2bin (-3), "11111101") %!assert (dec2bin (-3, 3), "11111101") %!assert (dec2bin (-3, 9), "011111101") -%!assert (dec2bin (-129), "1111111101111111") +%!assert (dec2bin (-2^7 -1), "1111111101111111") %!assert (dec2bin (-2^15 -1), "11111111111111110111111111111111") -%!assert (dec2bin (-2^31 -1), "1111111111111111111111111111111101111111111111111111111111111111") -%!assert (dec2bin (-2^63), "1000000000000000000000000000000000000000000000000000000000000000") -%!assert (dec2bin (-2^63-1), "1000000000000000000000000000000000000000000000000000000000000000") -%!assert (dec2bin ([-1, -2; -3, -4]), ["11111111"; "11111101"; "11111110"; "11111100"]) -%!assert (dec2bin ([1, 2; 3, -4]), ["00000001"; "00000011"; "00000010"; "11111100"]) -%!assert (dec2bin ({1, 2; 3, -4}), ["00000001"; "00000011"; "00000010"; "11111100"]) +## The expected value is correct, but not what Octave generates because +## floating point integer precision is 2^53. Matlab gets this right. +%!xtest +%! assert (dec2bin (-2^31 -1), +%! "1111111111111111111111111111111101111111111111111111111111111111"); +%!assert (dec2bin (-2^63), +%! "1000000000000000000000000000000000000000000000000000000000000000") +## These tests also don't work because of floating point precision. +%!xtest +%! assert (dec2bin (int64 (-2^63)), +%! "1000000000000000000000000000000000000000000000000000000000000000"); +%!xtest +%! assert (dec2bin (int64 (-2^63) -1), +%! "1000000000000000000000000000000000000000000000000000000000000000"); +%!xtest +%! assert (dec2bin (int64 (-2^63) +1), +%! "1000000000000000000000000000000000000000000000000000000000000001"); +%!assert (dec2bin ([-1, -2; -3, -4]), +%! ["11111111"; "11111101"; "11111110"; "11111100"]) +%!assert (dec2bin ([1, 2; 3, -4]), +%! ["00000001"; "00000011"; "00000010"; "11111100"]) +%!assert (dec2bin ({1, 2; 3, -4}), +%! ["00000001"; "00000011"; "00000010"; "11111100"]) ## Test input validation %!error dec2bin () %!error dec2bin (1, 2, 3) -%!error dec2bin (2 * double (intmin ("int64"))) +%!error <negative inputs> dec2bin (2 * double (intmin ("int64")))