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('.', '&nbsp;', $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) 位运算的更多相关文章

  1. Java学习之位运算和逻辑运算符

    今天看了一下HashMap类的源码,在HashMap的源码中定义了初始空间的大小 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; 当 ...

  2. php学习笔记位运算

    位运算 源码:用二进制表示一个数,这个码就是源码. 比如2====00000000 00000000 0000000 00000010 正数的反码 源码 补码都一样 负数的源码是符号位取反.第一个位  ...

  3. 曹工说JDK源码(3)--ConcurrentHashMap,Hash算法优化、位运算揭秘

    hashcode,有点讲究 什么是好的hashcode,一般来说,一个hashcode,一般用int来表示,32位. 下面两个hashcode,大家觉得怎么样? 0111 1111 1111 1111 ...

  4. 关于C/C++中的位运算技巧

    本篇文章讲述在学习CSAPP位运算LAB时的一些心得. 移位运算的小技巧 C/C++对于移位运算具有不同的策略,对于无符号数,左右移位为逻辑移位,也就是直接移位:对于有符号数,采用算术移位的方式,即左 ...

  5. N皇后-位运算优化

    N皇后问题 时间限制: 5 Sec  内存限制: 128 MB 题目描述 魔法世界历史上曾经出现过一个伟大的罗马共和时期,出于权力平衡的目的,当时的政治理论家波利比奥斯指出:“事涉每个人的权利,绝不应 ...

  6. 位运算之——按位与(&)操作——(快速取模算法)

    学习redis 字典结构,hash找槽位 求槽位的索引值时,用到了 hash值 & sizemask操作, 其后的scan操作涉及扫描顺序逻辑,对同模的槽位 按一定规则扫描! 其中涉及位运算 ...

  7. 【Java基础】14、位运算之——按位与(&)操作——(快速取模算法)

    学习redis 字典结构,hash找槽位 求槽位的索引值时,用到了 hash值 & sizemask操作, 其后的scan操作涉及扫描顺序逻辑,对同模的槽位 按一定规则扫描! 其中涉及位运算 ...

  8. 面试必备:高频算法题终章「图文解析 + 范例代码」之 矩阵 二进制 + 位运算 + LRU 合集

    Attention 秋招接近尾声,我总结了 牛客.WanAndroid 上,有关笔试面经的帖子中出现的算法题,结合往年考题写了这一系列文章,所有文章均与 LeetCode 进行核对.测试.欢迎食用 本 ...

  9. 剑指offer—算法之位运算(二进制中1的个数)

    位运算: 左移:m<<n将m左移n位,左移后低位补充0: 右移:m>>n将m右移n位,右移后高位补充的是符号位,负数补充1,整数补充0.(正数的边界值为(1,ox7FFFFFF ...

随机推荐

  1. 边框回归(bounding-Box regression)

    转自:https://blog.csdn.net/zijin0802034/article/details/77685438 为什么要边框回归? 什么是边框回归? 边框回归怎么做的? 边框回归为什么宽 ...

  2. 最大熵模型和EM算法

    一.极大似然已经发生的事件是独立重复事件,符合同一分布已经发生的时间是可能性(似然)的事件利用这两个假设,已经发生时间的联合密度值就最大,所以就可以求出总体分布f中参数θ 用极大似然进行机器学习有监督 ...

  3. ActiveMQ简单介绍及安装

    消息中间件 我们简单的介绍一下消息中间件,对它有一个基本认识就好,消息中间件(MOM:Message Orient middleware). 消息中间件有很多的用途和优点: 1. 将数据从一个应用程序 ...

  4. SQL Server2016安装

    VS2017已经发布10多天了,这几天正好要重新做系统.所以想着把SQL Server和VS都做一次升级.VS2017只需要下载一个安装包就可以进行在线安装.但是SQL Server2016安装时会碰 ...

  5. 20165314 [第二届构建之法论坛] 预培训心得(Java版)

    安装IDEA配置JDKsourcepath啥的之前已经弄好了 克隆项目 emmm这次的代码托管部分好像比之前做的要简单,之前还要git config啥的,还有就是git clone不会提示要输入账号密 ...

  6. 剑指offer数组列表

    一.数组 面试题3 : 找出数组中重复的数字 面试题3(二):不修改数组找出重复的数字 面试题4:二维数组的查找 面试题21:调整数组顺序使奇数位于偶数前面 面试题39:数组中出现次数超过一半的数字 ...

  7. Java Spring Boot VS .NetCore (四)数据库操作 Spring Data JPA vs EFCore

    Java Spring Boot VS .NetCore (一)来一个简单的 Hello World Java Spring Boot VS .NetCore (二)实现一个过滤器Filter Jav ...

  8. select2 api参数的文档

    具体参数可以参考一下: 参数 类型 描述 Width 字符串 控制 宽度 样式属性的Select2容器div minimumInputLength int 最小数量的字符 maximumInputLe ...

  9. 11 个超棒的 jQuery 分步指引插件

    当一个网站或者一个Web应用推出新功能时,为了让用户了解你的站点(或应用)如何操作,往往都会在站点(应用)中添加一个分步指引的效果.然而这样的效果,对于不懂原生JS的同学来说,是件很头痛的事情. 下面 ...

  10. 查看CentOS版本信息

    今天小编将给大家详细讲解查看CentOS版本信息的命令. (一) 查看已经安装的CentOS版本信息 1.cat /etc/issue 查看版本 cat  缩写concatenate  cat命令可以 ...