如果给定两个十六进制数,用格雷码判断它们是否可以连续
If given two hexadecimal numbers find if they can be consecutive in gray code
"consecutive in gray code" 是什么意思?我的意思是 10 和 11 在十进制中是连续的,但是 "consecutive in gray code" 是什么意思?我只知道格雷码是一种二进制数字系统,两个连续的值只有一位不同。
网上有解决办法,但是我看不懂
private static int graycode(byte term1, byte term2) {
byte x = (byte)(term1^term2); // why use XOR?
int count = 0;
while(x!=0)
{
x = (byte)(x &(x-1)); // why use bitwise operator?
count++; // what is count?
}
return count == 1;
}
我花了一个小时试图理解,但我仍然没有头绪。
这意味着两个数字恰好相差一位。
所以解决方案从对两个数字进行异或运算开始。异或运算结果为 1,其中操作数的位不同,否则为零。
因此您需要计算异或结果中的位数并与 1 进行比较。您下载的示例就是这样做的。由于 Brian Kernighan,这种计算二进制数 1 的方法是一种相当著名的方法。状态 x = (byte)(x & (x-1))
是位魔术,可将最高位 1 位重置为零。 There are lots of others.
或者,您可以用 1 位搜索 8 个可能字节中的 table。
byte one_bit_bytes[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
如果两个数字在二进制表示中仅相差一位,则它们在格雷码中被认为是连续的,例如111 和 101 仅第二位不同。您拥有的功能检查两个输入字节是否只有一位使它们不同。所以 111 和 101 将从函数 return 1 而 111 和 100 将 return 0.
异或用于查找两个数字之间的差异;当位不同时 XOR 产生 1,否则产生 0,例如1111 XOR 1011 将给出 0100。因此,对于 XOR,每个位差都在该位置以 1 突出显示。如果两个数字都是连续的格雷码,那么 XOR 的结果中应该只有一个 1。多于一个 1 表示存在多重差异,因此不符合标准。 XOR 结果存储在变量 x
.
中
接下来的任务是计算 1 的个数——因此变量 count
。如果您尝试其他格雷码对(位长更长),您会注意到获得的 XOR 值将始终采用这种格式(忽略前导零):10、100、1000 等。基本上,1 后跟零,或者,换句话说,总是 2 的幂。
如果这些样本 XOR 结果减 1,您将得到:01、011、0111 等。如果这些新值与原始 XOR 结果进行 AND 运算,则结果每次都是 0。这是在您的解决方案中实现的逻辑:对于连续的格雷码对,while 循环只会 运行 一次(并递增 count
),之后它将终止,因为 x
已变为 0 .所以count = 1
在最后。对于非连续对,循环将 运行 不止一次(尝试)并且 count
最后会大于 1。
如果 count
== 1,则函数将其用作 return 1 的基础,否则为 0。
有点晦涩,但它完成了工作。
这是一种非常不直观的方法来计算二进制数中有多少位等于“1”。
它需要二进制算术知识。从一个由“1”后跟一个或多个零组成的十进制数减去 1 时发生的情况开始:您得到一个 9 的序列,其长度等于零的数量:
1000000 - 1 = 999999
二进制数也会发生类似的事情。如果从非负二进制数中减去 1,则所有最低的“0”数字都将替换为“1”,并且这些零之前的“1”将替换为零。这遵循以二进制进行借用的方式。示例:
0101_0000_0001_0000 - 1 = 0101_0000_0000_1111
aaaa aaaa aaab cccc -> aaaa aaaa aaab cccc
符号:下划线以提高易读性。出现在字母 a 上方的所有数字均保持不变。出现在字母 b 上方的数字“1”更改为“0”。而出现在字母c上方的数字'0'被更改为'1'。
下一步是对两个数字 (X) 和 (X-1) 进行按位与运算。使用上述算术 属性,在每次迭代中,只有一个数字“1”从数字中消失(从右边开始,即最低有效位)。
通过计算迭代次数,我们可以知道数字 X 中最初出现了多少个“1”位。当变量 X 等于 0 时,迭代停止。
其他人已经回答了关于格雷码的问题。我的回答只解释了 "bit counting" 是如何工作的(在对两个值进行异或之后)。
这是针对特定格雷码单调排序(二进制反射格雷码)的简单测试:
// convert Gray code binary number to base 2 binary number
int Base2(byte Gray){ Gray^=Gray>>4; Gray^=Gray>>2; return Gray^=Gray>>1; }
// test if Gray codes are consecutive using "normal" base 2 numbers
boolean GraysAdjacent(byte x, byte y){ return 1 == abs(Base2(x)-Base2(y)); }
特别看看这个答案(最佳):
How to find if two numbers are consecutive numbers in gray code sequence
在 C 中编码为:
int GraysTouch(byte x, byte y){ return !( (x^y ^ 1) && ( x^y ^ (y&-y)<<1 ) ); }
// test x marks the spots! (where they touch!)
for(int i=31; i>-1; --i )
for(int j=31; j>-1; --j )
Serial.print((String)(GraysTouch( i^i>>1, j^j>>1 )?"x":".") +
(GraysTouch( j^j>>1, i^i>>1 )?"X":".") + (j?"":"\n"));
如何这个工作:...将被解释并且不是 OP代码因为它非常可疑(请参阅下面的注意事项评论)。
XOR
的 属性,又名 ^
运算符,匹配的位是 0
,不同的位是 1
。
1^0 == 0^1 == 1
1^1 == 0^0 == 0
此外,0 XOR b
暂时用作身份函数或简单地 b
和
1 XOR b
用作补充(请不要恭维)函数或 ~b
。
id(x) == x == x^0
opposite(x) == ~x == x^11111111 Why eight 1's? Are eight enough?
当比较两个位串与XOR
时,XOR
与1
不同的位,否则必须匹配并且XOR
是 0
:
0101 0001111001100111000
XOR 0011 XOR 0001111001100000111
------ ---------------------
0110 0000000000000111111
这解释了上面代码的 x^y
部分。
-------------------------------------------- ------------------------
题外话:
n^n>>1
进行从基数 2 二进制数到此处使用的格雷码二进制数的快速转换。
还要注意 f(a,b)=a^b^b=a
对于任何 b
!
是幂等的
那么就地交换是 a=a^b; b=a^b; a=a^b;
.
展开 c=a^b; d=c^b; e=c^d;
即。 d=a^b^b=a; e=a^b^a=b;
-------------------------------------------- --------------------------
现在,根据定义,对于相邻或连续的两个格雷码数,必须一位并且只有一位可以改变,与众不同。
例子:
Johnson
Code
000 000 000 000
001 001 001 100
011 101 011 110
111 111 010 010
110 011 110 011
100 010 111 111
110 101 101
100 100 001
^^^
this Gray coding
is the one used here
仔细检查。
案例一
当连续数的最低位x
和y
,对于any格雷码,其余必须一样!这是格雷码的定义。这意味着 x^y
必须 看起来像 0000...0001。
还记得补码,~
函数又名 1^b
吗?要测试最后一位 x^y
是 XOR
和 1
。
这解释了 x^y ^ 1
。
-----------------------------------------
案例二
连续的格雷码数x
和y
中不同位的位置不是最低位。仔细看这些格雷码连续数字。
001 010 101 lower order bits all match
011 110 111
| | | <-- | mark location of lowest 1
010 100 010 <-- XOR's
有趣的是,在this格雷码中,当最低位匹配x
和y
时,最低位的位置也匹配1
。
更有趣的是,对于连续的数字,总是不同(对于this格雷码)下一个高位位位置!
所以,x^y
看起来像 ???...?1000...0
其中 1000...0
必须至少有一个 0,10
(为什么?)和 ???...?
是谜连续个格雷码数的位必须是000...0
。 (为什么?即连续 x^y
必须看起来像...)
观察到
x^y looks like ???...?100...0 if and only if
x and y look like ???...?:10...0
| <-- remember? the 1 location !!
|
位置可以通过 x&-x
或 y&-y
找到。 (为什么?为什么 -
必须使用 2 的补码机来完成?)
但是,必须检查 :
位置以查看它是 1
(为什么?)并且 ???...?
是 000...0
。 (为什么?)
所以,
x^y looks like ???...?100...0 and
(y&-y)<<1 looks like 000...0100...0
这解释了 x^y ^ ((y&-y)<<1)
测试。
-------------------------------------------- ----------------------
为何如此有效:...是此处使用的特定格雷码的属性的结果。关于为什么这个格雷码应该具有这些性质,检查和解释太复杂了,不能在这里给出。
---------------------------------------- ------------------------------
由于 OP 代码问题,对先前答案的不足之处进行评论。
警告 1: 明确地说,OP 问题中的算法:
private static int graycode(byte term1, byte term2) {
byte x = (byte)(term1^term2); // why use XOR?
int count = 0;
while(x!=0)
{
x = (byte)(x &(x-1)); // why use bitwise operator?
count++; // what is count?
}
return count == 1;
}
对连续的格雷码有一个有趣的解释。当任何两个二进制序列在单个位位置不同时,它确实会正确报告。
如果连续代码意味着格雷码用于枚举单调排序,则存在问题。
具体来说,代码将为所有这些对 return true
:
000, 001 or 000, 010 or 000, 100
所以排序可能是 001, 000, 010
但是 100
可以去哪里?
该算法(正确地)报告 100
的 "consecutiveness" 与 001 or 010
之一是 false
。
因此 100
在枚举中必须紧跟在 000
之前或之后,但不能紧跟在 001
或 010
之前或之后。 DOH!!!
警告 2: 注意 x = (byte)(x & (x-1))
重置 lowest 顺序 1 位x
到零。
参考文献:
Gray code increment function
https://electronics.stackexchange.com/questions/26677/3bit-gray-counter-using-d-flip-flops-and-logic-gates
How do I find next bit to change in a Gray code in constant time?
How to find if two numbers are consecutive numbers in gray code sequence
"consecutive in gray code" 是什么意思?我的意思是 10 和 11 在十进制中是连续的,但是 "consecutive in gray code" 是什么意思?我只知道格雷码是一种二进制数字系统,两个连续的值只有一位不同。
网上有解决办法,但是我看不懂
private static int graycode(byte term1, byte term2) {
byte x = (byte)(term1^term2); // why use XOR?
int count = 0;
while(x!=0)
{
x = (byte)(x &(x-1)); // why use bitwise operator?
count++; // what is count?
}
return count == 1;
}
我花了一个小时试图理解,但我仍然没有头绪。
这意味着两个数字恰好相差一位。
所以解决方案从对两个数字进行异或运算开始。异或运算结果为 1,其中操作数的位不同,否则为零。
因此您需要计算异或结果中的位数并与 1 进行比较。您下载的示例就是这样做的。由于 Brian Kernighan,这种计算二进制数 1 的方法是一种相当著名的方法。状态 x = (byte)(x & (x-1))
是位魔术,可将最高位 1 位重置为零。 There are lots of others.
或者,您可以用 1 位搜索 8 个可能字节中的 table。
byte one_bit_bytes[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
如果两个数字在二进制表示中仅相差一位,则它们在格雷码中被认为是连续的,例如111 和 101 仅第二位不同。您拥有的功能检查两个输入字节是否只有一位使它们不同。所以 111 和 101 将从函数 return 1 而 111 和 100 将 return 0.
异或用于查找两个数字之间的差异;当位不同时 XOR 产生 1,否则产生 0,例如1111 XOR 1011 将给出 0100。因此,对于 XOR,每个位差都在该位置以 1 突出显示。如果两个数字都是连续的格雷码,那么 XOR 的结果中应该只有一个 1。多于一个 1 表示存在多重差异,因此不符合标准。 XOR 结果存储在变量 x
.
接下来的任务是计算 1 的个数——因此变量 count
。如果您尝试其他格雷码对(位长更长),您会注意到获得的 XOR 值将始终采用这种格式(忽略前导零):10、100、1000 等。基本上,1 后跟零,或者,换句话说,总是 2 的幂。
如果这些样本 XOR 结果减 1,您将得到:01、011、0111 等。如果这些新值与原始 XOR 结果进行 AND 运算,则结果每次都是 0。这是在您的解决方案中实现的逻辑:对于连续的格雷码对,while 循环只会 运行 一次(并递增 count
),之后它将终止,因为 x
已变为 0 .所以count = 1
在最后。对于非连续对,循环将 运行 不止一次(尝试)并且 count
最后会大于 1。
如果 count
== 1,则函数将其用作 return 1 的基础,否则为 0。
有点晦涩,但它完成了工作。
这是一种非常不直观的方法来计算二进制数中有多少位等于“1”。
它需要二进制算术知识。从一个由“1”后跟一个或多个零组成的十进制数减去 1 时发生的情况开始:您得到一个 9 的序列,其长度等于零的数量:
1000000 - 1 = 999999
二进制数也会发生类似的事情。如果从非负二进制数中减去 1,则所有最低的“0”数字都将替换为“1”,并且这些零之前的“1”将替换为零。这遵循以二进制进行借用的方式。示例:
0101_0000_0001_0000 - 1 = 0101_0000_0000_1111
aaaa aaaa aaab cccc -> aaaa aaaa aaab cccc
符号:下划线以提高易读性。出现在字母 a 上方的所有数字均保持不变。出现在字母 b 上方的数字“1”更改为“0”。而出现在字母c上方的数字'0'被更改为'1'。
下一步是对两个数字 (X) 和 (X-1) 进行按位与运算。使用上述算术 属性,在每次迭代中,只有一个数字“1”从数字中消失(从右边开始,即最低有效位)。
通过计算迭代次数,我们可以知道数字 X 中最初出现了多少个“1”位。当变量 X 等于 0 时,迭代停止。
其他人已经回答了关于格雷码的问题。我的回答只解释了 "bit counting" 是如何工作的(在对两个值进行异或之后)。
这是针对特定格雷码单调排序(二进制反射格雷码)的简单测试:
// convert Gray code binary number to base 2 binary number
int Base2(byte Gray){ Gray^=Gray>>4; Gray^=Gray>>2; return Gray^=Gray>>1; }
// test if Gray codes are consecutive using "normal" base 2 numbers
boolean GraysAdjacent(byte x, byte y){ return 1 == abs(Base2(x)-Base2(y)); }
特别看看这个答案(最佳):
How to find if two numbers are consecutive numbers in gray code sequence
在 C 中编码为:
int GraysTouch(byte x, byte y){ return !( (x^y ^ 1) && ( x^y ^ (y&-y)<<1 ) ); }
// test x marks the spots! (where they touch!)
for(int i=31; i>-1; --i )
for(int j=31; j>-1; --j )
Serial.print((String)(GraysTouch( i^i>>1, j^j>>1 )?"x":".") +
(GraysTouch( j^j>>1, i^i>>1 )?"X":".") + (j?"":"\n"));
如何这个工作:...将被解释并且不是 OP代码因为它非常可疑(请参阅下面的注意事项评论)。
XOR
的 属性,又名 ^
运算符,匹配的位是 0
,不同的位是 1
。
1^0 == 0^1 == 1
1^1 == 0^0 == 0
此外,0 XOR b
暂时用作身份函数或简单地 b
和
1 XOR b
用作补充(请不要恭维)函数或 ~b
。
id(x) == x == x^0
opposite(x) == ~x == x^11111111 Why eight 1's? Are eight enough?
当比较两个位串与XOR
时,XOR
与1
不同的位,否则必须匹配并且XOR
是 0
:
0101 0001111001100111000
XOR 0011 XOR 0001111001100000111
------ ---------------------
0110 0000000000000111111
这解释了上面代码的 x^y
部分。
-------------------------------------------- ------------------------
题外话:
n^n>>1
进行从基数 2 二进制数到此处使用的格雷码二进制数的快速转换。
还要注意 f(a,b)=a^b^b=a
对于任何 b
!
是幂等的
那么就地交换是 a=a^b; b=a^b; a=a^b;
.
展开 c=a^b; d=c^b; e=c^d;
即。 d=a^b^b=a; e=a^b^a=b;
-------------------------------------------- --------------------------
现在,根据定义,对于相邻或连续的两个格雷码数,必须一位并且只有一位可以改变,与众不同。
例子:
Johnson
Code
000 000 000 000
001 001 001 100
011 101 011 110
111 111 010 010
110 011 110 011
100 010 111 111
110 101 101
100 100 001
^^^
this Gray coding
is the one used here
仔细检查。
案例一
当连续数的最低位x
和y
,对于any格雷码,其余必须一样!这是格雷码的定义。这意味着 x^y
必须 看起来像 0000...0001。
还记得补码,~
函数又名 1^b
吗?要测试最后一位 x^y
是 XOR
和 1
。
这解释了 x^y ^ 1
。
-----------------------------------------
案例二
连续的格雷码数x
和y
中不同位的位置不是最低位。仔细看这些格雷码连续数字。
001 010 101 lower order bits all match
011 110 111
| | | <-- | mark location of lowest 1
010 100 010 <-- XOR's
有趣的是,在this格雷码中,当最低位匹配x
和y
时,最低位的位置也匹配1
。
更有趣的是,对于连续的数字,总是不同(对于this格雷码)下一个高位位位置!
所以,x^y
看起来像 ???...?1000...0
其中 1000...0
必须至少有一个 0,10
(为什么?)和 ???...?
是谜连续个格雷码数的位必须是000...0
。 (为什么?即连续 x^y
必须看起来像...)
观察到
x^y looks like ???...?100...0 if and only if
x and y look like ???...?:10...0
| <-- remember? the 1 location !!
|
位置可以通过 x&-x
或 y&-y
找到。 (为什么?为什么 -
必须使用 2 的补码机来完成?)
但是,必须检查 :
位置以查看它是 1
(为什么?)并且 ???...?
是 000...0
。 (为什么?)
所以,
x^y looks like ???...?100...0 and
(y&-y)<<1 looks like 000...0100...0
这解释了 x^y ^ ((y&-y)<<1)
测试。
-------------------------------------------- ----------------------
为何如此有效:...是此处使用的特定格雷码的属性的结果。关于为什么这个格雷码应该具有这些性质,检查和解释太复杂了,不能在这里给出。
---------------------------------------- ------------------------------
由于 OP 代码问题,对先前答案的不足之处进行评论。
警告 1: 明确地说,OP 问题中的算法:
private static int graycode(byte term1, byte term2) {
byte x = (byte)(term1^term2); // why use XOR?
int count = 0;
while(x!=0)
{
x = (byte)(x &(x-1)); // why use bitwise operator?
count++; // what is count?
}
return count == 1;
}
对连续的格雷码有一个有趣的解释。当任何两个二进制序列在单个位位置不同时,它确实会正确报告。
如果连续代码意味着格雷码用于枚举单调排序,则存在问题。
具体来说,代码将为所有这些对 return true
:
000, 001 or 000, 010 or 000, 100
所以排序可能是 001, 000, 010
但是 100
可以去哪里?
该算法(正确地)报告 100
的 "consecutiveness" 与 001 or 010
之一是 false
。
因此 100
在枚举中必须紧跟在 000
之前或之后,但不能紧跟在 001
或 010
之前或之后。 DOH!!!
警告 2: 注意 x = (byte)(x & (x-1))
重置 lowest 顺序 1 位x
到零。
参考文献:
Gray code increment function
https://electronics.stackexchange.com/questions/26677/3bit-gray-counter-using-d-flip-flops-and-logic-gates
How do I find next bit to change in a Gray code in constant time?
How to find if two numbers are consecutive numbers in gray code sequence