为什么在实践中向右移动在霓虹灯和SSE中向左移动(反之亦然)
Why does shift right in practice shifts left (and viceversa) in Neon and SSE?
(注意,在Neon中,我使用这种数据类型是为了避免处理16位数据类型之间的转换)
为什么本质中的"左移"在实践中是"右移"?
// Values contained in a
// 141 138 145 147 144 140 147 153 154 147 149 146 155 152 147 152
b = vshlq_n_u32(a,8);
// Values contained in b
// 0 141 138 145 0 144 140 147 0 154 147 149 0 155 152 147
b = vshrq_n_u32(a,8);
// Values contained in b
// 138 145 147 0 140 147 153 0 147 149 146 0 152 147 152 0
我记得在使用_mm_slli_si128
时发现了同样的情况(尽管不同,但转换后的结果看起来像:
// b = _mm_slli_si128(a,1);
// 0 141 138 145 147 144 140 147 153 154 147 149 146 155 152 147
是因为endianness吗它会随着平台的变化而变化吗
你说"这是因为endianes吗",但这更多的是一种类型滥用的情况。您正在对机器在字节/字边界上的位顺序进行假设,以及对操作施加本地端序的非字节指令(您使用的是_u32指令,它要求值是无符号的32位值,而不是8位值的数组)。
正如您所说,您要求它通过/aask/it以32位为单位移位值来移位一系列无符号字符值。
不幸的是,如果你想对它们进行架构转换,你需要将它们按架构顺序排列。
否则,您可能需要查找blit或move指令,但在不支付体系结构成本的情况下,您不能人为地将机器类型强制到机器寄存器中。持久性只是你头疼的问题之一(对齐、填充等)
---后期编辑---
从根本上说,你混淆了字节和比特的移位,我们认为最重要的比特是"左"
bit number
87654321
hex
8421
00008421
00000001 = 0x01 (small, less significant)
10000000 = 0x80 (large, more significant)
但是,您正在移动的值是32位字,在小端序机器上,这意味着每个后续地址都会增加值的一个更有效的字节,对于32位字:
bit numbers
1111111111111111
87654321fedcba0987654321fedcba09
表示32位值0x0001
1111111111111111
87654321fedcba0987654321fedcba09
00000001000000000000000000000000
将其向左移动2个位置
00000001000000000000000000000000
v<
00000100000000000000000000000000
要将其向左移动另外8个位置,我们必须将其扭曲到下一个地址:
00000100000000000000000000000000
>>>>>>>v
00000000000001000000000000000000
如果你以字节为单位思考,这看起来像是一个右移。但我们告诉这个小端CPU,我们正在开发uint32,所以这意味着:
1111111111111111
87654321fedcba0987654321fedcba09
word01 word02 word03 word04
00000001000000000000000000000000 = 0x0001
00000100000000000000000000000000 = 0x0004
00000000000001000000000000000000 = 0x0400
问题是,这与8位值的本地数组的顺序不同,但您告诉CPU这些值是_u32,所以它使用了它的本机endianes进行操作。
这些内部函数的结果似乎取决于系统端序,因此,如果我们将代码移植到big-endian系统,我已经准备好了一个标志
#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
#pragma GCC error "Intrinsics used with little endian systems in mind. Start by reviewing all shifts operators."
#endif
请参阅在编译时检查字节序。
- 使用boost::multiprecision cpp_int左移时出现超时错误
- 警告:左移计数 >= 在 C++ 中将字节流读取为双精度变量时的类型宽度
- 左移<<如何在不同的功能中给出不同的结果?
- 使用 AVX2 指令左移 128 位数字
- <<(按位左移)在 Swift 中的数组上做什么?
- 带有左移操作员C 的意外输出
- 编译器将输出的流运算符<<解释为用于按位左移的二进制运算符<<
- 左移负整数为零是否有意义?
- 在 VS 移位中,UINT64 上的左移(64 >移位> 32)位仅 32 位
- C++20 是否为"overflow"的有符号整数很好地定义了左移?
- C++左移操作
- 为什么编译器左移 0
- 如何在位明智的操作中选择正确的左移
- 为什么很多人使用左移<<而不是乘法
- 左移 0 有什么意义
- 虽然左移运算符 (<<) 在 std::cout 之前使用,但它有什么用?
- 左移<<有些意外的行为
- 使用左移运算符将 F 转换为 FF
- 右移速度与左移相同的速度测试位
- Ruby和C++中的左移16位