从JavaScript的移位运算看数字在计算机内部的编码——补码
2014-02-19 21:47
337 查看
偶然看到一个JavaScript的题目:
js中13>>2=? -13>>2=?
在浏览器中很容易测试出答案分别是 3 和 -4。
13>>2 = 3 很好理解,但是对于 -13>>2 = -4 ,我无法理解。然后我又去用 Java 语言实现一遍,结果也是一样的。
我知道关于 “原码、反码、补码” 这个知识点是 《计算机组成原理》 中的内容,但苦于网上下载不到该书,只得去Google各种博客去深入了解。
(吐槽下,Google搜索“原码 反码 补码”的结果,比度娘搜索该关键词的结果好太多!用百度真真是浪费生命。)
看着充满数学公式,和无聊的 “计算方法”,都是些教材上的理论东西,越看越迷糊。后来,我就总结了:
为什么呢? 因为 在计算机内部(寄存器层面),数都是以补码的形式存储在寄存器中的。
原码,反码什么的都是为了计算补码存在于人类思维中的,可无视它们。
比如,此题中,13 是原始数,移位移的是 13 的补码(下面细讲JavaScript整数的补码),移位后再将 补码 反算成 原始数。
这里为了方便,假设 在一个寄存器只有8位的机器上,整型只能用 8个比特位来表示。本文讲的都是有符号数。
那么,
13的 补码 就可以表示为:(其中D 表示 十进制数, B 表示二进制数)
13 (D) = 0000 1101 (B)
-13 的 补码 就是:
-13 (D) = 1101 0011 (B)
那么 -13 的补码是怎么算出来的呢? 很简单,只要 让 -13 的补码 加上 13 的补码, 溢出后变成 0 就行了。
这有什么根据么? 当然有根据了,我们知道为什么发明 补码么? 就是因为 原码 和 反码 会出现 +0 和 -0 ,
所以才不为计算机科学家采用。而接着发明出来的补码,恰好补上这一漏洞,使得计算机可以和正常的数学运算
一样,完美的完成加减乘除。
所以,如果 在数学里,
13 + (-13) = 0
那么,在计算机的世界里,必须
0000 1101 + 1101 0011 = 0
因为造出补码的意义就是为了让计算机内补码和数学中的数字一一对应,就是能完全代表数学中的数。这样才能使用传承了
几千年的数学知识进行更高深的微积分等科学计算。
这里举一个简单的例子。
一台8位寄存器的机器,13 的补码 是 0000 1101 ,那 -13 的补码呢?
根据 -13 + 13 = 0 ,可以这么算:
0000 1101
+ xxxx xxxx
———————
1 0000 0000 (8寄存器,进位的1溢出被丢弃。寄存器中就保存的是 0000 0000 ,就是数学中的0)
这样,很容易凑出 -13 的补码,再简单不过了。就只有1和0进行加减。-13的补码可以算出 是 1111 0011。
比之,教科书式的
View Code
答案见:http://blog.chinaunix.net/uid-23629988-id-3018793.html
PS:在JS中,位运算基本没用。这是强类型语言C/C++/Java才经常用到的内容。
.
js中13>>2=? -13>>2=?
在浏览器中很容易测试出答案分别是 3 和 -4。
13>>2 = 3 很好理解,但是对于 -13>>2 = -4 ,我无法理解。然后我又去用 Java 语言实现一遍,结果也是一样的。
我知道关于 “原码、反码、补码” 这个知识点是 《计算机组成原理》 中的内容,但苦于网上下载不到该书,只得去Google各种博客去深入了解。
(吐槽下,Google搜索“原码 反码 补码”的结果,比度娘搜索该关键词的结果好太多!用百度真真是浪费生命。)
看着充满数学公式,和无聊的 “计算方法”,都是些教材上的理论东西,越看越迷糊。后来,我就总结了:
原码、反码、补码
其实,抛开应付《计算机组成原理》考试,以后(无论笔试、面试、Coding)遇到的都是 “补码”,没人关心 原码 和 反码 是个什么。为什么呢? 因为 在计算机内部(寄存器层面),数都是以补码的形式存储在寄存器中的。
原码,反码什么的都是为了计算补码存在于人类思维中的,可无视它们。
比如,此题中,13 是原始数,移位移的是 13 的补码(下面细讲JavaScript整数的补码),移位后再将 补码 反算成 原始数。
补码的简便计算方法
无论C/C++/Java强类型语言,还是JavaScript,都有移位运算符,在CPU中的运算器进行移位操作时,这个过程都是一样的。这里为了方便,假设 在一个寄存器只有8位的机器上,整型只能用 8个比特位来表示。本文讲的都是有符号数。
那么,
13的 补码 就可以表示为:(其中D 表示 十进制数, B 表示二进制数)
13 (D) = 0000 1101 (B)
-13 的 补码 就是:
-13 (D) = 1101 0011 (B)
那么 -13 的补码是怎么算出来的呢? 很简单,只要 让 -13 的补码 加上 13 的补码, 溢出后变成 0 就行了。
这有什么根据么? 当然有根据了,我们知道为什么发明 补码么? 就是因为 原码 和 反码 会出现 +0 和 -0 ,
所以才不为计算机科学家采用。而接着发明出来的补码,恰好补上这一漏洞,使得计算机可以和正常的数学运算
一样,完美的完成加减乘除。
所以,如果 在数学里,
13 + (-13) = 0
那么,在计算机的世界里,必须
0000 1101 + 1101 0011 = 0
因为造出补码的意义就是为了让计算机内补码和数学中的数字一一对应,就是能完全代表数学中的数。这样才能使用传承了
几千年的数学知识进行更高深的微积分等科学计算。
这里举一个简单的例子。
一台8位寄存器的机器,13 的补码 是 0000 1101 ,那 -13 的补码呢?
根据 -13 + 13 = 0 ,可以这么算:
0000 1101
+ xxxx xxxx
———————
1 0000 0000 (8寄存器,进位的1溢出被丢弃。寄存器中就保存的是 0000 0000 ,就是数学中的0)
这样,很容易凑出 -13 的补码,再简单不过了。就只有1和0进行加减。-13的补码可以算出 是 1111 0011。
比之,教科书式的
#include <stdlib.h> #include <stdio.h> static void divide_by_two(int num) { while (num) { printf("%d\n", num); num = num>>1; } } int main() { int num; scanf("%d", &num); divide_by_two(num); return 0; }
View Code
答案见:http://blog.chinaunix.net/uid-23629988-id-3018793.html
PS:在JS中,位运算基本没用。这是强类型语言C/C++/Java才经常用到的内容。
.
相关文章推荐
- CDN(内容分发网络)技术原理
- 数据结构常考面试题
- 数据结构实验图论一:基于邻接矩阵的广度优先搜索遍历
- ASP.NET的必须知道的东东(HttpModule,HttpHandler)之二
- <META HTTP-EQUIV="Refresh" CONTENT="0;URL=cmsview/pages/jsp/frame.jsp">
- 计算机系统的基本组成
- [深入浅出Cocoa]iOS网络编程之Socket
- 网络连接汇总
- 网络编程之编程日记
- 网络嗅探器(Sniffer)的原理与实现(1)
- 【winsock2】windows网络编程 之 UDP/IP
- AJAX - 创建 XMLHttpRequest 对象
- 数据结构实验图论:基于邻接矩阵/邻接表的广度优先搜索遍历(BFS)
- Jquery的跨域调用和HttpClient入门
- Android实现网络多线程断点续传下载
- 【winsock2】windows网络编程 之 TCP/IP Client
- java网络编程:基于UDP的网络编程
- Android操作HTTP实现与服务器通信
- iOS网络编程之Socket
- 数据结构实验图论一:基于邻接矩阵的广度优先搜索遍历