为什么我的移位给了错误的数字

时间:2018-09-23 00:45:44

标签: c++ bit logical-operators

我正在尝试将数字存储在4个整数的数组中。该数组在类Num中。我的问题是,当我调用getValue时,该函数返回的数字不正确。我尝试在纸上浏览该程序,并使用Microsoft的计算器进行所有计算,该程序应提供正确的输出。我什至不知道哪个功能可能有问题,因为没有任何错误或警告,并且两者都可以在纸上工作。

21(二进制):10101

我要做什么:

输入setValue函数:21

setValue210101)的前四位放入num[3]中。因此num[3]现在是二进制的0101。然后,应将21的后四位放入num[2]中。接下来的四位是0001,因此0001进入num[2]其余的位是0,因此我们忽略它们。现在num{0,0,1,5}getValue首先进入num[3]5是二进制文件0101。因此,它将其放入返回值的前四位。然后将0001放入接下来的四位。其余数字为0,因此应该忽略它们。然后,直接输出函数getValue的输出。实际输出在底部。

我的代码:

#include <iostream>
class Num {
    char len = 4;
    int num[4];
    public:
        void setValue(int);
        int getValue();
};

void Num::setValue(int toSet)
{
    char len1=len-1;
    for (int counter = len1;counter>=0;counter--)
    {
        if(toSet&(0xF<<(len1-counter))!=0)
        {
            num[counter]=(toSet&(0xF<<(len1-counter)))>>len1-counter;
        } else {
            break;
        }
    }
}

int Num::getValue() 
{
    char len1 = len-1;
    int returnValue = 0;
    for(char counter = len1; counter>=0;counter--)
    {
        if (num[counter]!=0) {
            returnValue+=(num[counter]<<(len1-counter));
        } else {
            break;
        }

    }
    return returnValue;
}

int main()
{
    int x=260;
    Num number;
    while (x>0)
    {
        number.setValue(x);
        std::cout<<x<<"Test: "<<number.getValue()<<std::endl;
        x--;
    }



    std::cin>>x;
    return 0;
}

输出:

260Test: -1748023676
259Test: 5
258Test: 5
257Test: 1
256Test: 1
255Test: 225
254Test: 225
253Test: 221
252Test: 221
251Test: 213
250Test: 213
249Test: 209
248Test: 209
247Test: 193
246Test: 193
245Test: 189
244Test: 189
243Test: 181
242Test: 181
241Test: 177
240Test: 177
239Test: 177
238Test: 177
237Test: 173
236Test: 173
235Test: 165
234Test: 165
233Test: 161
232Test: 161
231Test: 145
230Test: 145
229Test: 141
228Test: 141
227Test: 133
226Test: 133
225Test: 1
224Test: 1
223Test: 161
222Test: 161
221Test: 157
220Test: 157
219Test: 149
218Test: 149
217Test: 145
216Test: 145
215Test: 129
214Test: 129
213Test: 125
212Test: 125
211Test: 117
210Test: 117
209Test: 113
208Test: 113
207Test: 113
206Test: 113
205Test: 109
204Test: 109
203Test: 101
202Test: 101
201Test: 97
200Test: 97
199Test: 81
198Test: 81
197Test: 77
196Test: 77
195Test: 5
194Test: 5
193Test: 1
192Test: 1
191Test: 161
190Test: 161
189Test: 157
188Test: 157
187Test: 149
186Test: 149
185Test: 145
184Test: 145
183Test: 129
182Test: 129
181Test: 125
180Test: 125
179Test: 117
178Test: 117
177Test: 113
176Test: 113
175Test: 113
174Test: 113
173Test: 109
172Test: 109
171Test: 101
170Test: 101
169Test: 97
168Test: 97
167Test: 81
166Test: 81
165Test: 77
164Test: 77
163Test: 69
162Test: 69
161Test: 1
160Test: 1
159Test: 97
158Test: 97
157Test: 93
156Test: 93
155Test: 85
154Test: 85
153Test: 81
152Test: 81
151Test: 65
150Test: 65
149Test: 61
148Test: 61
147Test: 53
146Test: 53
145Test: 49
144Test: 49
143Test: 49
142Test: 49
141Test: 45
140Test: 45
139Test: 37
138Test: 37
137Test: 33
136Test: 33
135Test: 17
134Test: 17
133Test: 13
132Test: 13
131Test: 5
130Test: 5
129Test: 1
128Test: 1
127Test: 225
126Test: 225
125Test: 221
124Test: 221
123Test: 213
122Test: 213
121Test: 209
120Test: 209
119Test: 193
118Test: 193
117Test: 189
116Test: 189
115Test: 181
114Test: 181
113Test: 177
112Test: 177
111Test: 177
110Test: 177
109Test: 173
108Test: 173
107Test: 165
106Test: 165
105Test: 161
104Test: 161
103Test: 145
102Test: 145
101Test: 141
100Test: 141
99Test: 133
98Test: 133
97Test: 1
96Test: 1
95Test: 161
94Test: 161
93Test: 157
92Test: 157
91Test: 149
90Test: 149
89Test: 145
88Test: 145
87Test: 129
86Test: 129
85Test: 125
84Test: 125
83Test: 117
82Test: 117
81Test: 113
80Test: 113
79Test: 113
78Test: 113
77Test: 109
76Test: 109
75Test: 101
74Test: 101
73Test: 97
72Test: 97
71Test: 81
70Test: 81
69Test: 77
68Test: 77
67Test: 5
66Test: 5
65Test: 1
64Test: 1
63Test: 161
62Test: 161
61Test: 157
60Test: 157
59Test: 149
58Test: 149
57Test: 145
56Test: 145
55Test: 129
54Test: 129
53Test: 125
52Test: 125
51Test: 117
50Test: 117
49Test: 113
48Test: 113
47Test: 113
46Test: 113
45Test: 109
44Test: 109
43Test: 101
42Test: 101
41Test: 97
40Test: 97
39Test: 81
38Test: 81
37Test: 77
36Test: 77
35Test: 69
34Test: 69
33Test: 1
32Test: 1
31Test: 97
30Test: 97
29Test: 93
28Test: 93
27Test: 85
26Test: 85
25Test: 81
24Test: 81
23Test: 65
22Test: 65
21Test: 61
20Test: 61
19Test: 53
18Test: 53
17Test: 49
16Test: 49
15Test: 49
14Test: 49
13Test: 45
12Test: 45
11Test: 37
10Test: 37
9Test: 33
8Test: 33
7Test: 17
6Test: 17
5Test: 13
4Test: 13
3Test: 5
2Test: 5
1Test: 1

