Mercurial > octave
comparison 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 |
comparison
equal
deleted
inserted
replaced
28236:5bb1c0cbb27e | 28237:ac3a078e688f |
---|---|
22 ## <https://www.gnu.org/licenses/>. | 22 ## <https://www.gnu.org/licenses/>. |
23 ## | 23 ## |
24 ######################################################################## | 24 ######################################################################## |
25 | 25 |
26 ## -*- texinfo -*- | 26 ## -*- texinfo -*- |
27 ## @deftypefn {} {} dec2bin (@var{d}, @var{len}) | 27 ## @deftypefn {} {} dec2bin (@var{d}) |
28 ## Return a binary number corresponding to the integer @var{d} as a string of | 28 ## @deftypefnx {} {} dec2bin (@var{d}, @var{len}) |
29 ## ones and zeros. If @var{d} is negative, return the two's complement binary | 29 ## Return a string of ones and zeros representing the conversion of the integer |
30 ## value of @var{d}. | 30 ## @var{d} to a binary number. |
31 ## | 31 ## |
32 ## For example: | 32 ## If @var{d} is negative, return the two's complement binary value of @var{d}. |
33 ## If @var{d} is a matrix or cell array, return a string matrix with one row | |
34 ## for each element in @var{d}, padded with leading zeros to the width of the | |
35 ## largest value. | |
36 ## | |
37 ## The optional second argument, @var{len}, specifies the minimum number of | |
38 ## digits in the result. | |
39 ## | |
40 ## Examples: | |
33 ## | 41 ## |
34 ## @example | 42 ## @example |
35 ## @group | 43 ## @group |
36 ## dec2bin (14) | 44 ## dec2bin (14) |
37 ## @result{} "1110" | 45 ## @result{} "1110" |
39 ## dec2bin (-14) | 47 ## dec2bin (-14) |
40 ## @result{} "11110010" | 48 ## @result{} "11110010" |
41 ## @end group | 49 ## @end group |
42 ## @end example | 50 ## @end example |
43 ## | 51 ## |
44 ## If @var{d} is a matrix or cell array, return a string matrix with one row | |
45 ## per element in @var{d}, padded with leading zeros to the width of the | |
46 ## largest value. | |
47 ## | |
48 ## The optional second argument, @var{len}, specifies the minimum number of | |
49 ## digits in the result. | |
50 ## | |
51 ## @seealso{bin2dec, dec2base, dec2hex} | 52 ## @seealso{bin2dec, dec2base, dec2hex} |
52 ## @end deftypefn | 53 ## @end deftypefn |
53 | 54 |
54 function b = dec2bin (d, len) | 55 function b = dec2bin (d, len) |
55 | 56 |
56 ## dec2base does cell->mat conversion, this allows easier content comparison | 57 if (nargin == 0 || nargin > 2) |
57 if (iscell (d)) | 58 print_usage (); |
58 d = cell2mat (d); | 59 endif |
59 endif | |
60 | 60 |
61 d = d(:); ## output is always a column vector, (:) simplifies value checks | 61 if (iscell (d)) |
62 | 62 d = cell2mat (d); |
63 if (any (d < intmin ("int64"))) | |
64 error ("dec2bin: negative inputs cannot be less than intmin('int64')"); | |
65 endif | |
66 | |
67 if (any (d < 0)) | |
68 if (any (d < intmin ("int64"))) | |
69 error ("out of range"); | |
70 elseif (any (d < intmin ("int32"))) | |
71 d(d < 0) += double (intmax ("uint64")) + 1 ; | |
72 elseif (any (d < intmin ("int16"))) | |
73 d(d < 0) += double (intmax ("uint32")) + 1; | |
74 elseif (any (d < intmin ("int8"))) | |
75 d(d < 0) += double (intmax ("uint16"))+ 1; | |
76 else | |
77 d(d < 0) += double (intmax ("uint8")) +1; | |
78 endif | 63 endif |
79 endif | 64 ## Create column vector for algorithm (output is always col. vector anyways) |
65 d = d(:); | |
66 | |
67 lt_zero_idx = (d < 0); | |
68 if (any (lt_zero_idx)) | |
69 if (any (d(lt_zero_idx) < intmin ("int64"))) | |
70 error ('dec2bin: negative inputs cannot be less than intmin ("int64")'); | |
71 elseif (any (d(lt_zero_idx) < intmin ("int32"))) | |
72 d(lt_zero_idx) += double (intmax ("uint64")) + 1; | |
73 elseif (any (d < intmin ("int16"))) | |
74 d(lt_zero_idx) += double (intmax ("uint32")) + 1; | |
75 elseif (any (d < intmin ("int8"))) | |
76 d(lt_zero_idx) += double (intmax ("uint16"))+ 1; | |
77 else | |
78 d(lt_zero_idx) += double (intmax ("uint8")) + 1; | |
79 endif | |
80 endif | |
80 | 81 |
81 if (nargin == 1) | 82 if (nargin == 1) |
82 b = dec2base (d, 2); | 83 b = dec2base (d, 2); |
83 elseif (nargin == 2) | 84 else |
84 b = dec2base (d, 2, len); | 85 b = dec2base (d, 2, len); |
85 else | |
86 print_usage (); | |
87 endif | 86 endif |
88 | 87 |
89 endfunction | 88 endfunction |
90 | 89 |
91 | 90 |
98 | 97 |
99 ## Test negative inputs | 98 ## Test negative inputs |
100 %!assert (dec2bin (-3), "11111101") | 99 %!assert (dec2bin (-3), "11111101") |
101 %!assert (dec2bin (-3, 3), "11111101") | 100 %!assert (dec2bin (-3, 3), "11111101") |
102 %!assert (dec2bin (-3, 9), "011111101") | 101 %!assert (dec2bin (-3, 9), "011111101") |
103 %!assert (dec2bin (-129), "1111111101111111") | 102 %!assert (dec2bin (-2^7 -1), "1111111101111111") |
104 %!assert (dec2bin (-2^15 -1), "11111111111111110111111111111111") | 103 %!assert (dec2bin (-2^15 -1), "11111111111111110111111111111111") |
105 %!assert (dec2bin (-2^31 -1), "1111111111111111111111111111111101111111111111111111111111111111") | 104 ## The expected value is correct, but not what Octave generates because |
106 %!assert (dec2bin (-2^63), "1000000000000000000000000000000000000000000000000000000000000000") | 105 ## floating point integer precision is 2^53. Matlab gets this right. |
107 %!assert (dec2bin (-2^63-1), "1000000000000000000000000000000000000000000000000000000000000000") | 106 %!xtest |
108 %!assert (dec2bin ([-1, -2; -3, -4]), ["11111111"; "11111101"; "11111110"; "11111100"]) | 107 %! assert (dec2bin (-2^31 -1), |
109 %!assert (dec2bin ([1, 2; 3, -4]), ["00000001"; "00000011"; "00000010"; "11111100"]) | 108 %! "1111111111111111111111111111111101111111111111111111111111111111"); |
110 %!assert (dec2bin ({1, 2; 3, -4}), ["00000001"; "00000011"; "00000010"; "11111100"]) | 109 %!assert (dec2bin (-2^63), |
110 %! "1000000000000000000000000000000000000000000000000000000000000000") | |
111 ## These tests also don't work because of floating point precision. | |
112 %!xtest | |
113 %! assert (dec2bin (int64 (-2^63)), | |
114 %! "1000000000000000000000000000000000000000000000000000000000000000"); | |
115 %!xtest | |
116 %! assert (dec2bin (int64 (-2^63) -1), | |
117 %! "1000000000000000000000000000000000000000000000000000000000000000"); | |
118 %!xtest | |
119 %! assert (dec2bin (int64 (-2^63) +1), | |
120 %! "1000000000000000000000000000000000000000000000000000000000000001"); | |
121 %!assert (dec2bin ([-1, -2; -3, -4]), | |
122 %! ["11111111"; "11111101"; "11111110"; "11111100"]) | |
123 %!assert (dec2bin ([1, 2; 3, -4]), | |
124 %! ["00000001"; "00000011"; "00000010"; "11111100"]) | |
125 %!assert (dec2bin ({1, 2; 3, -4}), | |
126 %! ["00000001"; "00000011"; "00000010"; "11111100"]) | |
111 | 127 |
112 ## Test input validation | 128 ## Test input validation |
113 %!error dec2bin () | 129 %!error dec2bin () |
114 %!error dec2bin (1, 2, 3) | 130 %!error dec2bin (1, 2, 3) |
115 %!error dec2bin (2 * double (intmin ("int64"))) | 131 %!error <negative inputs> dec2bin (2 * double (intmin ("int64"))) |