虽然有多种方法可以在一个字节中反转位顺序,但我很好奇开发人员实现的"最简单".通过颠倒我的意思是:
1110 -> 0111
0010 -> 0100
Run Code Online (Sandbox Code Playgroud)
这与此 PHP问题类似,但不重复.
这与此 C问题类似,但不重复.这个问题要求开发人员实施最简单的方法."最佳算法"涉及内存和CPU性能.
LOOP(英特尔参考手动输入)递减ecx/rcx,然后如果非零则跳转.这很慢,但是英特尔不能廉价地把它变得很快吗? dec/jnz
已经将宏观融合成 Sandybridge家族的一个 uop; 唯一的区别是设置标志.
loop
关于各种微体系结构,来自Agner Fog的说明表:
Bulldozer-family/Ryzen:1 m-op(与宏观融合测试和分支相同,或者jecxz
)
P4:4次(相同jecxz
)
loope
/ loopne
).吞吐量= 4c(loop
)或7c(loope/ne
).loope
/ loopne
). 吞吐量=每5个循环一个,这是将循环计数器保留在内存中的瓶颈!jecxz
只有2 uops,吞吐量与普通吞吐量相同jcc
难道解码器不能像lea rcx, [rcx-1]
/ 那样解码jrcxz
吗?这将是3 uops.至少那是没有地址大小前缀的情况,否则它必须使用ecx
和截断RIP
,EIP
如果跳转; 也许奇怪的地址大小选择控制减量的宽度解释了许多uops?
或者更好,只需将其解码为不设置标志的融合分支和分支? dec ecx …
给定一个十进制整数(例如65),如何反转Python中的底层位?即.以下操作:
65 ? 01000001 ? 10000010 ? 130
Run Code Online (Sandbox Code Playgroud)
看来这个任务可以分为三个步骤:
步骤#2和3似乎很简单(见本和本 SO问题关系到步骤#2),但我卡上的步骤1#.步骤#1的问题是检索带有填充零的完整十进制表示(即65 = 01000001,而不是1000001).
我四处寻找,但似乎找不到任何东西.
例如,我有二进制数1011,它等于十进制11.我希望反向位的位置使它变为1101,即十进制13.这是代码:
import java.util.*;
public class bits {
public static void main(String[] args) {
Scanner scnr=new Scanner(System.in);
System.out.println("enter x:");
int x=scnr.nextInt();
int b=0;
while (x!=0){
b|=( x &1);
x>>=1;
b<<=1;
}
System.out.println(b);
}
}
Run Code Online (Sandbox Code Playgroud)
但是当我输入x 11然后它打印出来26.这是什么错误?
我正在使用一些遗留代码,我遇到了一个函数,它显然用于在任意长的字段上执行网络字节顺序转换(大于ntohl可以处理的).
我无法理解它是否足以告诉它是否正在执行除了在msg缓冲区范围内反转字节顺序之外的任何事情(或者即使它会可靠地执行此操作).有人可以帮助我分解并分析它,以便我可以用更易于理解的东西(或者至少评论它)替换它!
void swapit(unsigned char *msg, int length) {
for(;length>0;length--, msg++) {
*msg = ((*msg * 0x0802LU & 0x22110LU) |
(*msg * 0x8020LU & 0x88440LU)) *
0x10101LU >> 16;
}
}
Run Code Online (Sandbox Code Playgroud) 我转换的无符号整数使用位运算符为二进制,和目前还整数&1,以检查是否比特是1或0,并且输出,然后通过1右移由2.然而的位被以错误的顺序返回到划分(反转),所以我想在开始之前反转整数中的位顺序.
有一个简单的方法吗?
示例:如果我给了unsigned int 10 = 1010
while (x not eq 0)
if (x & 1)
output a '1'
else
output a '0'
right shift x by 1
Run Code Online (Sandbox Code Playgroud)
这会返回0101这是不正确的...所以我想在运行循环之前反转最初的位顺序,但我不确定如何做到这一点?
我在C++中有二进制矩阵,我用8位值向量重复.
例如,以下矩阵:
1 0 1 0 1 0 1
0 1 1 0 0 1 1
0 0 0 1 1 1 1
Run Code Online (Sandbox Code Playgroud)
表示为:
const uint8_t matrix[] = {
0b01010101,
0b00110011,
0b00001111,
};
Run Code Online (Sandbox Code Playgroud)
我这样做的原因是因为然后计算这样的矩阵和8位向量的乘积变得非常简单和有效(每行只有一个按位AND和奇偶校验计算),这比单独计算每个位.
我现在正在寻找一种有效的方法来转置这样的矩阵,但是我无法弄清楚如何在不必手动计算每个位的情况下进行转换.
只是为了澄清一下,对于上面的例子,我想从转置中得到以下结果:
const uint8_t transposed[] = {
0b00000000,
0b00000100,
0b00000010,
0b00000110,
0b00000001,
0b00000101,
0b00000011,
0b00000111,
};
Run Code Online (Sandbox Code Playgroud)
注意:我更喜欢一种算法,它可以用任意大小的矩阵来计算,但我也对只能处理某些大小的算法感兴趣.
我正在将数字转换为二进制数,并且必须使用它putchar
来输出每个数字.
问题是我正在接受订单.
在做自己的后缀之前,有没有反转数字位模式?
因为在int中有一个特定的位模式 - 我该如何反转这个位模式?
你会怎么用C做的?(例如:如果我们必须镜像8位,则10110001变为10001101).某些处理器上是否有任何可以简化此任务的说明?
我必须计算汉明重量以获得相当快速的连续64位数据流,并且使用popcnt
汇编指令引起了我的一个例外,即我的英特尔酷睿i7-4650U.
我检查了我的圣经黑客的喜悦,并扫描了网络上的各种算法(因为他们在计算机诞生时开始解决这个'问题',所以这里有很多算法).
我在周末玩了一些我自己的想法并提出了这些算法,我几乎可以将数据移入和移出CPU.
//64-bit popcnt using BMI2
_popcnt_bmi2:
mov (%rdi),%r11
pext %r11,%r11,%r11
not %r11
tzcnt %r11,%r11
mov %r11,(%rdx)
add $8h,%rdi
add $8h,%rdx
dec %rsi
jnz _popcnt_bmi2
ret
Run Code Online (Sandbox Code Playgroud)
在上面的代码中我使用pext
(BMI2),其中输入数据使用自身作为掩码.然后,所有存在的位将从结果寄存器中的最低有效位(本身再次)开始崩溃.然后我需要计算折叠位的数量,所以我反转所有位然后tzcnt
用来计算现在为零的数量.我认为这是一个相当不错的主意.
然后我也尝试了AVX2方法:
//64-bit popcnt using AVX2
_popcnt_avx2:
vmovdqa (%rcx),%ymm2
add $20h,%rcx
vmovdqa (%rcx),%ymm3
add $20h,%rcx
vmovdqa (%rcx),%ymm4
popcnt_avx2_loop:
vmovdqa (%rdi),%ymm0
vpand %ymm0, %ymm2, %ymm1
vpandn %ymm0, %ymm2, %ymm0
vpsrld $4h,%ymm0, %ymm0
vpshufb %ymm1, %ymm3, %ymm1
vpshufb %ymm0, %ymm3, %ymm0
vpaddb %ymm1,%ymm0,%ymm0 //popcnt (8-bits)
vpsadbw %ymm0,%ymm4,%ymm0 //popcnt (64-bits) …
Run Code Online (Sandbox Code Playgroud) c ×4
assembly ×3
c++ ×3
binary ×2
performance ×2
avx ×1
int ×1
intel ×1
java ×1
math ×1
matrix ×1
networking ×1
optimization ×1
python ×1
python-2.7 ×1
simd ×1
transpose ×1
unsigned ×1
x86 ×1