证明tmult_ok的正确性
csapp page124. practice problem 2.35
/* Determine whether arguments can be multiplied without overflow */
int tmult_ok(int x, int y){
int p = x*y;
/* Either x is zero, or dividing p by x gives y */
return !x || p/x == y;
}
函数 tmult_ok 的功能是检查两个二补数相乘会不会溢出, 逻辑是,要么 x 为零, 或者 乘积 p 除以 x 等于另一个乘数 y 的话,就说明不会溢出。
这题要求给出这个函数正确性的数学证明。首先证明当x=0这个情况的正确性。然后考虑w位的数字(w不等于0) 有 y, p, 和 q, 其中 p 是x, y执行了二补码乘法后的结果, q 是 p/x 的值。
书中给出三条线索,分别给出这三条线索的证明即可证明这个函数的正确性。
- 证明: x和y的整数相乘结果可以被写成 \(x*y = p + t*2^w\) 形式, 当且仅当 t != 0 的时候,p溢出。
- 证明: p 可以被写成 \(p = x * q + r\), 其中\(|r| < |x|\).
- 证明: 当且仅当 \(r = t = 0\) 的时候 \(q = y\).
答案是这么证明的:
1.因为x,y都是w位二补码表示的数,所以他们的乘积最多要用2w位表示,因为:
\(-2^{w-1} <= x, y <=2^{w-1} - 1\) 注:这是二补码的取值范围
所以 x*y 就要 大于等于 \(-2^{w-1} * (2^{w-1} - 1)\) 就等于 \(-2^{2*w - 1} + 2^{w - 1}\) 注: 其实就是Tmax*Tmin
小于等于 \((-2^{w - 1})^2\) 就等于 \(2^{2*w - 2}\) 注: 其实就是Tmin*Tmin,可以证明Tmax^2 没有 Tmin^2大
看见2的次方数是2w起跳的,就说明肯定得要2w位才能表示了。所以 x*y 理应是要用 2w 位表示的(但是2w位是溢出的,暂时不管),现在设 u 等于该乘积低w位的无符号形式,v 等于该乘积高w位的二补码形式。
那么,根据公式2.3 即二进制到二补码的转换公式可以得出 \(x*y = v*2^w + u\) 这个式子乍一看匪夷所思,怎么能把一个位向量劈成两半,前w位按二补码算然后乘以\(2^w\) ,后w位按无符号算然后两个部分加起来怎么刚好就是x和y的乘积??
其实只要根据二进制转二补码的公式细心推倒,马上就可以证明这个结论:

