Mercurial > octave
comparison scripts/strings/dec2bin.m @ 31239:dd6b37f67db2
Accept negative inputs to -2^63 for dec2bin and dec2hex (bug #63089)
dec2bin.m: Accept negative inputs lower than -flintmax down to -2^63
Return 64-bit string in certain cases for Matlab compatibility
Activate BISTs commented out earlier
dec2hex.m: Remove repeated code and call dec2bin instead
Accept negative inputs lower than -flintmax down to -2^63
Update and activate BISTs commented out earlier
author | Arun Giridhar <arungiridhar@gmail.com> |
---|---|
date | Sun, 25 Sep 2022 06:22:25 -0400 |
parents | 5d3faba0342e |
children | 7018819318d1 |
comparison
equal
deleted
inserted
replaced
31238:67cad4e8f866 | 31239:dd6b37f67db2 |
---|---|
27 ## @deftypefn {} {@var{bstr} =} dec2bin (@var{d}) | 27 ## @deftypefn {} {@var{bstr} =} dec2bin (@var{d}) |
28 ## @deftypefnx {} {@var{bstr} =} dec2bin (@var{d}, @var{len}) | 28 ## @deftypefnx {} {@var{bstr} =} dec2bin (@var{d}, @var{len}) |
29 ## Return a string of ones and zeros representing the conversion of the integer | 29 ## Return a string of ones and zeros representing the conversion of the integer |
30 ## @var{d} to a binary number. | 30 ## @var{d} to a binary number. |
31 ## | 31 ## |
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 | 32 ## 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 | 33 ## for each element in @var{d}, padded with leading zeros to the width of the |
35 ## largest value. | 34 ## largest value. |
36 ## | 35 ## |
37 ## The optional second argument, @var{len}, specifies the minimum number of | 36 ## The optional second argument, @var{len}, specifies the minimum number of |
38 ## digits in the result. | 37 ## digits in the result. |
38 ## | |
39 ## For negative elements of @var{d}, return the binary value of the two's | |
40 ## complement. The result is padded with leading ones to 8, 16, 32, or 64 | |
41 ## bits as appropriate for the magnitude of the input. Positive input | |
42 ## elements are padded with leading zeros to the same width. If the second | |
43 ## argument @var{len} exceeds that calculated width, the result is further | |
44 ## padded with leading zeros, for compatibility with @sc{matlab}. | |
39 ## | 45 ## |
40 ## Examples: | 46 ## Examples: |
41 ## | 47 ## |
42 ## @example | 48 ## @example |
43 ## @group | 49 ## @group |
46 ## | 52 ## |
47 ## dec2bin (-14) | 53 ## dec2bin (-14) |
48 ## @result{} "11110010" | 54 ## @result{} "11110010" |
49 ## @end group | 55 ## @end group |
50 ## @end example | 56 ## @end example |
51 ## | |
52 ## Programming Notes: The largest negative value that can be converted into | |
53 ## two's complement is @code{- (flintmax () / 2)}. | |
54 ## | 57 ## |
55 ## Known @sc{matlab} Incompatibility: @sc{matlab}'s @code{dec2bin} allows | 58 ## Known @sc{matlab} Incompatibility: @sc{matlab}'s @code{dec2bin} allows |
56 ## non-integer values for @var{d}, truncating the value using the equivalent | 59 ## non-integer values for @var{d}, truncating the value using the equivalent |
57 ## of @code{fix (@var{d})} for positive values, but, as of R2020b and in | 60 ## of @code{fix (@var{d})} for positive values, but, as of R2020b and in |
58 ## conflict with published documentation, appears to use | 61 ## conflict with published documentation, appears to use |
73 d = cell2mat (d); | 76 d = cell2mat (d); |
74 endif | 77 endif |
75 ## Create column vector for algorithm (output is always col. vector anyways) | 78 ## Create column vector for algorithm (output is always col. vector anyways) |
76 d = d(:); | 79 d = d(:); |
77 | 80 |
78 lt_zero_idx = (d < 0); | 81 neg = (d < 0); # keep track of which elements are negative |
79 if (any (lt_zero_idx)) | 82 if (any (neg)) # must be a signed type |
80 ## FIXME: Need an algorithm that works with larger values such as int64. | 83 ## Cast to a suitable signed integer type, then to unsigned. |
81 if (any (d(lt_zero_idx) < -2^52)) | 84 ## Ensure that the left-most bit of the unsigned number is 1, |
82 error ("dec2bin: negative inputs cannot be less than -flintmax () / 2"); | 85 ## to signify negative input. |
83 elseif (any (d(lt_zero_idx) < intmin ("int32"))) | 86 tmp = int64 (d); |
84 d(lt_zero_idx) += flintmax (); | 87 if (all (tmp >= -128 & tmp <= 127)) |
85 elseif (any (d < intmin ("int16"))) | 88 d = int8 (d); |
86 d(lt_zero_idx) += double (intmax ("uint32")) + 1; | 89 d(neg) = (d(neg) + intmax (d)) + 1; |
87 elseif (any (d < intmin ("int8"))) | 90 d = uint8 (d); |
88 d(lt_zero_idx) += double (intmax ("uint16"))+ 1; | 91 d(neg) += uint8 (128); |
92 elseif (all (tmp >= -32768 & tmp <= 32767)) | |
93 d = int16 (d); | |
94 d(neg) = (d(neg) + intmax (d)) + 1; | |
95 d = uint16 (d); | |
96 d(neg) += uint16 (32768); | |
97 elseif (all (tmp >= -2147483648 & tmp <= 2147483647)) | |
98 d = int32 (d); | |
99 d(neg) = (d(neg) + intmax (d)) + 1; | |
100 d = uint32 (d); | |
101 d(neg) += uint32 (2147483648); | |
89 else | 102 else |
90 d(lt_zero_idx) += double (intmax ("uint8")) + 1; | 103 d = int64 (d); |
104 d(neg) = (d(neg) + intmax (d)) + 1; | |
105 d = uint64 (d); | |
106 d(neg) += uint64 (9223372036854775808); | |
91 endif | 107 endif |
92 endif | 108 endif |
93 | 109 |
94 if (nargin == 1) | 110 if (nargin == 1) |
95 bstr = dec2base (d, 2); | 111 bstr = dec2base (d, 2); |
109 | 125 |
110 ## Test negative inputs | 126 ## Test negative inputs |
111 %!assert (dec2bin (-3), "11111101") | 127 %!assert (dec2bin (-3), "11111101") |
112 %!assert (dec2bin (-3, 3), "11111101") | 128 %!assert (dec2bin (-3, 3), "11111101") |
113 %!assert (dec2bin (-3, 9), "011111101") | 129 %!assert (dec2bin (-3, 9), "011111101") |
114 %!assert (dec2bin (-2^7 -1), "1111111101111111") | 130 %!assert (dec2bin (-2^7 - 1), "1111111101111111") |
115 %!assert (dec2bin (-2^15 -1), "11111111111111110111111111111111") | 131 %!assert (dec2bin (-2^15 - 1), "11111111111111110111111111111111") |
116 ## FIXME: Matlab generates a string that is 64 characters long | 132 %!assert (dec2bin (-2^31 - 1), |
117 %!assert (dec2bin (-2^31 -1), | 133 %! "1111111111111111111111111111111101111111111111111111111111111111") |
118 %! "11111111111111111111101111111111111111111111111111111") | |
119 %!assert (dec2bin (-2^52), | 134 %!assert (dec2bin (-2^52), |
120 %! "10000000000000000000000000000000000000000000000000000") | 135 %! "1111111111110000000000000000000000000000000000000000000000000000") |
121 ## FIXME: Uncomment when support for int64 is added | 136 %!assert (dec2bin (-2^63), |
122 %!#assert (dec2bin (-2^63), | |
123 %! "1000000000000000000000000000000000000000000000000000000000000000") | 137 %! "1000000000000000000000000000000000000000000000000000000000000000") |
124 %!#test | 138 %!assert (dec2bin (int64 (-2) ^ 63), |
125 %! assert (dec2bin (int64 (-2^63)), | 139 %! "1000000000000000000000000000000000000000000000000000000000000000") |
126 %! "1000000000000000000000000000000000000000000000000000000000000000"); | 140 %!assert (dec2bin (int64 (-2) ^ 63 - 1), |
127 %!#test | 141 %! "1000000000000000000000000000000000000000000000000000000000000000") |
128 %! assert (dec2bin (int64 (-2^63) -1), | 142 %!assert (dec2bin (int64 (-2) ^ 63 + 1), |
129 %! "1000000000000000000000000000000000000000000000000000000000000000"); | 143 %! "1000000000000000000000000000000000000000000000000000000000000001") |
130 %!#test | |
131 %! assert (dec2bin (int64 (-2^63) +1), | |
132 %! "1000000000000000000000000000000000000000000000000000000000000001"); | |
133 %!assert (dec2bin ([-1, -2; -3, -4]), | 144 %!assert (dec2bin ([-1, -2; -3, -4]), |
134 %! ["11111111"; "11111101"; "11111110"; "11111100"]) | 145 %! ["11111111"; "11111101"; "11111110"; "11111100"]) |
135 %!assert (dec2bin ([1, 2; 3, -4]), | 146 %!assert (dec2bin ([1, 2; 3, -4]), |
136 %! ["00000001"; "00000011"; "00000010"; "11111100"]) | 147 %! ["00000001"; "00000011"; "00000010"; "11111100"]) |
137 %!assert (dec2bin ({1, 2; 3, -4}), | 148 %!assert (dec2bin ({1, 2; 3, -4}), |
138 %! ["00000001"; "00000011"; "00000010"; "11111100"]) | 149 %! ["00000001"; "00000011"; "00000010"; "11111100"]) |
139 | 150 |
140 ## Test input validation | 151 ## Test input validation |
141 %!error <Invalid call> dec2bin () | 152 %!error <Invalid call> dec2bin () |
142 %!error <negative inputs cannot be less than> dec2bin (- flintmax ()) | 153 |