PHP算法学习(5) 位运算
svn地址:svn://gitee.com/zxadmin/live_z
2019年2月14日11:38:46
- <?php
- /*
- * 位运算学习笔记
- *
- * 1,php所有的数都是有符号的,无法指定是否是无符号的 unsign
- * 2.计算机底层运算都是补码运算的
- * 3,0反码,补码都是0
- * 4,正数的反码,补码全都一样
- * 5,二进制的最高位是符号位,0是正数,1是负数
- * 6,负数的反码符号位不变,其他未取反
- * 7,负数的补码等于反码+1
- * 8,负数(取反)=》反码 +1 =》补码
- * 9,补码-1=》反码(取反)=》负数
- * 10,右移 低位溢出,符号位不变 ,并用符号位补溢出的到位
- * 11,符号位不变 低位补0
- *
- * 32位的1表示是 31个0+1
- * 64位的1表示是 63个0+1
- * 参考 http://php.net/manual/zh/function.decbin.php
- * 测试: print_r(decbin(-50)) 32 位
- *
- $a & $b And(按位与) 将把 $a 和 $b 中都为 1 的位设为 1。
- $a | $b Or(按位或) 将把 $a 和 $b 中任何一个为 1 的位设为 1。
- $a ^ $b Xor(按位异或) 将把 $a 和 $b 中一个为 1 另一个为 0 的位设为 1。
- ~ $a Not(按位取反) 将 $a 中为 0 的位设为 1,反之亦然。
- $a << $b Shift left(左移) 将 $a 中的位向左移动 $b 次(每一次移动都表示“乘以 2”)。
- $a >> $b Shift right(右移) 将 $a 中的位向右移动 $b 次(每一次移动都表示“除以 2”)。
- ⋅⋅右移 >>:将二进制进行右移,低位丢掉,高位补零 符号位不变 。
- ⋅⋅左移 <<:将二进制进行左移,低位补零,高位丢掉 符号位不变 。
- ----------------------------------------------------------------------------------------------------------------------
- &
- 按位与
- 如果两个相应的二进制位都为1,则该位的结果值为1,否则为0
- |
- 按位或
- 两个相应的二进制位中只要有一个为1,该位的结果值为1
- ^
- 按位异或
- 若参加运算的两个二进制位值相同则为0,否则为1
- ~
- 取反
- ~是一元运算符,用来对一个二进制数按位取反,即将0变1,将1变0
- <<
- 左移
- 用来将一个数的各二进制位全部左移N位,右补0
- >>
- 右移
- 将一个数的各二进制位右移N位,移到右端的低位被舍弃,对于无符号数, 高位补0
- 要使用八进制表达,数字前必须加上 0(零)。要使用十六进制表达,数字前必须加上 0x。要使用二进制表达,数字前必须加上 0b。
- Example #1 整数文字表达
- $a = 1234; // 十进制数
- $a = -123; // 负数
- $a = 0123; // 八进制数 (等于十进制 83)
- $a = 0x1A; // 十六进制数 (等于十进制 26)
- $a = 0b11111111; // 二进制数字 (等于十进制 255)
- *
- * printf() - 输出格式化字符串, using %b, %032b or %064b as the format
- */
- final class BitOperation {
- /*
- * 注意:位运算只能支持int类型
- */
- public static $format = true;
- //计算原码 吧数字十进制转换成二进制,并补充字符到系统的位数指定长度的原码
- public static function OriginalCode(int $number) {
- $OriginalCode = self::DecimalToBinary($number);
- return $OriginalCode;
- }
- //计算反码
- public static function InverseCode(int $number) {
- $OriginalCode = self::DecimalToBinary($number);
- // p($OriginalCode);
- $InverseCode = '';
- if ($number >= 0) {
- return $OriginalCode;
- } else {
- $array = str_split($OriginalCode);
- foreach ($array as $k => &$v) {
- //符号位不变
- if ($k == 0) {
- continue;
- }
- //1变0 0变1
- if ($v == '0') {
- $v = 1;
- } elseif ($v == '1') {
- $v = 0;
- }
- }
- foreach ($array as $k1 => $v1) {
- $InverseCode .= $v1;
- }
- }
- return $InverseCode;
- }
- //计算补码
- public static function ComplementCode(int $number) {
- $InverseCode = self::InverseCode($number);
- $ComplementCode = '';
- if ($number >= 0) {
- return $InverseCode;
- } else {
- // $array = str_split($InverseCode);
- // for ($index = (count($array) - 1); $index >= 0; $index--) {
- // $str .= $return[$index];
- // }
- /*
- * 不好直接计算
- */
- return decbin($number);
- }
- return self::Format($ComplementCode);
- }
- /*
- * 十进制转二进制
- * 或者直接借用 decbin函数直接转换效率更高,这次是学习代码,为了写清楚原理
- * 注意这里的效率慢其实只要 self::PhpDigit()函数造成的,如果定义死计算是64,32效率快很多倍
- */
- public static function DecimalToBinary(int $number) {
- $return = [];
- $abs = abs($number);
- while ($abs > 0) {
- $return[] = $abs % 2;
- $abs = $abs >> 1;
- }
- $str = '';
- for ($index = (count($return) - 1); $index >= 0; $index--) {
- $str .= $return[$index];
- }
- $plus_or_minus = $number >= 0 ? true : false;
- return self::FillingLength($str, $plus_or_minus);
- }
- //优化版 十进制转二进制
- public static function DecimalToBinaryFast(int $number) {
- $return = [];
- $str = decbin(abs($number));
- $plus_or_minus = $number >= 0 ? true : false;
- return self::FillingLength($str, $plus_or_minus);
- }
- /*
- * $plus_or_minus true + false -
- */
- public static function FillingLength($string = null, $plus_or_minus = true) {
- $length = self::PhpDigit();
- $res = '';
- if ($plus_or_minus) {
- $res = str_pad($string, $length, '0', STR_PAD_LEFT);
- } else {
- $res = str_pad($string, $length - 1, '0', STR_PAD_LEFT);
- $res = '1' . $res;
- }
- return $res;
- }
- public static function Format($string = null, $separation = 4) {
- if (mb_strlen($string) == 32 || mb_strlen($string) == 64) {
- $re = chunk_split($string, $separation, ".");
- $re = trim($re, '.');
- $re = str_replace('.', ' ', $re);
- return $re;
- } else {
- return $string;
- }
- }
- /*
- * 你的系统是64,但是你运行的php版本不一定是64特别是在windows上
- */
- public static function PhpDigit() {
- $phpinfo = self::PhpInfoArray();
- if (strtolower($phpinfo['General']['Architecture']) == 'x86') {
- return 32;
- } else {
- return 64;
- }
- }
- public static function PhpInfoArray() {
- ob_start();
- phpinfo();
- $info_arr = array();
- $info_lines = explode("\n", strip_tags(ob_get_clean(), "<tr><td><h2>"));
- $cat = "General";
- foreach ($info_lines as $line) {
- // new cat?
- preg_match("~<h2>(.*)</h2>~", $line, $title) ? $cat = $title[1] : null;
- if (preg_match("~<tr><td[^>]+>([^<]*)</td><td[^>]+>([^<]*)</td></tr>~", $line, $val)) {
- $info_arr[trim($cat)][trim($val[1])] = trim($val[2]);
- } elseif (preg_match("~<tr><td[^>]+>([^<]*)</td><td[^>]+>([^<]*)</td><td[^>]+>([^<]*)</td></tr>~", $line, $val)) {
- $info_arr[trim($cat)][trim($val[1])] = array("local" => trim($val[2]), "master" => trim($val[3]));
- }
- }
- return $info_arr;
- }
- public static function CountIntOne_1(int $n) {
- //计算一个十进制数转换为二进制数中‘1’的个数
- //例如十进制11 = 二进制1011,则结果是3个1
- //解题思路:利用 n & (n - 1) 可以将最后一个1变0
- //xxxx1000 & (xxxx1000 - 1) = xxxx1000 & xxxx0111 = xxxx0000
- // 1011 & (1011 - 1) = 1011 & 1010 = 1010
- //直到最后一个1被与为0,得出结果
- $r = 0;
- while ($n != 0) {
- $r++;
- $n &= ($n - 1);
- }
- return $r;
- }
- /*
- *
- */
- public static function CountIntOne_2(int $n) {
- /*
- * 十进制转二进制过程计算余数
- * 1%2 = 1 1 2~0
- * 2%2 = 0 10 2~1
- * 3%2 = 1 11 2~0 + 2~1
- * 4%2 = 0 100 2~3
- * 5%2 = 1 101 2~0 + 2~3 5%2 = 1 1%2 =1
- *
- * 利用的是数学计算过程,因为是对2求余,所有有可能是0 1 两个元素,0就是二进制位数0 1就是二进制位数的1
- */
- $r = 0;
- while ($n > 0) {
- $t = $n % 2;
- $n = $n >> 1;
- if ($t == 1) {
- $r++;
- }
- }
- return $r;
- }
- /**
- * @param int $a
- * @param int $b
- * @return int $a + $b;
- */
- public static function add(int $a, int $b): int {
- $sum = $a;
- while ($b) {
- $sum = $a ^ $b; // 不考虑进位
- $b = ($a & $b) << 1; // 只考虑进位
- $a = $sum;
- }
- return $sum;
- }
- /**
- * 相反数 <= 二进制表达取反+1(补码)
- * @param int $n
- * @return int
- */
- public static function negateNumber(int $n): int {
- return self::add(~$n, 1);
- }
- /**
- * a-b = a + (-b)
- * @param int $a
- * @param int $b
- * @return int
- */
- public static function minus(int $a, int $b): int {
- return self::add($a, self::negateNumber($b));
- }
- /**
- * @param int $a
- * @param int $b
- * @return int $a * $b
- */
- public static function multiple(int $a, int $b): int {
- $res = 0;
- while ($b) {
- if (($b & 1)) {
- $res = self::add($res, $a);
- }
- $a <<= 1;
- $b >>= 1;
- }
- return $res;
- }
- // public static function isNegative(int $n): bool {
- // return $n < 0;
- // }
- //-1就是负数, 0就是正数 直接右移31位即可看最左边第一个
- public static function isNegative(int $n) {
- return $n >> 31;
- }
- public static function maxInt(int $n) {
- return PHP_INT_MAX;
- }
- //交换两个int数
- public static function swap(int &$x, int &$y) {
- $x ^= $y;
- $y ^= $x;
- $x ^= $y;
- }
- //交换两个int数,注意返回int
- public static function average(int $x, int $y) {
- return ($x & $y) + (($x ^ $y) >> 1);
- }
- //判断奇偶
- public static function isOddEven(int $n) {
- return $n & 1;
- }
- public static function abs($x) {
- $y = $x >> 31;
- return ($x ^ $y) - $y;
- }
- /**
- * a/b a = MIN_INTEGER, b!=MIN_INTEGER ?
- * @param int $a
- * @param int $b
- * @return int
- */
- public static function p(int $a, int $b): int {
- $x = self::isNegative($a) ? self::negateNumber($a) : $a;
- $y = self::isNegative($b) ? self::negateNumber($b) : $b;
- $res = 0;
- for ($i = 31; $i > -1; $i = self::minus($i, 1)) {
- if (($x >> $i) >= $y) {
- $res |= (1 << $i);
- $x = self::minus($x, $y << $i);
- }
- }
- return self::isNegative($a) ^ self::isNegative($b) ? self::negateNumber($res) : $res;
- }
- /**
- * @return int $a / $b
- */
- public static function pide(int $a, int $b): int {
- if ($b === 0) {
- throw new RuntimeException("pisor is 0");
- }
- if ($a === self::MIN_INTEGER && $b === self::MIN_INTEGER) {
- return 1;
- } else if ($b === self::MIN_INTEGER) {
- return 0;
- } else if ($a === self::MIN_INTEGER) {
- $res = self::p(self::add($a, 1), $b);
- return self::add($res, self::p(self::minus($a, self::multiple($res, $b)), $b));
- } else {
- return self::p($a, $b);
- }
- }
- }
其实位运算的基础能力对于算法是很重要的,特别是在优化算法的时候,如果代码有问题进群反馈
参考:
https://www.cnblogs.com/kingkoo/p/6117690.html
https://www.cnblogs.com/XuYiHe/p/4966309.html
https://www.cnblogs.com/luowei010101/archive/2011/11/24/2261575.html
https://www.cnblogs.com/qiaogaojian/p/5873105.html
https://www.cnblogs.com/kiven-code/archive/2012/09/15/2686922.html
https://blog.csdn.net/lmhacm/article/details/77287571
PHP算法学习(5) 位运算的更多相关文章
- Java学习之位运算和逻辑运算符
今天看了一下HashMap类的源码,在HashMap的源码中定义了初始空间的大小 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; 当 ...
- php学习笔记位运算
位运算 源码:用二进制表示一个数,这个码就是源码. 比如2====00000000 00000000 0000000 00000010 正数的反码 源码 补码都一样 负数的源码是符号位取反.第一个位 ...
- 曹工说JDK源码(3)--ConcurrentHashMap,Hash算法优化、位运算揭秘
hashcode,有点讲究 什么是好的hashcode,一般来说,一个hashcode,一般用int来表示,32位. 下面两个hashcode,大家觉得怎么样? 0111 1111 1111 1111 ...
- 关于C/C++中的位运算技巧
本篇文章讲述在学习CSAPP位运算LAB时的一些心得. 移位运算的小技巧 C/C++对于移位运算具有不同的策略,对于无符号数,左右移位为逻辑移位,也就是直接移位:对于有符号数,采用算术移位的方式,即左 ...
- N皇后-位运算优化
N皇后问题 时间限制: 5 Sec 内存限制: 128 MB 题目描述 魔法世界历史上曾经出现过一个伟大的罗马共和时期,出于权力平衡的目的,当时的政治理论家波利比奥斯指出:“事涉每个人的权利,绝不应 ...
- 位运算之——按位与(&)操作——(快速取模算法)
学习redis 字典结构,hash找槽位 求槽位的索引值时,用到了 hash值 & sizemask操作, 其后的scan操作涉及扫描顺序逻辑,对同模的槽位 按一定规则扫描! 其中涉及位运算 ...
- 【Java基础】14、位运算之——按位与(&)操作——(快速取模算法)
学习redis 字典结构,hash找槽位 求槽位的索引值时,用到了 hash值 & sizemask操作, 其后的scan操作涉及扫描顺序逻辑,对同模的槽位 按一定规则扫描! 其中涉及位运算 ...
- 面试必备:高频算法题终章「图文解析 + 范例代码」之 矩阵 二进制 + 位运算 + LRU 合集
Attention 秋招接近尾声,我总结了 牛客.WanAndroid 上,有关笔试面经的帖子中出现的算法题,结合往年考题写了这一系列文章,所有文章均与 LeetCode 进行核对.测试.欢迎食用 本 ...
- 剑指offer—算法之位运算(二进制中1的个数)
位运算: 左移:m<<n将m左移n位,左移后低位补充0: 右移:m>>n将m右移n位,右移后高位补充的是符号位,负数补充1,整数补充0.(正数的边界值为(1,ox7FFFFFF ...
随机推荐
- Stm32型号查阅手册
- Synchronized 和 Volatile
Synchronized : 称为重量级锁,经过优化后,也没那么重了 一.CAS 1.CAS:Compare and Swap, 翻译成比较并交换. 2.java.util.concurrent包中借 ...
- [好文mark] 深度学习中的注意力机制
https://cloud.tencent.com/developer/article/1143127
- php exit die的区别
exit 输出一个消息并且退出当前脚本 void exit([string $status]) void exit(int $status)中止脚本的执行.尽管调用了exit(),Shutdow函数以 ...
- Python 概念小屋
 Python 中的 if __name__ == '__main__' 该如何理解 python多进程的理解 multiprocessing Process join run
- 【原创】大数据基础之Ambari(3)通过Ambari部署Airflow
ambari2.7.3(hdp3.1) 安装 airflow1.10 ambari的hdp中原生不支持airflow安装,下面介绍如何通过mpack方式使ambari支持airflow安装: 1 下载 ...
- Python- redis缓存 可达到瞬间并发量10W+
redis是什么? mysql是一个软件,帮助开发者对一台机器的硬盘进行操作. redis是一个软件,帮助开发者对一台机器的内存进行操作. redis缓存 可达到瞬间并发量10W+ 高并发架构系列:R ...
- GRPC单向/双向流
开始食用grpc(之二)https://www.cnblogs.com/funnyzpc/p/9570992.html 开始食用grpc(之一)https://www.cnblogs.com/funn ...
- Vue中父子组件通讯——组件todolist
一.todolist功能开发 <div id="root"> <div> <input type="text" v-model=& ...
- Cordova IOT Lesson003
bot index.html <!DOCTYPE html> <html> <head> <title>Arduino蓝牙机械昆虫控制器</tit ...