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 相关文章推荐
Smarty foreach控制循环次数的实现详解
Jul 03 PHP
php设计模式之单例模式使用示例
Jan 20 PHP
将php数组输出html表格的方法
Feb 24 PHP
ThinkPHP CURD方法之field方法详解
Jun 18 PHP
分享3个php获取日历的函数
Sep 25 PHP
PHP利用imagick生成组合缩略图
Feb 19 PHP
yii2实现根据时间搜索的方法
May 25 PHP
php判断用户是否关注微信公众号
Jul 22 PHP
Thinkphp框架 表单自动验证登录注册 ajax自动验证登录注册
Dec 27 PHP
[原创]PHP实现字节数Byte转换为KB、MB、GB、TB的方法
Aug 31 PHP
PHP实现的AES双向加密解密功能示例【128位】
Sep 03 PHP
Yii使用EasyWechat实现小程序获取用户的openID的方法
Apr 29 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
PhpMyAdmin中无法导入sql文件的解决办法
2010/01/08 PHP
用PHP为SHOPEX增加日志功能代码
2010/07/02 PHP
php生成扇形比例图实例
2013/11/06 PHP
php gd等比例缩放压缩图片函数
2016/06/12 PHP
Yii2.0多文件上传实例说明
2017/07/24 PHP
解决php用mysql方式连接数据库出现Deprecated报错问题
2019/12/25 PHP
Js动态创建div
2008/09/25 Javascript
JavaScript实现简单的时钟实例代码
2013/11/23 Javascript
jquery仿百度经验滑动切换浏览效果
2015/04/14 Javascript
js实现仿微博滚动显示信息的效果
2015/12/21 Javascript
深入分析javascript中的错误处理机制
2016/07/17 Javascript
鼠标点击input,显示瞬间的边框颜色,对之修改与隐藏实例
2016/12/26 Javascript
JS字符串false转boolean的方法(推荐)
2017/03/08 Javascript
Vue异步组件处理路由组件加载状态的解决方案
2018/09/07 Javascript
bootstrap+spring boot实现面包屑导航功能(前端代码)
2019/10/09 Javascript
Vue如何获取数据列表展示
2019/12/11 Javascript
jQuery cookie的公共方法封装和使用示例
2020/06/01 jQuery
[00:59]DOTA2背景故事第二期之四大基本法则
2020/07/07 DOTA
在Linux系统上部署Apache+Python+Django+MySQL环境
2015/12/24 Python
Python中Django发送带图片和附件的邮件
2017/03/31 Python
TensorFlow安装及jupyter notebook配置方法
2017/09/08 Python
Python中的默认参数实例分析
2018/01/29 Python
分分钟入门python语言
2018/03/20 Python
Python使用dict.fromkeys()快速生成一个字典示例
2019/04/24 Python
Python计算两个矩形重合面积代码实例
2019/09/16 Python
Python-numpy实现灰度图像的分块和合并方式
2020/01/09 Python
python中requests模拟登录的三种方式(携带cookie/session进行请求网站)
2020/11/17 Python
详解CSS 3 中的 calc() 方法
2018/01/12 HTML / CSS
Linux上比较文件的命令都有哪些
2012/02/24 面试题
质量主管工作职责
2014/09/26 职场文书
教师节标语大全
2014/10/07 职场文书
2014年卫生工作总结
2014/11/27 职场文书
涨价通知
2015/04/23 职场文书
2016年校园重阳节广播稿
2015/12/18 职场文书
健身房被搭讪?用python写了个小米计时器助人为乐
2021/06/08 Python
Pillow图像处理库安装及使用
2022/04/12 Python