* bug 15070 fixed: bitset() failed for bit pos as encoded integer
[scilab.git] / scilab / modules / elementary_functions / macros / bitset.sci
1 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
2 // Copyright (C) 2008 - INRIA - Pierre MARECHAL
3 //
4 // Copyright (C) 2012 - 2016 - Scilab Enterprises
5 //
6 // This file is hereby licensed under the terms of the GNU GPL v2.0,
7 // pursuant to article 5.3.4 of the CeCILL v.2.1.
8 // This file was originally licensed under the terms of the CeCILL v2.1,
9 // and continues to be available under such terms.
10 // For more information, see the COPYING file which you should have received
11 // along with this program.
12
13 function y = bitset(x,pos,v)
14
15     // INRIA 2008 - Pierre MARECHAL
16     //
17     // BITSET function
18     // Set bit at specified position
19
20     // Check input arguments
21     // =========================================================================
22
23     // check number input argument
24
25     rhs = argn(2);
26
27     if rhs < 2 then
28         msg = _("%s: Wrong number of input argument(s): At least %d expected.\n")
29         error(msprintf(msg, "bitset", 2));
30     end
31
32     // case empty matrix
33     if isempty(x)
34         if ~isempty(pos) & prod(size(pos))<>1
35             msg = _("%s: Wrong size for input arguments: Same sizes expected.\n")
36             error(msprintf(msg, "bitset"));
37         else
38             y=[]
39             return
40         end
41     end
42
43     // check v value
44     if rhs == 3 & or(v <> 0 & v <> 1) then
45         msg = _("%s: Wrong value for input argument #%d: 0 or 1 expected.\n")
46         error(msprintf(msg, "bitset",3));
47     elseif rhs == 2 then
48         v = ones(x);
49     end
50
51     // check size
52     if or(size(x) <> size(pos)) | or(size(v) <> size(x)) then
53         msg = _("%s: Wrong size for input arguments: Same sizes expected.\n")
54         error(msprintf(msg, "bitset"));
55     end
56
57     // check type
58     if (type(x) == 1  & (or(x-floor(x) <> 0) | or(x < 0))) ..
59         | (type(x) == 8  & (inttype(x) < 10)) ..
60         | (typeof(x) == "hypermat" & (or(x-floor(x) <> 0) | or(x < 0))) ..
61         | (type(x) <> 1 & type(x) <> 8 & typeof(x) <> "hypermat") then
62         msg = _("%s: Wrong type for input argument #%d: Scalar/matrix/hypermatrix of unsigned integers expected.\n")
63         error(msprintf(msg, "bitset",1));
64     end
65
66     if (type(pos) == 1  & (or(pos-floor(pos) <> 0) | or(pos < 0))) ..
67         | (type(pos) == 8  & (inttype(pos) < 10)) ..
68         | (typeof(pos) == "hypermat" & (or(pos-floor(pos) <> 0) | or(pos < 0))) ..
69         | (type(pos) <> 1 & type(pos) <> 8 & typeof(pos) <> "hypermat") then
70         msg = _("%s: Wrong type for input argument #%d: Scalar/matrix/hypermatrix of unsigned integers expected.\n")
71         error(msprintf(msg, "bitset",2));
72     end
73
74     // check pos value
75     select inttype(x(1))
76     case 0  then posmax = 52;
77     case 11 then posmax = 8;
78     case 12 then posmax = 16;
79     case 14 then posmax = 32;
80     end
81
82     if or(pos > posmax) | or(pos < 1) then
83         msg = _("%s: Wrong value for input argument #%d: Must be between %d and %d.\n")
84         error(msprintf(msg, "bitset", 2, 1, posmax));
85     end
86
87     // Algorithm
88     // =========================================================================
89
90     if size(pos,"*") == 1;
91         pos  = ones(x)*pos;
92     end
93
94     if size(x,"*") == 1;
95         x    = ones(pos)*x;
96     end
97
98     vZero = find(v == 0);
99     vOne = find(v == 1);
100     sz = size(x);
101
102     if type(x(1)) == 8 then
103
104         select inttype(x(1))
105         case 11 then mask = 2^uint8((pos(:)-1));
106         case 12 then mask = 2^uint16((pos(:)-1));
107         case 14 then mask = 2^uint32((pos(:)-1));
108         end
109         mask = matrix(mask, sz);
110         y(vZero) = x(vZero) & (~mask(vZero));
111         y(vOne) = x(vOne) | mask(vOne);
112         y = matrix(y, sz);
113
114         return;
115
116     else
117         // type == 1
118         a     = 2^32;
119         mask  = uint32(zeros(pos));
120
121         y_MSB  = uint32(zeros(pos));
122         y_LSB  = uint32(zeros(pos));
123
124         y_LSB = uint32( x - double(uint32(x/a)) * a ); // LSB Less Significant Bits
125         y_MSB = uint32( x/a );                         // MSB Most Significant Bits
126         yMSB  = y_MSB;
127         yLSB  = y_LSB;
128
129         if or(pos<=32) then
130             mask(pos<=32) = uint32(2^(pos(pos<=32) -1));
131             yLSB = y_LSB(pos<=32);
132             ymask = mask(pos<=32);
133             // v == 0
134             yLSB(vZero) = yLSB(vZero) & (~ymask(vZero));
135             // v == 1
136             yLSB(vOne) = yLSB(vOne) | ymask(vOne);
137             yLSB = matrix(yLSB, sz);
138         end
139
140         if or(pos>32) then
141             mask(pos>32) = uint32(2^(pos(pos>32) -32 -1));
142             yMSB = y_MSB(pos>32);
143             ymask = mask(pos>32);
144             yMSB(vZero) = yMSB(vZero) & (~ymask(vZero));
145             yMSB(vOne) = yMSB(vOne) | ymask(vOne);
146             // v == 0
147             yMSB(vZero) = yMSB(vZero) & (~ymask(vZero));
148             // v == 1
149             yMSB(vOne) = yMSB(vOne) | ymask(vOne);
150             yMSB = matrix(yMSB, sz);
151         end
152         y = double(a * yMSB + yLSB);
153     end
154
155 endfunction