【问题标题】:Exercise 6 from Chapter 11 Programming in C Kochan, finding bit patterns第 11 章 C Kochan 编程中的练习 6,查找位模式
【发布时间】:2017-05-23 00:32:48
【问题描述】:

希望对位运算符有所帮助。练习内容如下:

编写一个名为 bitpat_search() 的函数,用于查找 unsigned int 内指定的位模式的出现。该函数应该接受三个参数,并且应该这样调用:

   bitpat_search (source, pattern, n)

该函数从最左边的位开始搜索整数“source”,以查看“pattern”的最右边n位是否出现在“source”中。如果找到模式,则让函数返回模式开始的位号,其中最左边的位是数字 0。如果找不到模式,则让函数返回 -1。所以,例如,调用

   index = bitpat_search (0xe1f4, 0x5, 3);

使 bit_pat(search() 函数在数字 0xe1f4(= 1110 0001 1111 0100 二进制)中搜索三位模式 0x5(= 101 二进制)的出现。该函数返回 11 表示该模式是在以第 11 位开头的“源代码”中找到。

确保函数不对 int 的大小做任何假设。

我遇到了一些问题:

1- 这些数字对我来说实际上没有多大意义......我在每次迭代后都尝试了各种 printf() 函数,看起来 0x5 数字被读取为 100 二进制,这将是四。如果我尝试其他数字,它们会相当随机,但通常是 000,所以.... 不是很有帮助。我算错了吗?右移会以某种方式改变它吗?

2 - 它返回了错误的位置(19 而不是 11),但是虽然我把上面的 q1 数字弄乱了,但它并没有真正起作用,是吗?

对不起,如果这对你们所有可爱的人来说是显而易见的,我只能看到它。 (顺便说一句,我只是想从书中学习,这不是学校的作业)。

谢谢

#include <stdio.h>

int int_size(unsigned int num);
int bit_test(unsigned int word, int position, int size);
int bitpat_search(unsigned int source, unsigned int pattern, int n);

int main(void)
{
    int index;

    index  = bitpat_search(0xe1f4, 0x5, 3);

    printf(" Pattern found in position %i\n", index);
    return 0;
}

int bitpat_search(unsigned int source, unsigned int pattern, int n)
{
    int i, j, tempSource, tempPat, count;

    int size = int_size(~0);

    for (i = 0; i < size;)
    {
        count = 0;
        for (j = 0; j < n; j++)
        {
            tempSource = bit_test(source, i, size);
            tempPat = bit_test(pattern, j, size);

            i++;
            count++;

            if (tempSource != tempPat)
            break;
        }
        if (count == n)
            return i - n;
    }
    return 0;

}

int bit_test(unsigned int word, int position, int size)
{
    if( (word >> (size - position)) & 0x1) // shift bits in word 31 minus n     spaces right, and AND word with hexadecimal 1
        return 1; // if above is true (1 & 1) return 1
    else
        return 0;

}

int int_size(unsigned int num)
{
    int size = 0;

    while (num)
    {
        size++;
        num >>= 1;
    }

    return size;
}

【问题讨论】:

    标签: c bitwise-operators bits


    【解决方案1】:
    for (i = 0; i < size;)
    {
        count = 0;
        for (j = 0; j < n; j++)
        {
            tempSource = bit_test(source, i, size);
            tempPat = bit_test(pattern, j, size);
    

    在这里,您正在检查源中位置 i 的位与模式中位置 j 的位。这需要在源代码中为i+j,否则您将模式与源中的一位进行比较,而不是将模式与源中的 number 位进行比较。由于模式 101 包含 1 和 0,因此您将永远找不到任何东西。

    旁注:您可以将int_size 函数替换为sizeof(int)*8。假设是 8 位字节,但自 80 年代初以来就没有出现过这种假设不成立的计算机,因此这应该是一个相当安全的假设。

    【讨论】:

    • sizeof(int)*CHAR_BIT 不会假定 8 位字节,但它仍然假定 int 没有填充位,这是无法保证的。
    • 在请求中,大小不假定为sizeof(int),而是“从最左边开始”。而对于要检查的源值0xe1f4,大小为16bits1110 0001 1111 0100。所以,int size = int_size(source);.
    【解决方案2】:

    1- 这些数字对我来说实际上没有多大意义......我在每次迭代后都尝试了各种 printf() 函数,看起来 0x5 数字被读取为 100 二进制,这将是四。如果我尝试其他数字,它们只是相当随机,但通常是 000,所以.... 不是很有帮助。我算错了吗?

    我无法评论您未提供的代码,但当然十六进制 0x5 是二进制 101。我倾向于假设您在测试中打印的值与您认为的打印值不同,或者您打印它们的机制存在缺陷。

    右移会以某种方式改变它吗?

    移位运算符保持其操作数不变。当然,如果符合条件的移位操作的右侧操作数不为零,则 结果 与左侧操作数不同。如果左侧操作数是从变量中提取的,那么您可能会在之后覆盖该变量的值。

    2 - 它返回了错误的位置(19 而不是 11),但是虽然我把上面的 q1 数字弄乱了,但它并没有真正起作用,是吗?

    我认为您的主要问题不是“弄乱数字”。你的实现是有问题的。考虑代码中的关键循环嵌套:

    for (i = 0; i < size;)
    {
        count = 0;
        for (j = 0; j < n; j++)
        {
            tempSource = bit_test(source, i, size);
            tempPat = bit_test(pattern, j, size);
    
            i++;
            count++;
    

    观察你在每次内循环迭代时增加外循环的控制变量。因此,您仅针对源字符串中的每个 nth 起始索引测试模式。也就是说,您测试源位的非重叠集。相反,您应该从每个可能的起始位置开始测试整个模式。

    还请注意,您要测试n-bit 模式不可能开始的起始位置,因为该位置和源字符串结尾之间的n 位少于。在这种情况下,您最终会通过对移位运算符使用无效的右手操作数来调用未定义的行为。

    【讨论】:

    • 顺便说一句,我首先不会逐位执行测试。您可以用右移 (&gt;&gt;)、按位与 (&amp;) 和按位异或 (^) 替换整个内部循环,从而一次测试所有模式位。跨度>
    • 谢谢约翰,我会再试一次......如果我能弄清楚如何使用,您使用位运算符的第二个建议可能就是我的意思。我真希望这本书有答案,不是因为我想复制和粘贴(我讨厌那样),但有时,当我真的被困住时,最好能对我应该理解的内容有所了解.在我理解问题和答案之前,我通常尽量不要继续前进(这很幸运,因为我第一次运行这个程序时它实际上产生了正确的答案,但它是基于一个错误,所以只是侥幸) .
    【解决方案3】:

    在所提出的算法中,除了@WouterVerhelst 揭示的问题外,还存在其他导致错误结果的问题。

    问题 1 - 在函数 bit_test() 中,测试位不是预期的。

    要从最左侧开始测试,请将(size - position) 替换为 (size - (position + 1)).

    int bit_test(unsigned int word, int position, int size)
    {
        if( (word >> (size - (position + 1))) & 0x1) // 
            return 1; // if above is true (1 & 1) return 1
        else
            return 0;
    }
    

    问题 2 - 要测试为与 source 相同的大小,pattern 应向左对齐。

    bitpat_search()中,在for循环之前,(size-n)的左移 位。

    int size = int_size(source);
    
    pattern = pattern << (size-n);
    

    问题 3 - 要将正确的countn 进行比较,应在count++ 之前进行位与break; 的比较。

        if (tempSource != tempPat)
            break;
    
        count++;
    

    问题 4 - 返回的索引结果将是 i 而不是 i - n(与问题 5 相关联)。

    if (count == n)
        return (i); // instead of (i - n);
    

    问题 5 - 正如@WouterVerhelst 建议的那样,sourcepattern 之间的比较应该针对每个位进行。

    for (i = 0; i < size;i++) // each bit ==> i++
    {
        count = 0;
        for (j = 0; j < n; j++)
        {
            tempSource = bit_test(source, i+j, size);
            tempPat = bit_test(pattern, j, size);
            // not here i++;
    
            if (tempSource != tempPat)
                break;
    
            count++;
        }
        if (count == n)
            return (i);
    }
    

    问题 6 - 'pattern not found' 的结果是 -1。

    return (-1); // Instead of (0);
    

    【讨论】:

    • 谢谢,现在可以使用了!现在我只需要把它写在纸上并理解为什么......谢谢! (然后我可能应该尝试使用按位运算符 John 的建议,但 babysteps 似乎首先是必要的)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多