我们先看一个题目

#include<stdio.h>int main()
{unsigned a,b,c,d;   //或者   int a,b,c,d;a=0x8;b=a>>1;c=~(~0<<1);d=b&c;printf("c is %d\n",c);printf("d is %d\n",d);
}


假设计算机是存储八位

0的存储是   0b 0000 0000
~按位取反   0b 1111 1111
左移一位    0b 1111 1110     空档处补0
再按位取反  0b 0000 0001所以c就等于1

这里是一步一步推导过来的,你会忽略一个关键的过程,就是~0你算出来是
0b 1111 1111,一个很大的负数,这和你以为的常理违背,我们下面讨论。

再次举例

#include <stdio.h>
int main()
{printf("~0 == %d\n", ~0);
}

0的存储是   0b 0000 0000
~按位取反   0b 1111 1111

这个题目比较干脆,直接是~0 == -1,有的时候我们不明白,为什么0b 1111 1111在内存中代表-1,因为他无论如何也是一个很大的负数才对。

可是实际上,负数在内存中是按照补码的形式存储的,也就是说0b 1111 1111是一个补码,那么它的反码就是0b 1111 1110,原码就是0b 1000 0001,也就是-1(注意负数求反码补码的时候符号位不变)

所以结论

0b 1111 1111 == -1 (~0)0b 1111 1110 == -2 (~1)0b 1111 1101 == -3 (~2)

可以把它当做一个公式 ~a == -【a+1】

补充说明

为什么整数要在内存中按照补码储存。因为正数的原码反码补码都一样,所以我们主要讨论问什么负数在内存中按照补码方式存储。

采用补码的原因或好处如下,采用补码运算具有如下两个特征:

1)因为使用补码可以将符号位和其他位统一处理,同时,减法也可以按加法来处理,即如果是补码表示的数,不管是加减法都直接用加法运算即可实现。

2)两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位被舍弃。

这样的运算有两个好处:

1)使符号位能与有效值部分一起参加运算,从而简化运算规则。从而可以简化运算器的结构,提高运算速度;(减法运算可以用加法运算表示出来。)

2)加法运算比减法运算更易于实现。使减法运算转换为加法运算,进一步简化计算机中运算器的线路设计。

用带符号位的原码进行乘除运算时结果正确,而在加减运算的时候就出现了问题,如下: 假设字长为8bits

( 1 ) - ( 1 ) = ( 1 ) + ( -1 ) = ( 0 )

(00000001)原 + (10000001)原 = (10000010)原 = ( -2 ) 显然不正确.。

因为在两个整数的加法运算中是没有问题的,于是就发现问题出现在带符号位的负数身上,对除符号位外的其余各位逐位取反就产生了反码。反码的取值空间和原码相同且一一对应。下面是反码的减法运算:

( 1 ) - ( 1 ) = ( 1 ) + ( -1 ) = ( 0 )

(00000001) 反+ (11111110)反 = (11111111)反 = ( -0 ) 有问题。

( 1 ) - ( 2) = ( 1 ) + ( -2 ) = ( -1 )

(00000001) 反+ (11111101)反 = (11111110)反 = ( -1 ) 正确

问题出现在(+0)和(-0)上,在人们的计算概念中零是没有正负之分的。

于是就引入了补码概念。负数的补码就是对反码加一,而正数不变,正数的原码反码补码是一样的。在补码中用(-128)代替了(-0),所以补码的表示范围为:

(-128~127)共256个。

注意:(-128)没有相对应的原码和反码, (-128) = (10000000) 补码的加减运算如下:

( 1 ) - ( 1 ) = ( 1 ) + ( -1 ) = ( 0 )

(00000001)补 + (11111111)补 = (00000000)补 = ( 0 ) 正确

( 1 ) - ( 2) = ( 1 ) + ( -2 ) = ( -1 )

(00000001) 补+ (11111110) 补= (11111111)补 = ( -1 ) 正确

采用补码表示还有另外一个原因,那就是为了防止0的机器数有两个编码。原码和反码表示的0有两种形式+0和-0,而我们知道,+0和-0是相同的。这样,8位的原码和反码表示的整数的范围就是-127-127(11111111-01111111),而采用补码表示的时候,00000000是+0,即0;10000000不再是-0,而是-128,这样,补码表示的数的范围就是-128~+127了,不但增加了一个数得表示范围,而且还保证了0编码的唯一性。

为什么正数的反码,补码和原码一样

这是规定 或者说这是约定,没有多少道理,你算是算不出来的。

补码只是为 负数 想出来的办法,目的是减法变加法。是减法可以 用 加补码 的方法实现。补码 可用反码加1得来。于是道又有了 负数的反码。

计算机里有硬件“加法器”,有了补码,减法 也可以 用 加法器 做了。计算机 里运算速度,硬件远快于软件。这是弄出反码,补码和原码花样的原因。

形象说明

引进补码的作用是为了让计算机更方便做减法
比如说,按时间12个小时来算
现在的准确时间是4点
有一个表显示的是7点
要校准时间,我们可以将时针退7-4=3格,也可以向前拨12-3=9格
计算机做减法就可以转化成-3=+9
这样可以简化计算机的硬件设备去做复杂的减法

