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 相关文章推荐
php 获取完整url地址
Dec 20 PHP
PHP has encountered an Access Violation 错误的解决方法
Jan 17 PHP
PHP的可变变量名的使用方法分享
Feb 05 PHP
PHP实现把数字ID转字母ID
Aug 12 PHP
实现获取http内容的php函数分享
Feb 16 PHP
php求正负数数组中连续元素最大值示例
Apr 11 PHP
通过PHP简单实例介绍文件上传
Dec 16 PHP
thinkPHP连接sqlite3数据库的实现方法(附Thinkphp代码生成器下载)
May 27 PHP
完美利用Yii2微信后台开发的系列总结
Jul 18 PHP
thinkphp的dump函数无输出实例代码
Nov 15 PHP
PHP多维数组排序array详解
Nov 21 PHP
php 将json格式数据转换成数组的方法
Aug 21 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中用PDO查询Mysql来避免SQL注入风险的方法
2013/04/25 PHP
PHP中使用memcache存储session的三种配置方法
2014/04/05 PHP
推荐10个提供免费PHP脚本下载的网站
2014/12/31 PHP
php操作MongoDB类实例
2015/06/17 PHP
thinkPHP5框架中widget的功能与用法详解
2018/06/11 PHP
PHP设计模式(四)原型模式Prototype实例详解【创建型】
2020/05/02 PHP
Jquery 组合form元素为json格式,asp.net反序列化
2009/07/09 Javascript
8款非常棒的响应式jQuery 幻灯片插件推荐
2012/02/02 Javascript
JS 事件绑定、事件监听、事件委托详细介绍
2016/09/28 Javascript
AngularJS实现用户登录状态判断的方法(Model添加拦截过滤器,路由增加限制)
2016/12/12 Javascript
Angular2利用组件与指令实现图片轮播组件
2017/03/27 Javascript
nodejs取得当前执行路径的方法
2018/05/13 NodeJs
基于vue实现圆形菜单栏组件
2019/07/05 Javascript
基于Vue的商品主图放大镜方案详解
2019/09/19 Javascript
基于javascript处理nginx请求过程详解
2020/07/07 Javascript
JS实现按比例缩小图片宽高
2020/08/24 Javascript
[46:50]Liquid vs Mineski 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
python 生成目录树及显示文件大小的代码
2009/07/23 Python
python监控文件或目录变化
2016/06/07 Python
Python更新数据库脚本两种方法及对比介绍
2017/07/27 Python
python3.6连接MySQL和表的创建与删除实例代码
2017/12/28 Python
Python通过调用有道翻译api实现翻译功能示例
2018/07/19 Python
使用TensorFlow实现SVM
2018/09/06 Python
python 解决flask 图片在线浏览或者直接下载的问题
2020/01/09 Python
浅谈keras中Dropout在预测过程中是否仍要起作用
2020/07/09 Python
加拿大消费电子和手机购物网站:The Source
2017/01/28 全球购物
白酒业务员岗位职责
2013/12/27 职场文书
我的长生果教学反思
2014/04/28 职场文书
人事专员岗位说明书
2014/07/29 职场文书
建筑节能汇报材料
2014/08/22 职场文书
工作后的感想
2015/08/07 职场文书
2016年教师反腐倡廉心得体会
2016/01/13 职场文书
解决Jupyter-notebook不弹出默认浏览器的问题
2021/03/30 Python
go使用Gin框架利用阿里云实现短信验证码功能
2021/08/04 Golang
python的变量和简单数字类型详解
2021/09/15 Python
React自定义hook的方法
2022/06/25 Javascript