在第2章,关于按位运算符的部分(第2.9节),我无法理解其中一个示例方法是如何工作的.
这是提供的方法:
unsigned int getbits(unsigned int x, int p, int n) {
return (x >> (p + 1 - n)) & ~(~0 << n);
}
Run Code Online (Sandbox Code Playgroud)
这个想法是,对于给定的数字x,它将返回从位置p开始的n位,从右边开始计数(最右边的位是位置0).给出以下方法:main()
int main(void) {
int x = 0xF994, p = 4, n = 3;
int z = getbits(x, p, n);
printf("getbits(%u (%x), %d, %d) = %u (%X)\n", x, x, p, n, z, z);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出是:
getbits(63892 (f994), 4, 3) = 5 (5)
我得到了部分内容,但我对"大局"感到困扰,主要是因为我不理解的比特(没有双关语).
我特别遇到问题的部分是补充部分:~(~0 << …
很多年前,在大学里,我学会了正确地按位移动实现与除以2相同的操作,但通常要快得多.自从9-10年前我了解到这一点以来,我不确定Java在这方面是如何出现的.Java编译器是否自动将二分频转换为位移操作,还是应该自己在代码中手动执行位移操作?
我有C代码,我在其中执行以下操作.
int nPosVal = +0xFFFF; // + Added for ease of understanding
int nNegVal = -0xFFFF; // - Added for valid reason
Run Code Online (Sandbox Code Playgroud)
现在,当我尝试
printf ("%d %d", nPosVal >> 1, nNegVal >> 1);
Run Code Online (Sandbox Code Playgroud)
我明白了
32767 -32768
Run Code Online (Sandbox Code Playgroud)
这是预期的吗?
我能够想到类似的东西
65535 >> 1 = (int) 32767.5 = 32767
-65535 >> 1 = (int) -32767.5 = -32768
Run Code Online (Sandbox Code Playgroud)
也就是说,-32767.5四舍五入为-32768.
这种理解是否正确?
我已经学会了如何使用80x86汇编程序,所以在逐位移位操作中,我遇到了SAL和SHL使用的问题.我的意思是代码行之间的区别如下:
MOV X, 0AAH
SAL X, 4
MOV X, 0AAH
SHL X, 4
Run Code Online (Sandbox Code Playgroud)
什么时候应该使用SHL和使用SAL?它们有什么区别?
我有一个关于Delphi中位移行为的问题(或者更可能是错误报告)(在Borland Delphi 7中测试过).
目标:使用任意数字向右执行"算术"按位移位.
这意味着必须扩展符号位 - 如果设置了一个数字的最高有效位,则将从左侧填充二进制数,而不是0.
因此,算术右移后的数字"-1"必须保持相同的数字(所有位= 1),但是"逻辑移位"(总是用零填充数字)必须给出最大正整数(最大正有符号整数) ,为了正确)
我只在32位系统上测试过它(Windows); 而且,我需要它以32位整数显式工作.
当源编号存储在变量中时,看起来Delphi中存在带有"shr"的内部错误.
我的示例代码:
program bug;
{$APPTYPE CONSOLE}
var
I:Integer;
C:Cardinal;
begin
I := -1; // we’ll need that later
C := $FFFFFFFF;
Run Code Online (Sandbox Code Playgroud)
(这只是开始).接下来,让我们尝试一些"shr":
Writeln('0) ', -1 shr 1 );
Writeln('1) ', $FFFFFFFF shr 1 );
Run Code Online (Sandbox Code Playgroud)
"-1"是等效于"$ FFFFFFFF"的签名.似乎"shr"行为(算术或逻辑)基于源号是签名还是不签名(整数或基数)的事实.
输出是:
0) -1
1) 2147483647
Run Code Online (Sandbox Code Playgroud)
非常正确.然后我需要尝试手动将这些数字转换为整数或基数:
Writeln('2) ', Integer(-1) shr 1 );
Writeln('3) ', Integer($FFFFFFFF) shr 1 );
Writeln('4) ', Cardinal(-1) shr 1 );
Writeln('5) ', Cardinal($FFFFFFFF) shr 1 ); …Run Code Online (Sandbox Code Playgroud) 关于负数的右移操作我很困惑,这里是代码.
int n = -15;
System.out.println(Integer.toBinaryString(n));
int mask = n >> 31;
System.out.println(Integer.toBinaryString(mask));
Run Code Online (Sandbox Code Playgroud)
结果是:
11111111111111111111111111110001
11111111111111111111111111111111
Run Code Online (Sandbox Code Playgroud)
为什么要将负数移31而不是1(符号位)?
java bit-manipulation bit-shift bitwise-operators negative-number
当我使用shift进行操作时,我最近发现了一种(奇怪的)行为>> <<!
为了解释它,让我编写这个小的可运行代码,执行两个应该相同的操作(在我的理解中),但我对不同的结果感到惊讶!
#include <stdio.h>
int main(void) {
unsigned char a=0x05, b=0x05;
// first operation
a = ((a<<7)>>7);
// second operation
b <<= 7;
b >>= 7;
printf("a=%X b=%X\n", a, b);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
跑步时,a = 5和b = 1.我希望它们都等于1!有人可以解释为什么我得到这样的结果?
PS:在我的环境中,大小unsigned char为1个字节
考虑以下Java代码片段
byte b=(byte) 0xf1;
byte c=(byte)(b>>4);
byte d=(byte) (b>>>4);
Run Code Online (Sandbox Code Playgroud)
输出:
c=0xff
d=0xff
Run Code Online (Sandbox Code Playgroud)
预期产量:
c=0x0f
Run Code Online (Sandbox Code Playgroud)
怎么样?为b二进制1111 0001
无符号右移之后0000 1111,因此0x0f,但为什么是0xff 怎么了?
考虑以下清单:
#include <type_traits>
#include <cstdint>
static_assert(std::is_same_v<decltype(31), int32_t>);
static_assert(std::is_same_v<decltype(31u), uint32_t>);
static_assert(std::is_same_v<decltype((signed char)1 << 1), int32_t>);
static_assert(std::is_same_v<decltype((signed char)1 << 1u), int32_t>);
static_assert(std::is_same_v<decltype((unsigned char)1 << 1), int32_t>);
// Signed result for unsigned char
static_assert(std::is_same_v<decltype((unsigned char)1 << 1u), int32_t>);
// But unsigned for uint32_t
static_assert(std::is_same_v<decltype(1u << 1u), uint32_t>);
Run Code Online (Sandbox Code Playgroud)
它可以与 GCC 和 Clang 很好地编译。我很困惑operator<<(uint8_t, uint32_t)。为什么要签署结果?