例如:
unsigned int a; // value to merge in non-masked bits
unsigned int b; // value to merge in masked bits
unsigned int mask; // 1 where bits from b should be selected; 0 where from a.
unsigned int r; // result of (a & ~mask) | (b & mask) goes here
r = a ^ ((a ^ b) & mask);
根据掩码合并两个值的位。
[取自here]
在这种情况下,我可以看到它有效,但我不确定逻辑是什么?而且我不确定我是否可以从头开始创建自己的位操作。我该如何开始思考?
答案 0 :(得分:7)
铅笔和纸张在这种情况下可以提供最佳帮助。我通常把它写下来:
a = 10101110
b = 01100011
mask = 11110000
a ^ b = 10101110
01100011
--------
x => 11001101
x & mask = 11001101
11110000
--------
x => 11000000
a ^ x = 11000000
10101110
--------
x => 01101110
(最终x
是您的r
)
我不知道这是否是你所追求的结果,但这就是它的作用。当我不理解按位操作时,写出来通常会有所帮助。
答案 1 :(得分:5)
在这种情况下,我可以看到它有效,但我不确定逻辑是什么?而且我不确定我是否可以从头开始创建自己的位操作。我该如何开始思考?
人们已经回答了你的第一个问题 - 解释逻辑。我希望能向你展示一个非常基本的,冗长但标准的方法,使任何一点点操作。 (注意,一旦你习惯了比特,你就会开始考虑&和|直接关闭而不做这些废话)。
得出你给出的例子。即,掩码从A或B中选择位。(0是A,1是B)
此表适用于每个输入1位。我做的不多,因为我不想浪费我的时间:)(为什么?2 ^(2bits * 3inputs)= 64个案例:( 2 ^(3bits * 3inputs)= 512个案例:(( )
但好消息是,在这种情况下,操作独立于位数,因此1位示例是100%罚款。事实上,我建议:)
| A | B | M || R |
============++====
| 0 | 0 | 0 || 0 |
| 0 | 0 | 1 || 0 |
| 0 | 1 | 0 || 0 |
| 0 | 1 | 1 || 1 |
| 1 | 0 | 0 || 1 |
| 1 | 0 | 1 || 0 |
| 1 | 1 | 0 || 1 |
| 1 | 1 | 1 || 1 |
希望你能看到这个真值表是如何运作的。
如何从中获取表达式?两种方法:KMaps和副手。我们先做,我们先做吧? :)
看看R为真的点,我们看到:
| A | B | M || R |
============++====
| 0 | 1 | 1 || 1 |
| 1 | 0 | 0 || 1 |
| 1 | 1 | 0 || 1 |
| 1 | 1 | 1 || 1 |
从这里我们可以进行表达:
R = (~A & B & M) |
( A & ~B & ~M) |
( A & B & ~M) |
( A & B & M) |
希望你能看到它是如何工作的:只是或者在每种情况下看到的完整表达式。完全我暗示你不需要变量。
让我们在python中尝试:
a = 0xAE #10101110b
b = 0x64 #01100011b
m = 0xF0 #11110000b
r = (~a & b & m) | ( a & ~b & ~m) | ( a & b & ~m) | ( a & b & m)
print hex(r)
输出:
0x6E
这些数字来自亚伯的例子。输出为0x6E
,即01101110b
。
所以它奏效了!欢呼。 (ps,如果你愿意的话,可以从第一个表中导出~r的表达式。只需考虑r为0的情况。)
你所做的这个表达式是一个布尔“产品之和”,又名析析范式,虽然DNF实际上是使用一阶谓词逻辑时使用的术语。这个表达也非常不合情理。将它缩小是一件很麻烦的事情,如果你学习编译器或硬件课程,你可以在Uni'的CS学位上做50万次。 (强烈推荐:))
所以让我们做一些布尔代数魔法(不要试着这样做,这是浪费时间):
(~a & b & m) | ( a & ~b & ~m) | ( a & b & ~m) | ( a & b & m)
|= ((~a & b & m) | ( a & ~b & ~m)) | ( a & b & ~m) | ( a & b & m)
采取我做的第一个子条款:
((~a & b & m) | ( a & ~b & ~m))
|= (~a | (a & ~b & ~m)) & (b | ( a & ~b & ~m)) & (m | ( a & ~b & ~m))
|= ((~a | a) & (a | ~b) &( a | ~m)) & (b | ( a & ~b & ~m)) & (m | ( a & ~b & ~m))
|= (T & (a | ~b) &( a | ~m)) & (b | ( a & ~b & ~m)) & (m | ( a & ~b & ~m))
|= ((a | ~b) & (a | ~m)) & (b | ( a & ~b & ~m)) & (m | ( a & ~b & ~m))
等等等。这是你猜不到的大量繁琐的一点。所以,只需在你的choice的网站上敲击表达式,它会告诉你
r = (a & ~m) | (b & m)
乌拉!正确的结果。注意,甚至可能会给你一个涉及XOR的表达,但是谁在乎?实际上,有些人会这样做,因为and
和or
s的表达式是4次操作(1 or
,2 and
,1 neg
),而r = a ^ ((a ^ b) & mask)
为3(2 xor
,1 and
)。
现在,你如何用kmaps做到这一点?好吧,首先你需要知道如何制作它们,我会让你这样做。 :)只是谷歌为它。有软件可用,但我认为最好手动完成 - 它更有趣,程序不允许你作弊。 作弊?好吧,如果你有很多输入,通常最好像这样减少表:
| A | B | M || R |
============++====
| X | X | 0 || A |
| X | X | 1 || B |
例如64个案例表?
| A1| A0| B1| B0| M1| M0|| R1| R0|
========================++========
| X | X | X | X | 0 | 0 || A1| A0|
| X | X | X | X | 0 | 1 || A1| B0|
| X | X | X | X | 1 | 0 || B1| A0|
| X | X | X | X | 1 | 1 || B1| B0|
在此示例中归结为4个案例:)
(其中X是“不关心”。)然后将那个表放在Kmap中。再一次,练习让你锻炼[即,我忘记了怎么做]。
希望你现在可以在给定一组输入和一组预期输出的情况下推导出你自己的布尔疯狂。
玩得开心。
答案 2 :(得分:2)
为了创建像那样的布尔表达式,我认为你必须学习一些布尔代数。
看起来不错:
http://www.allaboutcircuits.com/vol_4/chpt_7/1.html
它甚至有一个关于从真值表生成布尔表达式的页面。
它还有一个关于卡诺图的部分。说实话,我已经忘记了那些是什么,但看起来它们对你想做的事情有用。
http://www.allaboutcircuits.com/vol_4/chpt_8/1.html
答案 3 :(得分:0)
a ^ x
的 x
给出了a
中x
中设置a ^ b
中的那些位的结果。
a
为您提供1,其中b
和x
中的位不同,0表示它们相同。
将(a ^ b) & mask
设置为a
会得到翻转a
中b
和a ^ ((a ^ b) & mask)
中不同的位并在掩码中设置的结果。因此,a
给出了在必要时将掩码中设置的位的值从它们在b
中取值的值更改为它们在{{1}}中取值的结果。< / p>
答案 4 :(得分:0)
在不那么难的情况下思考,你只需要在头脑中将所有值转换成位并一次一点地处理它们。这听起来很难,但随着时间的推移会变得更容易。一个好的第一步是开始将它们视为十六进制数字(一次4位)。
例如,假设a
为0x13,b
为0x22且mask
为0x0f:
a : 0x13 : 0001 0011
b : 0x22 : 0010 0010
---------------------------------
a^b : 0x31 : 0011 0001
mask : 0x0f : 0000 1111
---------------------------------
(a^b)&mask : 0x01 : 0000 0001
a : 0x13 : 0001 0011
---------------------------------
a^((a^b)&mask) : 0x12 : 0001 0010
此特定示例是将a
的前四位与b
的后四位组合的方法(掩码决定哪些位来自a
和{{1} }。
正如网站所说,这是b
的优化:
(a & ~mask) | (b & mask)
除此之外:我不会过分关注你在链接到的页面上没有理解的东西。那里有一些严重的“黑魔法”。如果你真的想要了解一点点摆弄,那就从未经优化的方式开始吧。
答案 5 :(得分:0)
大多数按位运算(&amp;,|,^,〜)的基础是Boolean algebra。考虑将布尔代数并行执行多个布尔值,并且您已经获得了按位运算符。这个未覆盖的唯一运算符是移位运算符(&lt;&lt;&gt;&gt;),您可以将其视为移位或乘以2的幂。 x << 3 == x * pow(2,3)
和x >> 4 == (int)(x * pow(2,-4))
。
答案 6 :(得分:0)
将表达式分解为单个位。考虑表达式(a ^ b) & mask
中的单个位位置。如果掩码在该位位置为零,(a ^ b) & mask
将只给出零。任何与零相关的位都将保持不变,因此a ^ (a ^ b) & mask
将只返回a
的原始值。
如果掩码的位置为1,(a ^ b) & mask
将只返回a ^ b
的值。现在,如果我们将值与a相加,我们得到a ^ (a ^ b) = (a ^ a) ^ b = b
。这是a ^ a = 0
的结果 - 任何与自身相关的值都将返回零。然后,如前所述,零xor'ed任意值只会给你原始值。
如何思考:
阅读其他人所做的事情,并记下他们的策略。您链接到的斯坦福站点是一个非常好的资源 - 通常会针对特定操作显示几种技术,允许您从不同角度查看问题。您可能已经注意到,有些人为特定操作提交了自己的替代解决方案,这些解决方案受到应用于不同操作的技术的启发。你可以采取同样的方法。
此外,它可能会帮助您记住一些简单的身份,然后您可以将它们串在一起以进行更有用的操作。 IMO列出每个位组合的结果仅对逆向工程别人的工作有用。
答案 7 :(得分:0)
首先要很好地学习逻辑(即1位)运算符。尝试写下一些规则,比如
a && b = b && a
1 && a = a
1 || a = 1
0 && a = ... //you get the idea. Come up with as many as you can.
包括“逻辑”xor运算符:
1 ^^ b = !b
0 ^^ b = ...
一旦你对这些感觉有所感受,就转向按位运算符。尝试一些问题,看看一些常见的技巧和技巧。通过一些练习,你会感到更自信。
答案 8 :(得分:0)
也许你不需要考虑一下 - 也许你可以让你的编译器为你思考 你可以专注于你试图解决的实际问题。直接使用位操作 在你的代码中可以产生一些非常难以理解的(如果令人印象深刻的)代码 - 这里有一些不错的宏 (来自windows ddk)演示了这个
//来自ntifs.h
//这些宏用于分别测试,设置和清除标志
#define FlagOn(_F,_SF)((_ F)&amp;(_SF))
#define BooleanFlagOn(F,SF)((BOOLEAN)(((F)&amp;(SF))!= 0))
#define SetFlag(_F,_SF)((_ F)| =(_SF))
#define ClearFlag(_F,_SF)((_ F)&amp; =〜(_SF))
现在如果你想在一个值中设置一个标志,我可以简单地说SetFlag(x,y)更清晰。此外 如果你专注于你正试图解决的问题,那么你的技巧就会变得更加强大 第二天性,你不必花费任何精力。查看位和字节将照顾 自己!