是否可以仅使用按位运算符来测试数字是偶数还是“1”?
Is it possible to test if a number is either even or '1', using only bitwise operators?
是否可以仅使用按位运算符实现,即不使用 logical/comparison/relation 运算符?
这基本上等同于以下内容。
(a & 1 == 0) || (a == 1)
我接受在许多语言中可能需要进行最终相等性比较才能将结果转换为 true/false 值,但我在问题中并未考虑这一点。
接受输入位数组和 returns 与“1”相同的偶数输出位数组的答案基本上就是我所追求的。要么是那个,要么是不可能的原因。
((a & 1) == 0) | (a == 1)
有效。无需做任何复杂的技巧
虽然我根本不建议这样做,但我能够在 C 中实现它,但只需要将 a
设为 unsigned char
。它也可以与其他人一起使用,但这会延长条件。
#include <stdio.h>
int main() {
for (unsigned char a = 0; a < 255; a++) {
if ((~a & 1) | (1 >> (a & 0x0E | a >> 4)))
printf ("%d is even or 1\n", a);
else
printf("%d is odd\n", a);
}
return 0;
}
如果 a
是偶数,(~a & 1)
将产生 1
。当 a
为 1
或 0
时,(a & 0x0E | a >> 4)
将产生 0
。因此在那些情况下 (1 >> (a & 0x0E | a >> 4)))
将是 (1 >> 0)
即 1
,否则移位值介于 1
和 15
之间,因此使表达式 0
.
我最初的方法是 (1 >> (a >> 1))
,但很快意识到这会导致移位溢出,因为移位量超过了可能的最大值。不仅发出警告,而且实际上错误地将每个 n * 64 + 1
值识别为偶数。因此,更复杂的方法是通过 OR -ing a
高 4 位及其低 4 位,但将 LSB 设置为 0
来限制移位量小于 64
。当 a
为 1
或 0
时,此结果数字为 <= 15
且仅 0
。
我不完全确定我明白你在问什么,但在 Intel64/AMD64/x86_64 指令集中,很容易执行一系列按位操作,这些操作将 return 一个值和一个允许进行比较的条件代码标志。
假设输入值在 %rax 寄存器中。
MOV %rax, %r8 # replicate input value into %r8
MOV %rax, %r9 # replicate input value into %r9
AND [=10=]x1, %r8 # AND 0x1 with the contents of %r8 and put result in %r8
XOR [=10=]x1, %r9 # XOR 0x1 with the contents of %r9 and put result in %r9
OR %r8, %r9 # OR %r8 with %r9 and put result in %r9
如果输入为偶数,AND 运算将return 0,否则将return 1。
如果输入为 0x1,XOR 运算将 return 0,否则它 return 非零。
如果 %r8 和 %r9 都为零,则 OR 运算将 return 0,否则它 return 非零。
每个按位运算都会设置各种条件标志。此处相关的称为 "ZF",当运算结果为 0 时设置为 1。
最终操作设置的ZF标志可用于控制条件分支。如果 ZF=1(即条件为真),则使用 "JZ"(如果为零则跳转)或如果条件不为真则使用 "JNZ"(如果不为零则跳转)进行分支。
您可以将 %r9 的结果保存到内存中,稍后在与零 (true) 或非零 (false) 进行比较时使用它。
您也可以在不使用条件分支指令的情况下对结果进行操作——相同的条件代码可用于控制条件移动指令。当且仅当 ZF=1 时,CMOVE 指令会将内存或寄存器中的输入操作数复制到输出寄存器,或者当当且仅当 ZF=0 时,CMOVNE 将执行复制。例如,如果条件为真,您可以将值“1”从源寄存器复制到目标寄存器,然后将目标寄存器值累加到累加器中。然后累加器将包含比较 returned "True".
的案例计数
适用于任何固定(2 的幂)位宽的方法是使用以下函数,其中 returns 设置所有位时为 1,否则为 0:
uint32_t allOnes(uint32_t a) {
a &= a >> 1;
a &= a >> 2;
a &= a >> 4;
a &= a >> 8;
a &= a >> 16;
return a;
}
然后我们可以进行如下检查:
uint32_t f1(uint32_t a) {
return (~a & 1) | allOnes(a ^ ~uint32_t(1));
}
是否可以仅使用按位运算符实现,即不使用 logical/comparison/relation 运算符?
这基本上等同于以下内容。
(a & 1 == 0) || (a == 1)
我接受在许多语言中可能需要进行最终相等性比较才能将结果转换为 true/false 值,但我在问题中并未考虑这一点。 接受输入位数组和 returns 与“1”相同的偶数输出位数组的答案基本上就是我所追求的。要么是那个,要么是不可能的原因。
((a & 1) == 0) | (a == 1)
有效。无需做任何复杂的技巧
虽然我根本不建议这样做,但我能够在 C 中实现它,但只需要将 a
设为 unsigned char
。它也可以与其他人一起使用,但这会延长条件。
#include <stdio.h>
int main() {
for (unsigned char a = 0; a < 255; a++) {
if ((~a & 1) | (1 >> (a & 0x0E | a >> 4)))
printf ("%d is even or 1\n", a);
else
printf("%d is odd\n", a);
}
return 0;
}
如果 a
是偶数,(~a & 1)
将产生 1
。当 a
为 1
或 0
时,(a & 0x0E | a >> 4)
将产生 0
。因此在那些情况下 (1 >> (a & 0x0E | a >> 4)))
将是 (1 >> 0)
即 1
,否则移位值介于 1
和 15
之间,因此使表达式 0
.
我最初的方法是 (1 >> (a >> 1))
,但很快意识到这会导致移位溢出,因为移位量超过了可能的最大值。不仅发出警告,而且实际上错误地将每个 n * 64 + 1
值识别为偶数。因此,更复杂的方法是通过 OR -ing a
高 4 位及其低 4 位,但将 LSB 设置为 0
来限制移位量小于 64
。当 a
为 1
或 0
时,此结果数字为 <= 15
且仅 0
。
我不完全确定我明白你在问什么,但在 Intel64/AMD64/x86_64 指令集中,很容易执行一系列按位操作,这些操作将 return 一个值和一个允许进行比较的条件代码标志。
假设输入值在 %rax 寄存器中。
MOV %rax, %r8 # replicate input value into %r8
MOV %rax, %r9 # replicate input value into %r9
AND [=10=]x1, %r8 # AND 0x1 with the contents of %r8 and put result in %r8
XOR [=10=]x1, %r9 # XOR 0x1 with the contents of %r9 and put result in %r9
OR %r8, %r9 # OR %r8 with %r9 and put result in %r9
如果输入为偶数,AND 运算将return 0,否则将return 1。 如果输入为 0x1,XOR 运算将 return 0,否则它 return 非零。 如果 %r8 和 %r9 都为零,则 OR 运算将 return 0,否则它 return 非零。
每个按位运算都会设置各种条件标志。此处相关的称为 "ZF",当运算结果为 0 时设置为 1。
最终操作设置的ZF标志可用于控制条件分支。如果 ZF=1(即条件为真),则使用 "JZ"(如果为零则跳转)或如果条件不为真则使用 "JNZ"(如果不为零则跳转)进行分支。
您可以将 %r9 的结果保存到内存中,稍后在与零 (true) 或非零 (false) 进行比较时使用它。
您也可以在不使用条件分支指令的情况下对结果进行操作——相同的条件代码可用于控制条件移动指令。当且仅当 ZF=1 时,CMOVE 指令会将内存或寄存器中的输入操作数复制到输出寄存器,或者当当且仅当 ZF=0 时,CMOVNE 将执行复制。例如,如果条件为真,您可以将值“1”从源寄存器复制到目标寄存器,然后将目标寄存器值累加到累加器中。然后累加器将包含比较 returned "True".
的案例计数适用于任何固定(2 的幂)位宽的方法是使用以下函数,其中 returns 设置所有位时为 1,否则为 0:
uint32_t allOnes(uint32_t a) {
a &= a >> 1;
a &= a >> 2;
a &= a >> 4;
a &= a >> 8;
a &= a >> 16;
return a;
}
然后我们可以进行如下检查:
uint32_t f1(uint32_t a) {
return (~a & 1) | allOnes(a ^ ~uint32_t(1));
}