我是否正确地说有符号和无符号整数之间的区别是:
还有其他差异吗?
在Oracle"原始数据类型" 页面中,它提到Java 8增加了对无符号整数和长整数的支持:
int:默认情况下,int数据类型是32位带符号的二进制补码整数,其最小值为-2 31,最大值为2 31 -1.在Java SE 8及更高版本中,您可以使用int数据类型表示无符号的32位整数,其最小值为0,最大值为2 32 -1.使用Integer该类将int数据类型用作无符号整数.有关更多信息,请参阅数字类一节.像静态方法compareUnsigned,divideUnsigned等已被添加到Integer类,以支持算术运算的无符号整数.
long:long数据类型是64位二进制补码整数.签名long的最小值为-2 63,最大值为2 63 -1.在Java SE 8及更高版本中,您可以使用long数据类型表示无符号64位long,其最小值为0,最大值为2 64 -1.当需要比int提供的值更宽的值时,请使用此数据类型.本Long类也包含类似的方法compareUnsigned,divideUnsigned等支持算术运算的无符号long.
但是,我发现无法声明无符号长整数或整数.例如,下面的代码给出了编译器错误消息"文字超出范围"(我当然使用的是Java 8),当它应该在范围内时(指定的值恰好是2 64 -1) :
public class Foo {
static long values = 18446744073709551615L;
public static void main(String[] args){
System.out.println(values);
}
} …Run Code Online (Sandbox Code Playgroud) 我不理解JG/JNLE/JL/JNGECMP之后的说明.
例如,如果我有:
CMP al,dl
jg label1
Run Code Online (Sandbox Code Playgroud)
当al=101; dl =200.
我们问jg什么?是al>dl吗?还是al-dl>0?
在下一个代码上相同的prolbem:
test al,dl
jg label1
Run Code Online (Sandbox Code Playgroud)
我不明白我们比较什么,以及我们问什么" jg".
换句话说,我不明白我们何时会跳转到label1,何时不会.
谢谢.
我认为2的补码的重点是对于有符号和无符号数字的操作可以采用相同的方式.维基百科甚至特别列出了多重作为其中一项有益的操作.那么为什么x86对每个都有单独的指令,mul并且imul?x86-64仍然如此吗?
Visual Studio或Visual C++ Express的现代(2008/2010)版本是否会在编译代码中生成x86 MUL指令(无符号乘法)?我似乎无法找到或设想它们出现在编译代码中的示例,即使使用无符号类型也是如此.
如果VS不使用MUL进行编译,是否有理由说明原因?
在汇编编程中,想要从寄存器的低位计算某些东西是相当普遍的,这些位不能保证将其他位置零.在像C这样的高级语言中,你只需将输入转换为小尺寸,让编译器决定是否需要分别将每个输入的高位归零,或者是否可以在输出之后切断结果的高位.事实.
这是为x86-64的(又名AMD64),出于各种原因尤其常见1,其中的一些是存在于其它的ISA.
我将使用64位x86作为示例,但目的是询问/讨论2的补码和无符号二进制算法,因为所有现代CPU都使用它.(注意,C和C++不保证两个补码4,并且有符号溢出是未定义的行为.)
作为示例,考虑一个可以编译为LEA指令2的简单函数.(在X86-64 SysV的(Linux)的ABI 3,前两个函数参数是rdi和rsi,与在返回rax. int是一个32位的类型.)
; int intfunc(int a, int b) { return a + b*4 + 3; }
intfunc:
lea eax, [edi + esi*4 + 3] ; the obvious choice, but gcc can do better
ret
Run Code Online (Sandbox Code Playgroud)
gcc知道即使是负有符号整数,加法也只是从右到左,所以输入的高位不会影响进入的内容eax.因此,它保存了一个指令字节并使用 lea eax, [rdi + rsi*4 + 3]
为什么它有效?
1为什么x86-64频繁出现这种情况:x86-64有可变长度指令,其中额外的前缀字节改变了操作数大小(从32到64或16),因此在指令中通常可以保存一个字节.以相同的速度执行.当写入低8b或16b的寄存器(或稍后读取完整寄存器(Intel pre-IvB)时的失速)时,它也具有错误依赖性(AMD/P4/Silvermont):由于历史原因, …
我创建了一个使用SIMD进行64位*64位到128位的功能.目前我已经使用SSE2(acutally SSE4.1)实现了它.这意味着它可以同时运行两个64b*64b到128b的产品.同样的想法可以扩展到AVX2或AVX512,同时提供四个或八个64b*64到128b的产品.我的算法基于http://www.hackersdelight.org/hdcodetxt/muldws.c.txt
该算法进行一次无符号乘法,一次有符号乘法和两次有符号*无符号乘法.签名的*signed和unsigned*unsigned操作很容易使用_mm_mul_epi32和_mm_mul_epu32.但混合签名和未签名的产品给我带来了麻烦.例如,考虑一下.
int32_t x = 0x80000000;
uint32_t y = 0x7fffffff;
int64_t z = (int64_t)x*y;
Run Code Online (Sandbox Code Playgroud)
双字产品应该是0xc000000080000000.但是如果你假设你的编译器知道如何处理混合类型,你怎么能得到这个呢?这就是我想出的:
int64_t sign = x<0; sign*=-1; //get the sign and make it all ones
uint32_t t = abs(x); //if x<0 take two's complement again
uint64_t prod = (uint64_t)t*y; //unsigned product
int64_t z = (prod ^ sign) - sign; //take two's complement based on the sign
Run Code Online (Sandbox Code Playgroud)
使用SSE可以这样做
__m128i xh; //(xl2, xh2, xl1, xh1) high is signed, low unsigned
__m128i …Run Code Online (Sandbox Code Playgroud) 正如标题中所述,为什么ARM指令集仅区分有符号和无符号?
SDIV和UDIV可用,但ADD,SUB和MUL不是这种情况.
我在看一本教科书,上面写着:
重要的是要注意机器代码如何区分有符号和无符号值。与 C 不同,它不将数据类型与每个程序值相关联。相反,它主要对这两种情况使用相同的(汇编)指令,因为许多算术运算对于无符号和补码算术具有相同的位级行为。
我不明白这是什么意思,谁能给我举个例子?