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. iTOP-iMX6开发板-Android-can测试例程介绍

    TOP-iMX6开发板的 Android 源码的 can 例程包含在 Android 源码中,在“ packages/apps/”目 录下,如下图所示,这个是应用界面的源码.   如下图所示,can ...

  2. Linux下使用crontab对MYSQL进行备份以及定时清

      数据备份是一个项目必需的工作,保证数据库出问题时,将损失减小到最低.本文记录下linux服务器中使用脚本对MYSQL数据备份,并且定时清除7天前的备份. crontab定时备份 1.创建备份目录 ...

  3. Hello jna

    记录下这几天用jna3.5.0调c++写的dll的经历 os:win7 用jna调dll首先需要一个dll文件并有可调的方法,然后根据方法的名称,参数,返回值编写一个interface c++需要包含 ...

  4. 通俗易懂的vuex-demo

    在main.js引入store.js

  5. Docker入门-docker-compose使用(二)

    Docker  Docker容器大行其道,直接通过 docker pull + 启动参数的方式运行比较麻烦, 可以通过docker-compose插件快速创建容器 1.安装docker-compose ...

  6. 10张思维导图带你学习Java​Script

    10张思维导图带你学习Java​Script   下面将po出10张JavaScript相关的思维导图. 分别归类为: JavaScript变量 JavaScript运算符 JavaScript数组 ...

  7. 金三银四背后,一个 Android 程序员的面试心得

    回顾一下自己这段时间的经历,九月份的时候,公司通知了裁员,我匆匆忙忙地出去面了几家,但最终都没有拿到offer,我感觉今年的寒冬有点冷.到十二月份,公司开始第二波裁员,我决定主动拿赔偿走人.后续的面试 ...

  8. Python虚拟环境的安装与使用

    通过virtualenv创建 首先安装virtualenv:pip3 install virtualenv 安装完成之后cd到合适的目录下键入命令: virtualenv 虚拟环境名称 (创建纯净的虚 ...

  9. Caffe+Matlab'hole

    有时候,多坚持一小下下就成功了,遇到问题就频繁重装系统并不可取!放弃很容易,但坚持真的很酷! 1.安装依赖库也能出问题 命令行输入: sudo apt-get install libprotobuf- ...

  10. Linux 查看负载内存

    负载   内存     1.作用 top命令用来显示执行中的程序进程,使用权限是所有用户. 2.格式 top [-] [d delay] [q] [c] [S] [s] [i] [n] 3.主要参数 ...