PHP 使用位运算实现四则运算的代码

计算机最基本的操作单元是字节,一个字节由8个位组成,一个位只能存储一个0或1。所有数据在计算机中都是采用二进制,即 1 和 0 的编码存储和运算,这次尝试在 PHP 中使用位运算实现四则运算。

Posted in PHP onMarch 09, 2021
  • 原码:将最高位作为符号位(0表示正,1表示负),其它数字位代表数值本身的绝对值
  • 反码:正数反码和原码一样;如果是负数,符号位不变,其余各位取反
  • 补码:正数补码和原码一样;负数补码为反码加 1

计算机中的数使用 补码  的形式存储

加法

二进制中只有 0 和 1,0 + 0、0 + 1 都不需要进位,但 1 + 1 则需要进位。所以,首先通过 抑或 运算得到不需要进位的那些位相加的结果。然后进行 与 运算,当相加的两位都为 1 时结果为 1。所以如果与运算的结果大于 0 说明需要进位,此时将与运算的结果按位左移 1 位,此时将左移的结果与抑或运算得到的结果重新进行上述的运算过程,直到与运算的结果为 0。

function add($summand, $addend) {
	$sum = $summand ^ $addend;
	// 判断进位
	$carry = $summand & $addend;
	while ($carry <<= 1) {
		$summand = $sum;
		$addend = $carry;
		$sum = $summand ^ $addend;
		$carry = $summand & $addend;
	}
	return $sum;
}

 

减法

function subtract($minuend, $subtrahend) {
	// 先求得减数的补码,然后求和
	$subtrahend = add(~$subtrahend, 1);

	return add($minuend, $subtrahend);
}

 

乘法

乘法也可以看作是加法的变种,例如 m * n 可以看作是 n 个 m 相加的结果。但乘法使用位运算还有更快捷的实现方式。例如 3 * 10:3 的二进制表示为 0011,10 的二进制表示为 1010

0 0 1 1
×      1 0 1 0
————————————
0 0 0 0
0 0 1 1 0
0 0 0 0 0 0
0 0 1 1 0 0 0
————————————
0 0 1 1 1 1 0

乘法计算的结果为:当乘数的位的值为 1 时,将被乘数按位左移相应的位数,最后将这些按位左移后得到的结果相加及时最后的结果。

function multiply($multiplicand, $multiplicator) {
	// 判断符号位
	$flag = ($multiplicand ^ $multiplicator) < 0 ? false: true;
	// 被乘数和乘数取绝对值
	$multiplicand = $multiplicand < 0 ? add(~$multiplicand, 1) : $multiplicand;
	$multiplicator = $multiplicator < 0 ? add(~$multiplicator, 1) : $multiplicator;
	$product = 0;
	$multiplicator = decbin($multiplicator);
	$length = strlen($multiplicator);
	for ($i = 0; $i < $length; $i++) {
		if ($multiplicator[$i]) {
			$product += $multiplicand << $length - $i - 1;
		}
	}
	if (!$flag) {
		$product = add(~$product, 1);
	}
	return $product;
}

 

除法

同乘法类似,除法可以看作是被除数可以减去多少个除数。

function divide($dividend, $divisor) {
	// 判断符号位
	$flag = ($dividend ^ $divisor) < 0 ? false: true;
	// 取得被除数符号位
	$dividend_flag = $dividend < 0 ? false: true;
	// 取绝对值
	$dividend = $dividend < 0 ? add(~$dividend, 1) : $dividend;
	$divisor = $divisor < 0 ? add(~$divisor, 1) : $divisor;

	$quotient = 0;
	$remainder = 0;

	if ($dividend < $divisor) {
		// 被除数小于除数的情况
		$remainder = $dividend;
		return 'quotient = '.$quotient.' remainder = '.$remainder;
	}

	while ($dividend >= $divisor) {
		$i = 0;
		$mul_divisor = $divisor;

		while ($dividend >= ($mul_divisor << 1)) {
			$i++;
			$mul_divisor <<= 1;
		}

		$dividend -= $mul_divisor;
		$quotient += 1 << $i;
	}

	$remainder = $dividend;
	if (!$flag) {
		$quotient = add(~$quotient, 1);
	}
	if (!$dividend_flag) {
		$remainder = add(~$remainder, 1);
	}

	return 'quotient = '.$quotient.' remainder = '.$remainder;
}

