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和XSL stylesheets转换XML文档
Oct 09 PHP
Smarty+QUICKFORM小小演示
Feb 25 PHP
php 文件夹删除、php清除缓存程序
Aug 25 PHP
php date()日期时间函数详解
May 16 PHP
PHP自定义函数收代码
Aug 01 PHP
php创建sprite
Feb 11 PHP
php递归使用示例(php递归函数)
Feb 14 PHP
php计算2个日期的差值函数分享
Feb 02 PHP
php 的反射详解及示例代码
Aug 25 PHP
Yii2框架实现登录、退出及自动登录功能的方法详解
Oct 24 PHP
Laravel5.4框架使用socialite实现github登录的方法
Mar 20 PHP
php 文件上传至OSS及删除远程阿里云OSS文件
Jul 04 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中动态修改ini配置
2014/10/14 PHP
PHP动态编译出现Cannot find autoconf的解决方法
2014/11/05 PHP
php简单实现文件或图片强制下载的方法
2016/12/06 PHP
php readfile()修改文件上传大小设置
2017/08/11 PHP
php基于环形链表解决约瑟夫环问题示例
2017/11/07 PHP
php app支付宝回调(异步通知)详解
2018/07/25 PHP
如何让PHP编码更加好看利于阅读
2019/05/12 PHP
childNodes.length与children.length的区别
2009/05/14 Javascript
firefo xml 读写实现js代码
2009/06/11 Javascript
js操作textarea方法集合封装(兼容IE,firefox)
2011/02/22 Javascript
JavaScript中的逻辑判断符&amp;&amp;、||与!介绍
2014/12/31 Javascript
javascript将中国数字格式转换成欧式数字格式的简单实例
2016/08/02 Javascript
AngularJs Managing Service Dependencies详解
2016/09/02 Javascript
JS实现表单验证功能(验证手机号是否存在,验证码倒计时)
2016/10/11 Javascript
JS键盘版计算器的制作方法
2016/12/03 Javascript
JS封装通过className获取元素的函数示例
2016/12/20 Javascript
bootstrapValidator 重新启用提交按钮的方法
2017/02/20 Javascript
react性能优化达到最大化的方法 immutable.js使用的必要性
2017/03/09 Javascript
ajax实现加载页面、删除、查看详细信息 bootstrap美化页面!
2017/03/14 Javascript
微信小程序与php 实现微信支付的简单实例
2017/06/23 Javascript
Canvas放置反弹效果随机图形(实例)
2017/08/17 Javascript
bootstrap table实现双击可编辑、添加、删除行功能
2017/09/27 Javascript
详解使用mpvue开发github小程序总结
2018/07/25 Javascript
[36:45]TNC vs VGJ.S 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
python实现分页效果
2017/10/25 Python
python实现dijkstra最短路由算法
2019/01/17 Python
python2.7实现复制大量文件及文件夹资料
2019/08/31 Python
Python计算信息熵实例
2020/06/18 Python
GafasWorld哥伦比亚:网上购买眼镜
2017/11/28 全球购物
潘多拉珠宝美国官方网站:Pandora US
2020/06/18 全球购物
商家认证委托书格式
2014/10/16 职场文书
Python读取文件夹下的所有文件实例代码
2021/04/02 Python
Django Paginator分页器的使用示例
2021/06/23 Python
MyBatis-Plus 批量插入数据的操作方法
2021/09/25 Java/Android
十大最强火系宝可梦,喷火龙上榜,第一名有双火属性
2022/03/18 日漫
python井字棋游戏实现人机对战
2022/04/28 Python