~0 == -1 问题全解相关推荐

  1. zabbix 3.0 完全安装全解!

    环境准备: centos 6.5 x86_x64 安装依赖库文件 yum -y install mysql-devel net-snmp-devel curl curl-devel gcc pcre- ...

  2. Servlet3.0新特性全解

    tomcat 7以上的版本都支持Servlet 3.0 Servlet 3.0 新增特性 注解支持:Servlet.Filter.Listener无需在web.xml中进行配置,可以通过对应注解进行配 ...

  3. 稳扎稳打Silverlight(18) - 2.0视频之详解MediaElement, 开发一个简易版的全功能播放器...

    [索引页] [×××] 稳扎稳打Silverlight(18) - 2.0视频之详解MediaElement, 开发一个简易版的全功能播放器 作者:webabcd 介绍 Silverlight 2.0 ...

  4. atca背板_ATCA介绍全解.ppt

    ATCA介绍全解 ATCA - 概述Advanced Telecommunications Computing Architecture 高性能计算机和网络通信设备的要求: 1) 足够强的数据处理能力 ...

  5. Java IO编程全解(五)——AIO编程

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7794151.html 前面讲到:Java IO编程全解(四)--NIO编程 NIO2.0引入了新的异步通道的 ...

  6. html5相关介绍ppt,html5介绍全解.ppt

    html5介绍全解 渐变 (Gradients) 线性渐变: background: linear-gradient(to right, red, orange, yellow, green, blu ...

  7. 人工操作阶段计算机是如何工作的,第一章计算机基础概述全解.ppt

    第一章计算机基础概述全解 1.2.3 汉字编码 汉字的编码 国标码:中文内码之一,汉字信息交换的标准编码.国标码是不可能在计算机内部直接采用.于是, 汉字的机内码采用变形国标码 . 国标码:作为转换为 ...

  8. python100个必背知识-python编程面试中必考的知识点,数据类型全解,笔记超全面...

    原标题:python编程面试中必考的知识点,数据类型全解,笔记超全面 python作为一门高级编程语言,它的定位是优雅.明确和简单.阅读Python编写的代码感觉像在阅读英语一样,这让使用者可以专注于 ...

  9. python中的format什么意思中文-Python中format()格式输出全解

    格式化输出:format() format():把传统的%替换为{}来实现格式化输出 1.使用位置参数:就是在字符串中把需要输出的变量值用{}来代替,然后用format()来修改使之成为想要的字符串, ...

  10. Java数据类型转换全解

    Java数据类型转换全解 我们知道Java语言是典型的支持面向对象的程序语言,但考虑到有些基本Java数据类型的结构简单,占内存小且存取速度快等优点,Java依然提供了对这些非面向对象的简单Java数 ...

最新文章

  1. Python学习笔记(八)—使用正则获取网页中所需要的信息。
  2. “十四五”要建设的「交通强国」,会让我们都坐上自动驾驶车么?
  3. 电大2007计算机机考专科试题,中央电大2007-2008学年度第一学期期末考试计算机网络专业计算机网络试题2008年1月...
  4. c++学习笔记之指针
  5. .NET Core 实现定时抓取博客园首页文章信息并发送到邮箱
  6. 为什么一流成功人士的闹钟都定在早晨5:57?
  7. java类编写sql_用JavaBean编写SQL Server数据库连接类
  8. 【Android Studio安装部署系列】二十三、Android studio查看Gradle版本号
  9. 距离之和最小 V3 51Nod - 1110(带权中位数或者爆搜)
  10. linux网络服务错误6026,wpa_supplicant/wpa_cli无法检测到接入点的错误密钥
  11. 多线程的Lock锁——ReentrantReadWriteLock
  12. VS Code 取色器 插件 颜色选取
  13. 软著【设计说明书】(软件著作权)
  14. taxi计费器c语言程序,基于单片机的出租车计费器的设计(附实物图,原理图,程序)...
  15. 美国区块链与药品供应链管理的应用案例
  16. 中国企业家:TD-SCDMA的坎坷商业路
  17. docker-1 常用命令
  18. poj 3067 Japan
  19. java计算机毕业设计自习室座位预约管理源码+mysql数据库+系统+lw文档+部署
  20. Linux—教你两个方法轻松找回root密码

热门文章

  1. List<String> 查找重复记录
  2. ios根号怎么打_ios计算器开根号 苹果手机计算器怎么开根号 详情介绍
  3. android 脚本运行程序,用android app运行脚本
  4. Python坐标系转换
  5. 附件上传后台报The field uploadFile exceeds its maximum permitted size of 1048576 bytes.
  6. 树莓派装Aria2和YAAW实现无人值守远程离线下载服务
  7. python房屋租赁系统的设计与实现_毕业设计---在线房屋租赁系统的设计与实现.doc...
  8. 【深度学习笔记】理解Bicubic,双三次插值
  9. 踏雪点圣火,冰雕刻五环!揭秘全球刷屏的冬奥开幕式黑科技
  10. db2去除字段值的空格_sql trim()函数去掉两头空格