需要指出的是,上面的代码在实现过程中并没有考虑数据的溢出。
两个很大的数相加可能会溢出;
正数减负数也可能溢出;
两个大数相乘也会溢出;
任何数除以 0 都会溢出。

PHP 相关文章推荐
phpMyAdmin 安装及问题总结
May 28 PHP
DedeCMS dede_channeltype表字段注释
Apr 07 PHP
php的list()的一步操作给一组变量进行赋值的使用
May 18 PHP
php中根据变量的类型 选择echo或dump
Jul 05 PHP
Zend的AutoLoad机制介绍
Sep 27 PHP
php中将html中的br换行符转换为文本输入中的换行符
Mar 26 PHP
PHP代码优化的53个细节
Mar 03 PHP
让ThinkPHP支持大小写url地址访问的方法
Oct 31 PHP
分享3个php获取日历的函数
Sep 25 PHP
PHP程序员的技术成长规划
Mar 25 PHP
PHP编辑器PhpStrom运行缓慢问题
Feb 21 PHP
php根据地址获取百度地图经纬度的实例方法
Sep 03 PHP
让你的PHP,APACHE,NGINX支持大文件上传
Mar 09 #PHP
PHP常用字符串输出方法分析(echo,print,printf及sprintf)
Mar 09 #PHP
PHP中echo与print区别点整理
Mar 09 #PHP
PHP filter_var() 函数, 验证判断EMAIL,URL等
Mar 09 #PHP
PHP读取文件或采集时解决中文乱码
Mar 09 #PHP
利用PHP内置SERVER开启web服务(本地开发使用)
Mar 09 #PHP
PHP7 windows支持
Mar 09 #PHP
You might like
php 删除cookie和浏览器重定向
2009/03/16 PHP
php 删除记录同时删除图片文件的实现代码
2010/05/12 PHP
yii框架builder、update、delete使用方法
2014/04/30 PHP
destoon调用discuz论坛中带图片帖子的实现方法
2014/08/21 PHP
浅谈关于PHP解决图片无损压缩的问题
2017/09/01 PHP
浅谈laravel orm 中的一对多关系 hasMany
2019/10/21 PHP
JavaScript之Getters和Setters 平台支持等详细介绍
2012/12/07 Javascript
热点新闻滚动特效的js代码
2013/08/17 Javascript
关于JavaScript中name的意义冲突示例介绍
2014/05/29 Javascript
javascript中window.open在原来的窗口中打开新的窗口(不同名)
2015/11/15 Javascript
解析JavaScript面向对象概念中的Object类型与作用域
2016/05/10 Javascript
利用Vue.js+Node.js+MongoDB实现一个博客系统(附源码)
2017/04/24 Javascript
Javascript Promise用法详解
2018/05/10 Javascript
JS常见DOM节点操作示例【创建 ,插入,删除,复制,查找】
2018/05/14 Javascript
Vue2 添加数据可视化支持的方法步骤
2019/01/02 Javascript
[00:32]DOTA2上海特级锦标赛 Ehome战队宣传片
2016/03/03 DOTA
[01:48]帕吉至宝加入游戏,遗迹战场现“千劫神屠”
2018/04/07 DOTA
介绍Python的@property装饰器的用法
2015/04/28 Python
Python的Asyncore异步Socket模块及实现端口转发的例子
2016/06/14 Python
python实现抖音视频批量下载
2018/06/20 Python
Python3调用百度AI识别图片中的文字功能示例【测试可用】
2019/03/13 Python
ASOS西班牙官网:英国在线时尚和美容零售商
2020/01/10 全球购物
PHP如何防止SQL注入
2014/05/03 面试题
linux面试题参考答案(4)
2014/09/21 面试题
怎么写好自荐信
2013/10/30 职场文书
区三好学生主要事迹
2014/01/30 职场文书
优秀医生事迹材料
2014/02/12 职场文书
学期评语大全
2014/04/30 职场文书
法律系毕业生求职信
2014/05/28 职场文书
2014年四风问题个人对照自查剖析材料
2014/09/15 职场文书
2015年五一劳动节演讲稿
2015/03/18 职场文书
个人工作违纪检讨书
2015/05/05 职场文书
地雷战观后感
2015/06/09 职场文书
2016十一国庆节感言
2015/12/09 职场文书
《少年闰土》教学反思
2016/02/18 职场文书
python通过opencv调用摄像头操作实例分析
2021/06/07 Python