我用g++ 6.3.0g++ a.cpp -o a.exe的命令对此进行了编译

2 个答案:

答案 0 :(得分:0)

使用-Wall进行编译时,有许多警告:

orig.cpp: In member function ‘void Num::setValue(int)’:
orig.cpp:15:39: warning: suggest parentheses around comparison in operand of ‘&’ [-Wparentheses]
         if(toSet&(0xF<<(len1-counter))!=0)
                  ~~~~~~~~~~~~~~~~~~~~~^~~
orig.cpp:17:61: warning: suggest parentheses around ‘-’ inside ‘>>’ [-Wparentheses]
             num[counter]=(toSet&(0xF<<(len1-counter)))>>len1-counter;
                                                         ~~~~^~~~~~~~
orig.cpp: In member function ‘int Num::getValue()’:
orig.cpp:30:24: warning: array subscript has type ‘char’ [-Wchar-subscripts]
         if (num[counter]!=0) {
                        ^
orig.cpp:31:38: warning: array subscript has type ‘char’ [-Wchar-subscripts]
             returnValue+=(num[counter]<<(len1-counter));
                                      ^

如果在更改之前打印num 的值,您会发现某些值可能非零(即它们未初始化),这会导致未定义的行为,并且可能会中断forgetValue中的setValue循环。

所以改变:

int num[4];

进入:

int num[4] = { 0 };

这是一个修正了警告的清理版本:

#include <iostream>
class Num {
    int len = 4;
    int num[4] = { 0 };
    public:
        void setValue(int);
        int getValue();
        void showval();
};

void Num::setValue(int toSet)
{
    int len1=len-1;
    for (int counter = len1;counter>=0;counter--)
    {
        if ((toSet & (0xF << (len1-counter))) != 0)
        {
            num[counter] = (toSet & (0xF << (len1-counter))) >> (len1-counter);
        } else {
            break;
        }
    }
}

int Num::getValue()
{
    int len1 = len-1;
    int returnValue = 0;
    for(int counter = len1; counter>=0;counter--)
    {
        if (num[counter]!=0) {
            returnValue+=(num[counter]<<(len1-counter));
        } else {
            break;
        }

    }
    return returnValue;
}

void Num::showval()
{

    for (int i = 0;  i < len;  ++i)
        std::cout << i << ": show: " << num[i] << "\n";

#if 0
    for (int i = 0;  i < len;  ++i)
        num[i] = 0;
#endif
}

int main()
{
    int x=260;
    Num number;

    number.showval();

    while (x>0)
    {
        number.setValue(x);
        std::cout << x << " Test: " << number.getValue() << std::endl;
        x--;
    }

    std::cin>>x;
    return 0;
}

答案 1 :(得分:0)

要将数字细分为零,移位计数应为4的倍数。否则,将提取不排成一行的4位切片。

00010101 (21)
    ^^^^ first nibble
^^^^ second nibble

第二个半字节移位了4位,因此需要右移4,而不是1。

您可以将班次计数乘以4,但是有一种更简单的方法:仅将班次乘以4。例如:

for (int i = len - 1; i >= 0; i--) {
    num[i] = toSet & 0xF;
    toSet >>= 4;
}

然后,每次迭代都提取toSet中的最低半字节,并将toSet移至下一个半字节,从而成为最低半字节。 我没有放入break,因此不应有一个。绝对不应该是您所拥有的break类型,它会在数字中间有零时也停止循环(例如,在0x101中,中间的0会导致循环停止)。当数字的其余全部为零时,循环也不应停止,因为这样会在num的其他条目中留下垃圾。

在第0个元素中存储最低的半字节是更常见的,依此类推(然后,您不必使用递减计数循环处理所有“逆逻辑”并从长度中减去东西),但这取决于你。

可以对称地提取值,在移动结果时累积结果,而不是立即将每一部分移到最终位置。或仅将(len1-counter)乘以4。提取值时,num[i]为零时也不能停止,因为这不能证明数字的其余部分也为零。