二进制反码求和java_简单又复杂的“整数类型”

本文探讨了二进制原码、反码和补码的概念及其在整数表示中的作用,通过实例分析了C语言中整数类型的大小、范围以及不同编译器下的差异。此外,还讨论了Java中整数类型的特点,包括固定字长、无unsigned类型以及char类型的特殊性,并展示了整数类型在Java和C语言中越界行为的实验结果。
摘要由CSDN通过智能技术生成

前言

因为一道题目让我不断地深追下去,挖出了我多年的噩梦——数据类型的范围与长度。每次都想得头痛,因为平台不同、编译器不同、编程语言不同等等因素,又没去做实验,网上那么多说法该相信谁都不知道……那不如趁现在就来详细地解决掉它吧。

一、原码、反码和补码

基础知识

相信在大学的《数字逻辑》课上都学过这个内容了,原码、反码和补码都是基于二进制而言的:

【原码】第1位表示符号位,其余位是这个数的绝对值。这是最简单能够马上想到的表示方式了。

【反码】正数的反码是其本身;负数的反码:在原码的基础上,符号位不变,其余位取反。

【补码】正数的补码是其本身;负数的补码:在原码的基础上,符号位不变,其余位取反,最后+1。

举个例子,假设整数在机器上是用8位二进制数表示的(8位就和我们经常说的32位、64位是一样的含义):

AAffA0nNPuCLAAAAAElFTkSuQmCC

为什么要用原码、反码和补码呢?

原码的来源

为了让二进制能够表示负数,产生了原码。

反码的来源

一个正数和一个负数运算需要辨别符号位,然而单独去辨别符号位会给电路设计带来极大的复杂度,因此人们想只设计加法电路,让符号位直接参与加法运算达到减法的目的,产生了反码。例如:3-2 = 3+(-2) = [0000 0011]反+[1111 1101]反 = [0000 0001]反 = [0000 0001]原=1(注意反码的加法当最高位进位的时候,最低位需要+1,不再详细描述,参考百度百科《二进制反码求和》)。这样符号位就能够参与运算了。

补码的来源

反码看起来很完美,但是仍然存在问题。例如3-3 = 3+(-3) = [0000 0011]反+[1111 1100]反 = [1111 1111]反 = [1000 0000]原=-0,而[0000 0000]反=[0000 0000]原 = +0,也就是说,零可以表示为两种形式,这种歧义同样不利于电路实现。并且由于反码的加减法还需要对溢出位进行处理,于是产生了补码。补码对溢出位直接丢弃,而0的表示只有一种[0000 0000]补,[1000 0000]补则看成是-128,解决了所有问题。

原码、反码和补码的范围问题

值得注意的是,8位的原码和反码都只能表示[-127, +127]范围内的整数,而补码可以表示[-128, +127]范围,多一个-128。这里的-128是计算得到的,而不是从反码推出的,-128根本无法用反码表示,却能够用补码计算,比如-127+(-1) = [1000 0001]补+[1111 1111]补 = [1000 0000]补。所以我们经常背的整数取值范围[-32768, +32767]之类的东西为什么负数总比整数的真值大1,就是这样来的。

计算机中按位取反会发生什么?

既然计算机表示的时候用的是补码,那么如果对十进制的整数【按位取反】操作到底操作的是补码还是二进制呢?

实验一下吧:printf("%d\n", ~(3));printf("%d\n", ~(-3));

【平台】windows 8 64位

【IDE】vs2013 32位

【语言】C语言

【取反操作】~

【取反结果】~3 = -4,~(-3) = 2

数值比较小,最高位没有影响,就按照8位来仔细观察第一组数据:

3 = [0000 0011]b = [0000 0011]

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值