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制作静态网站的模板框架(四)
Oct 09 PHP
收集的php编写大型网站问题集
Mar 06 PHP
php checkdate、getdate等日期时间函数操作详解
Mar 11 PHP
php目录操作函数之获取目录与文件的类型
Dec 29 PHP
php算开始时间到过期时间的相隔的天数
Jan 12 PHP
如何判断php数组的维度
Jun 10 PHP
调试PHP程序的多种方法介绍
Nov 06 PHP
Symfony2实现从数据库获取数据的方法小结
Mar 18 PHP
PHP5.3连接Oracle客户端及PDO_OCI模块的安装方法
May 13 PHP
thinkPHP5.0框架URL访问方法详解
Mar 18 PHP
PHP简单实现二维数组赋值与遍历功能示例
Oct 19 PHP
PHP大文件分割分片上传实现代码
Dec 09 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 MPDF中文乱码的解决方式
2015/12/08 PHP
PHP编程快速实现数组去重的方法详解
2017/07/22 PHP
PHP中一个有趣的preg_replace函数详解
2018/08/15 PHP
SUN的《AJAX与J2EE》全文译了
2007/02/23 Javascript
JavaScript入门教程(11) js事件处理
2009/01/31 Javascript
Javascript将string类型转换int类型
2010/12/09 Javascript
背景图跟随鼠标移动的Mootools插件实现代码
2011/12/12 Javascript
11个用于提高排版水平的基于jquery的文字效果插件
2012/09/14 Javascript
Extjs优化(一)删除冗余代码提高运行速度
2013/04/15 Javascript
Nodejs关于gzip/deflate压缩详解
2015/03/04 NodeJs
NodeJS学习笔记之Module的简介
2017/03/24 NodeJs
ionic中的$ionicPlatform.ready事件中的通用设置
2017/06/11 Javascript
angular.extend方法的具体使用
2017/09/14 Javascript
基于原生js运动方式关键点的总结(推荐)
2017/10/01 Javascript
Angular如何在应用初始化时运行代码详解
2018/06/11 Javascript
AngularJS自定义表单验证功能实例详解
2018/08/24 Javascript
Vue.js实现的购物车功能详解
2019/01/27 Javascript
vuejs移动端实现div拖拽移动
2019/07/25 Javascript
使用layer弹窗,制作编辑User信息页面的方法
2019/09/27 Javascript
jquery实现直播视频弹幕效果
2020/02/25 jQuery
微信小程序自定义支持图片的弹窗
2020/12/21 Javascript
[02:54]DOTA2英雄基础教程 撼地者
2014/01/14 DOTA
python 循环遍历字典元素的简单方法
2016/09/11 Python
Django实现发送邮件找回密码功能
2019/08/12 Python
解决pycharm同一目录下无法import其他文件
2020/02/12 Python
基于pytorch padding=SAME的解决方式
2020/02/18 Python
利用matplotlib为图片上添加触发事件进行交互
2020/04/23 Python
keras自定义损失函数并且模型加载的写法介绍
2020/06/15 Python
移动端html5模拟长按事件的实现方法
2018/09/30 HTML / CSS
JDBC操作数据库的基本流程是什么
2014/10/28 面试题
如果重写了对象的equals()方法,需要考虑什么
2014/11/02 面试题
经管应届生求职信
2013/11/17 职场文书
校长岗位职责
2013/11/26 职场文书
校庆口号
2014/06/20 职场文书
2014年应急工作总结
2014/12/11 职场文书
销售工作决心书
2015/02/04 职场文书