本文已参与「新人创作礼」活动,一起开启掘金创作之路。
一、问题描述
问题:写一个函数,,在不直接使用比较运算符或与0比较的前提下,判断给定的两个数字是否是符号相同的。
例如
is_same_symbol(-1, 10) == false;is_same_symbol(10,20)=true;is_same_symbol(-1,-10)=true; 同时,规定0属于正数。
二、解决问题
在二进制表示中,最高位是1的话,就是负数。最高位为0则为正数。因此我可以想办法通过位运算来判断。1^0 = 1。所以 负数^正数=负数。其实就是类似于乘法了。
1、位运算符
位运算符允许对整型数中指定的位进行求值和操作。
| 例子 | 名称 | 结果 |
|---|---|---|
$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”)。 |
位移在 PHP 中是数学运算。向任何方向移出去的位都被丢弃。左移时右侧以零填充,符号位被移走意味着正负号不被保留。右移时左侧以符号位填充,意味着正负号被保留。
要用括号确保想要的优先级。例如 $a & $b == true 先进行比较再进行按位与;而 ($a & $b) == true 则先进行按位与再进行比较。
如果 &、 | 和 ^ 运算符的左右两个操作对象都是字符串,将对会组成字符串的字符 ASCII 值执行操作,结果也是一个字符串。除此之外,两个操作对象都将 转换为整数 ,结果也将会是整数。
如果 ~ 运算符的操作对象是字符串,则将对组成字符串的字符 ASCII 值进行操作, 结果将会是字符串,否则操作对象和结构都会是整数。
<< 和 >> 运算符的操作对象和结果始终都是整数。
2、方法封装
确定可以使用位运算 ^来处理 ,那么封装函数如下:
function is_same_symbol($a,$b){
return (($a ^ $b) > 0);
}
$a=12;
$b=-10;
if (is_same_symbol($a, $b) == true){
printf ("same symbol");
}else{
printf ("not same symbol");
}
- 上面的例子会输出:
not same symbol
这里用到了比较运算符(
^)。其实完全可以再简化一下,把函数中>0的判断比较去掉,因为我们只需要知道第一位符号位即可。
function is_same_symbol($a,$b){
return !(($a ^ $b) >> 31);
}
右移31位,则只剩下最高位符号位,不是0,就是1。
另外,如果处理非数字型,而是字符串型的数字,如
$a="100.01",$b="-10.01",只需转化成数字型即可。
【注意】在使用位运算的时候注意运算优先级。
END
如有问题请在下方留言。
或关注我的公众号“
孙三苗”(sunsanmiao),输入“联系方式”。获得进一步帮助。