对存在有效0位(低于最高1位)的数组元素进行计数



指定了一个包含3个字节的数组。计算任何一个后面有一个零的字节数。即在最高有效CCD_ 1之下的比特并非全部为CCD_。

{00000100, 00000011, 00001000}-对于这个数组,答案是2。

我的代码给出1,但不正确;如何修复?

#include <iostream>
#include <bitset>
using namespace std;
int main() {
int res = 0, res1 = 0;
_int8 arr[3] = { 4, 3, 8 };
__asm {
mov ecx, 3 
mov esi, 0
start_outer:
mov bx, 8 
mov al, arr[esi]
start_inner :
shl al, 1 
jnb zero 
jc one 
one :
dec bx к
test bx, bx
jnz start_inner 
jmp end_ 
zero :
dec bx 
test bx, bx
jz end_
inc res 
shl al, 1 
jnb was_zero 
jc start_inner 
was_zero :
dec bx 
dec res 
jmp start_inner 
end_ :
inc esi
loop start_outer
}
cout << res << endl;
system("pause");
}

下一次尝试。

下次请尽量解释得更好。许多人不理解你的问题。无论如何我希望我现在明白了。

我将解释一个字节使用的算法。在程序的后面,我们将运行一个简单的外循环3次,以处理所有值。当然,我会在汇编程序中显示结果。而且,这是许多可能的解决方案之一。

我们可以观察到以下情况:您的satement"计算任何一个后面有零的字节数。">意味着,您希望计算一个字节中一位从1到0的转换次数。如果我们看看从msb到lsb的比特。所以,从左到右。

如果我们将其公式化为反之亦然,那么如果我们从右向左,我们也可以计算从0到1的转换次数。

从0到1的转换总是可以通过将新值与取反的旧值"and"来计算。示例:

OldValue NewValue NotOldValue And
0 0        1           0
0 1        1           1   --> Rising edge
1 0        0           0
1 1        0           0

我们也可以说,如果没有设定以前的旧值,而设定了新值,那么我们就有上升的优势。

如果我们将字节向右移动,我们可以逐个查看(字节的(一个比特。然后,新的值(新的最低比特(将是LSB。我们记得以前的那一段,然后做测试。然后我们设置old=new,再次读取新值,进行测试等等。我们对所有比特都这样做。

在C++中,这可能看起来像这样:

#include <iostream>
#include <bitset>
using byte = unsigned char;
byte countForByte(byte b) {
// Initialize counter variable to 0
byte counter{};
// Get the first old value. The lowest bit of the orignal array entry
byte oldValue = b & 1;
// Check all 8 bits
for (int i=0; i<8; ++i) {
// Calculate a new value. First shift to right
b = b >> 1;
// Then mask out lowest bit
byte newValue = b & 1;
// Now apply our algorithm. The result will always be 0 or one. Add to result
counter += (newValue & !oldValue);
// The next old value is the current value from this time
oldValue = newValue;
} 
return counter;
}
int main() {
unsigned int x;
std::cin >> x;
std::cout << std::bitset<8>(x).to_string() << "n";
byte s = countForByte(x);
std::cout << static_cast<int>(s) << 'n';
return 0;
}

所以,无论出于何种原因,您都需要汇编程序中的解决方案。同样在这里,你需要告诉人们你为什么想要它,你使用什么编译器和你使用什么目标微处理器。否则,人们怎么能给出正确的答案呢?

不管怎样。这里是X86体系结构的解决方案。已测试wis MS VS2019。

#include <iostream>
int main() {
int res = 0;
unsigned char arr[3] = { 139, 139, 139 };
__asm {
mov esi, 0;         index in array
mov ecx, 3;         We will work with 3 array values
DoArray:
mov ah, arr[esi];   Load array value at index
mov bl, ah;         Old Value
and bl, 1;          Get lowest bit of old value
push ecx;           Save loop Counter for outer loop
mov ecx, 7;         7Loop runs to get the result for one byte
DoTest:
shr ah, 1;          This was the original given byte
mov al, ah;         Get the lowest bit from the new shifted value
and al, 1;          This is now new value
not bl;             Invert the old value
and bl, al;         Check for rising edge
movzx edi, bl
add res, edi;       Calculate new result
mov bl, al;         Old value = new value
loop DoTest
inc esi;            Next index in array
pop ecx;            Get outer loop counter
loop DoArray;       Outer loop
}
std::cout << res << 'n';
return 0;
}

对于这项工作,我想要100张赞成票和一个被接受的答案。

基本上,用户@Michael已经给出了正确的答案。所以所有的功劳都归他所有。

你可以在这里找到很多关于堆栈溢出的小技巧帖子。但是,你可以在"Henry s.Warren,Jr.">的《黑客的喜悦》一书中找到对此类活动的一个很好的描述。我在这里有第二版。

该解决方案在第2章"基础"中介绍,然后在中介绍"2–1操作最右位">

如果你手动检查,哪些值NOT完全满足你的条件,那么你会发现这些是

0,1,3,7,15,31,63127255,

或者,在二进制中

0b0000'0000,0b0000'1001,0b00000'0011,0b000'0111,0b00001'1111,0b0011'1111,0 b0111'1111

我们发现这些值对应于2^n-1。并且,根据"黑客的喜悦">,我们可以发现,用简单的公式

(x & (x + 1)) != 0

因此,我们可以将其转换为以下代码:

#include <iostream>
int main() {
unsigned char arr[3];
unsigned int x, y, z;
std::cin >> x >> y >> z;
arr[0] = static_cast<unsigned char>(x);
arr[1] = static_cast<unsigned char>(y);
arr[2] = static_cast<unsigned char>(z);
unsigned char res = ((arr[0] & (arr[0] + 1)) != 0) +  ((arr[1] & (arr[1] + 1)) != 0) + ((arr[2] & (arr[2] + 1)) != 0);
std::cout << static_cast<unsigned int>(res) << 'n';
return 0;
}

非常重要。您不需要汇编代码。优化编译器几乎总是优于手写代码。

您可以在编译器资源管理器上检查许多不同的版本。在这里,您可以看到,带有静态值的代码示例将被完全优化掉。编译器只需在编译时计算所有值,并将结果显示为2。所以,请注意。编译器资源管理器将向您显示不同编译器生成的汇编语言以及所选硬件的汇编语言。如果你愿意,你可以拿。

另外请注意:上面绘制的算法不需要任何分支。除非,如果您想在数组/向量上进行迭代。为此,您可以编写一个小lambda并使用C++标准库中的算法。

C++解决方案

#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <iterator>
int main() {
// Define Lambda to check conditions
auto add = [](const size_t& sum, const unsigned char& x) -> size_t {
return sum + static_cast<size_t>(((x & (x + 1)) == 0) ? 0U : 1U); };
// Vector with any number of test values
std::vector<unsigned char> test{ 4, 3, 8 };
// Calculate and show result
std::cout << std::accumulate(test.begin(), test.end(), 0U, add) << 'n';
return 0;
}

最新更新