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中使用Oracle数据库(4)
Oct 09 PHP
PHP生成月历代码
Jun 14 PHP
MySQL数据源表结构图示
Jun 05 PHP
PHP 加密/解密函数 dencrypt(动态密文,带压缩功能,支持中文)
Jan 30 PHP
Mysql数据库操作类( 1127版,提供源码下载 )
Dec 02 PHP
destoon实现底部添加你是第几位访问者的方法
Jul 15 PHP
5款适合PHP使用的HTML编辑器推荐
Jul 03 PHP
php对二维数组进行相关操作(排序、转换、去空白等)
Nov 04 PHP
Yii2中如何使用modal弹窗(基本使用)
May 30 PHP
PHP屏蔽关键字实现方法
Nov 17 PHP
PHP检测数据类型的几种方法(总结)
Mar 04 PHP
PHP实现的微信公众号扫码模拟登录功能示例
May 30 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的控制语句
2006/10/09 PHP
php从右向左/从左向右截取字符串的实现方法
2011/11/28 PHP
深入PHP运行环境配置的详解
2013/06/04 PHP
php生成图片验证码
2015/06/09 PHP
CodeIgniter配置之config.php用法实例分析
2016/01/19 PHP
php集成动态口令认证
2016/07/21 PHP
PHP设计模式之工厂模式实例总结
2017/09/01 PHP
php实现数组中出现次数超过一半的数字的统计方法
2018/10/14 PHP
PHP防止sql注入小技巧之sql预处理原理与实现方法分析
2019/12/13 PHP
在jQuery中 常用的选择器介绍
2013/04/16 Javascript
JSON.stringify转换JSON时日期时间不准确的解决方法
2014/08/08 Javascript
如何使用jquery实现文字上下滚动效果
2016/10/12 Javascript
利用JS对iframe父子(内外)页面进行操作的方法教程
2017/06/15 Javascript
微信小程序实现tab切换效果
2017/11/21 Javascript
JavaScript 跨域之POST实现方法
2018/05/07 Javascript
jQuery实现输入框的放大和缩小功能示例
2018/07/21 jQuery
Vue三种常用传值示例(父传子、子传父、非父子)
2018/07/24 Javascript
微信小程序视图控件与bindtap之间的问题的解决
2019/04/08 Javascript
javascript canvas检测小球碰撞
2020/04/17 Javascript
基于leaflet.js实现修改地图主题样式的流程分析
2020/05/15 Javascript
解决Echarts2竖直datazoom滑动后显示数据不全的问题
2020/07/20 Javascript
[44:47]Ti4 循环赛第三日 iG vs NaVi
2014/07/12 DOTA
实例解析Python中的__new__特殊方法
2016/06/02 Python
python 获取文件下所有文件或目录os.walk()的实例
2018/04/23 Python
中外合拍动画首获奥斯卡提名,“上海出品”《飞奔去月球》能否拿下最终大奖?
2021/03/16 国漫
竞争上岗演讲稿
2014/01/05 职场文书
后进生转化工作制度
2014/01/17 职场文书
写好自荐信需做到的5要点
2014/03/07 职场文书
护士优质服务演讲稿
2014/08/26 职场文书
计划生育汇报材料
2014/12/26 职场文书
新员工试用期工作总结2015
2015/05/28 职场文书
2016公司年会主持词
2015/07/01 职场文书
小学大队委竞选口号
2015/12/25 职场文书
2019 入党申请书范文
2019/07/10 职场文书
使用react+redux实现计数器功能及遇到问题
2021/06/02 Javascript
python pandas 解析(读取、写入)CSV 文件的操作方法
2022/12/24 Python