我们还知道 \(u = T2U_{2w}(p)\) 这里p是二补码乘积,因为实际上不管乘积结果有没有溢出,unsigned形式和tow's complement形式的乘积在w位上是一模一样的,这点在数的2.18给出了证明。
所以根据公式T2U 得 \(u = p_{w-1} * 2^w + p\), 把u 带入之前的 \(x*y = v*2^w + u\) 这里, 化简可以得到: \(x*y = 2^w * (v + p_{w-1}) + p\), 此时我们设 \(t = v + p_{w-1}\),公式变为:\(x*y = t* 2^w + p\)
这里我们就可以看出,当且仅当 t = 0 的时候, x*y 才等于p,t 不等于 0 的时候乘积是溢出的。到这里证明了上面的第1条。
2.因为无论 x*y 的值 p 有没有溢出,总之它是个整数,那么只要 p 是个整数,它除以一个非零整数 x 必然会得到一个商(q)和一个余数(r) 使得 \(p = x * q + r\) 其中 |r| < |x|
这里取绝对值是因为r 和 x 的符号可能不一样,比如 -7 / 2 得 -3 余 -1, |-1| < |2|。 这里证明了第2条。
3. 如果 q = y 根据 \(p = x*q+r\) 得出 \(p = x*y+r\) 其中 \(x*y = t * 2^w + p\) 所以 \(p = t*2^w + p + r\), 两边消去 p 以后得到 \(t*2^w = -r\) 要让这个等式成立,有两种情况,要么等号两边值相等,要么两边都为零。
在第2条的证明中,我们得出 |r| < |x|, 而x是二补码,所以绝对值的最大值是 2^w 所以 |r| < \(2^w\), 回到这里,等式左边出现了\(2^w\) 而 r 要比\(2^w\) 小,可见其值必不相等,则必须是为零的情况。所以必须 r = t = 0
根据第1条证明,我们知道要想乘积不溢出,t 必须为 0, 根据第三条,当且仅当 t 为 0 的时候 \(p / x = y\) 用程序表示就是 (!x || p / x == q) 这个逻辑被证明是正确的。
这样3也证明了,再看x=0的情况,x等于零的时候乘积为零肯定不会溢出嘛,所以这个程序是正确可靠的。证毕。
证明tmult_ok的正确性的更多相关文章
- 循环不变量loop invariant 与 算法的正确性
在论述插入排序的正确性的时候, 书中引入了循环不变量的概念, 刚开始稍微有点不太明白, 早上查了一波资料之后决定把自己的理解记录下来. 什么是循环不变量 ? 在我看来, 所谓循环不变量的就是一个在循环 ...
- 证明:寝室分配问题是NPC问题
P.NP.NPC.NP-hard P:多项式时间能够解决的问题的集合,比如最短路径问题是集合P的一个元素,而最短路径问题本身又是一个集合,因此P是集合的集合. NP:多项式时间内能够验证的问题的集合. ...
- RapidJSON 代码剖析(四):优化 Grisu
我曾经在知乎的一个答案里谈及到 V8 引擎里实现了 Grisu 算法,我先引用该文的内容简单介绍 Grisu.然后,再谈及 RapidJSON 对它做了的几个底层优化. (配图中的<Grisù& ...
- 两个int的和判断溢出
long a,b; cin>>a>>b; long i; i = a+b; if((i^a)<0 && (i^b)<0) cout<<& ...
- BZOJ1828 [Usaco2010 Mar]balloc 农场分配
直接贪心,我们把线段按照右端点从小到大排序,然后一个个尝试插入即可... 来证明贪心的正确性: 不妨设贪心得到的答案集合为$S$,最优解的答案集合为$T$ 若$S$不是最优解,那么$S \not= T ...
- algorithm -- 插入排序
插入排序是<算法导论>中第一个介绍的算法,详细分析了插入排序的原理,执行过程,证明了算法的正确性.同时也引出了算法分析和算法分析常用的方法. 此文对原文作个转述,检验学到的知识. 文中使用 ...
- Codeforces Round #173 (Div. 2)
A. Bit++ 模拟. B. Painting Eggs 贪心,每个物品给使差值较小的那个人,根据题目的约数条件,可证明贪心的正确性. C. XOR and OR \(,,00 \to 00,01 ...
- M1M2总结
这个学期很开心可以和一帮兄弟姐妹们一起做软件写代码,总体看下来真的是充满哦了艰辛和困苦.虽然我是负责软件测试的这一块的,但是看着他们辛苦的写代码我也很是为他们着急和心疼.毕竟,编译当头,数据库辅助,每 ...
- UOJ264 【NOIP2016】蚯蚓
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...
随机推荐
- U盘安装中标麒麟服务器操作系统 一 (NeoKylin 6.5)
U盘安装中标麒麟服务器操作系统(NeoKylin 6.5) 首先需要下载中标麒麟服务器操作系统的iso镜像.我这里的是NeoKylin Linux A 6.5.iso 因为超过了4GB,百度网盘不支持 ...
- 33 网络相关函数(一)——live555源码阅读(四)网络
33 网络相关函数(一)——live555源码阅读(四)网络 33 网络相关函数(一)——live555源码阅读(四)网络 简介 1)IsMulticastAddress多播(组播)地址判断函数 多播 ...
- 28 GroupSock(NetAddress)——live555源码阅读(四)网络
28 GroupSock(NetAddress)——live555源码阅读(四)网络 28 GroupSock(NetAddress)——live555源码阅读(四)网络 简介 1) NetAddre ...
- 20 BasicTaskScheduler0 基本任务调度类基类(二)——Live555源码阅读(一)任务调度相关类
这是Live555源码阅读的第二部分,包括了任务调度相关的三个类.任务调度是Live555源码中很重要的部分. 本文由乌合之众 lym瞎编,欢迎转载 http://www.cnblogs.com/ol ...
- c随机数&运行时间
#include<stdlib.h> #include<time.h> srand((unsigned) time(NULL)); //用时间做种,每次产生随机数不一样 pri ...
- Java读写文件通用格式
String path = "I:\\"; File file = new File(path + "user_id_pair.txt"); FileReade ...
- python egg文件解压
unzip 就可以了. 由于项目需要将某些版本的库打包,然后 sys.path.insert方式引用(避免升级包导致某些旧的系统崩掉). 在将egg文件打包时,发现不可用.但相关模块的__path__ ...
- 3D音效
摘自:http://baike.baidu.com/view/1330437.htm?fr=aladdin 3D音效就是用扬声器仿造出似乎存在但是虚构的声音.例如扬声器仿造头顶上有一架飞机从左至右飞过 ...
- C#中使用ADOMD.NET查询多维数据集
ADOMD.NET 是用于与 Microsoft SQL Server Analysis Services 进行通信的 Microsoft .NET Framework 数据访问接口. ADOMD.N ...
- (转)高性能网站架构之缓存篇—Redis集群搭建
看过 高性能网站架构之缓存篇--Redis安装配置和高性能网站架构之缓存篇--Redis使用配置端口转发 这两篇文章的,相信你已经对redis有一定的了解,并能够安装上,进行简单的使用了,但是在咱们的 ...