模:可理解为周期。一个偶数模,一半表示正数,一半表示负数。
十进制数的直接二进制表示。如果是正数第一位0,是负数第一位是1。但是会出现正负数相加不等于0的情况,所以产生了反码。
反码:正数的反码是自己,负数的反码是除了首位外其他位取反。正负数相加等于0了,但是会存在两个0的情况。为了解决两个0,所以产生了补码。
补码:正数的补码是自己,负数的补码是先求反码再加1。
整数部分是除2取余,逆序排列
小数部分是乘2取整,顺序排列
function ttwo(num) {
let str = num + ''
let dotIndex = str.indexOf('.')
let intNum = dotIndex > 0 ? str.substr(0, dotIndex)/1 : str/1
let floatNum = dotIndex > 0 ? str.substr(dotIndex, str.length - dotIndex)/1 : 0
let intRet = []
let floatRet = []
while (intNum > 1) {
intRet.push(intNum % 2)
intNum =intNum - Math.floor(intNum / 2) - intNum % 2
}
intRet.push(intNum)
while (floatNum) {
let _int = floatNum * 2
if (_int >= 1) {
floatRet.push(1)
floatNum = _int - 1
} else {
floatNum = _int
floatRet.push(0)
}
}
if (floatRet.length) {
return (intRet.reverse().join('') + '.' + floatRet.join(''))/1
} else {
return intRet.reverse().join('')/1
}
}
十进制的整数与小数的方法一致:
整数部分:二进制的从右往左为,第一位num*2的0次方,第二位num*2的1次方... 直至最左侧的num*2的0次方
小数部分:小数部分的二进制从左往右为,第一位num*2的-1次方,第二位num*2的-2次方
abcd.efg(2)=d*20+c*21+b*22+a*23+e*2-1+f*2-2+g*2-3(10)
function tten(num) {
let str = num + ''
let n = 0
let dotIndex = str.indexOf('.')
let intNum = dotIndex > 0 ? str.substr(0, dotIndex) : str
let floatNum = dotIndex > 0 ? str.substr(dotIndex + 1, str.length - dotIndex) : ''
for (let i = 0; i < intNum.length; i++) {
n += intNum[i]*Math.pow(2, intNum.length - i - 1)
}
for (let i = 0; i < floatNum.length; i++) {
n += floatNum[i]*Math.pow(2, -1 * (i + 1))
}
return n
}
&: 与。都为1时才为1
|:或。只有一个为1才为1
^:异或。相同为0,不同为1
~:取反。0变1,1变0
<<:左移。左移若干位,高位丢弃,低位补0。左移一位其实就是乘以2,左移n位就是乘以2的n次方。需要注意的是左移后依然保持符号位。
:右移。一般>>表示有符号位右移。>>>表示无符号位右移。都等于除以2的n次方,向下取整。
无符号位右移若干位,高位都补0。
若有符号位,整体右移n位,保留符号位。
与操作,只有都为1才为1。而偶数的最后一位必定0。那么0&1
就是1,不等于0。
function fc(num) {
return num & 1 != 0
}
2的n次幂表示为二进制,必定是1后面m个0,比如1000。那么减去1就是0111,这两个相与,必定结果为0。
function fc(num) {
return num & (num - 1) == 0
}
// 方法1
function fc(num) {
let ret = 0
while (num) {
// 判断最后一位是不是1
ret += num & 1
// 右移一位
// 注意>>>代表有符号位移动
num >>>= 1
}
}
// 方法2原理是 每个数与比自己小于1的数中必定存在一个数的最后一位为1,并且相与必定最后一个1会被抹去。
function fc(num) {
let ret = 0
while (num) {
// 判断最后一位是不是1
num = num & (num - 1)
// 每次抹除1个1
ret++
}
}
先需要知道规律:
任何一个数与0异或都是本身,任何数与自身异或都是0,多个数异或遵循交换律。
function fc(arr) {
let ret = 0
for (let i = 0; i < arr.length; i++) {
ret = ret ^ arr[i]
}
return ret
}
1,第一次完整遍历异或后,得到的值肯定为数组中两个没有重复值的异或结果
2,因为两个数字不一样,所以异或结果一定存在一个位为1,那么找到这个位的索引值。两个不同的数,这个索引值一个为1一个为0.
3,再次遍历数组的每个值,如果一个数该索引值的数字为1,则执行异或。因为相同的数执行完异或都为0,所以必定留下的是,目标两个数中索引值为1的值(为1)的那位。如果为0也执行异或,同理也留下的是目标两个数中索引值为0的值(此时为0)。
function fc(arr) {
let eo = 0
let leftArr = []
let rightArr = []
for (let i = 0; i < arr.length; i++) {
eo = eo ^ arr[i]
}
let index = 0
while (eo) {
if (eo & 1 == 1) {
break;
}
eo = eo >> 1
index++
}
let ret1 = 0
let ret2 = 0
for (let i = 0; i < arr.length; i++) {
if (arr[i] >> index & 1 == 1) {
ret1 = ret1 ^ arr[i]
} else {
ret2 = ret2 ^ arr[i]
}
}
return [ret1, ret2]
}
用二进制表示,则所有数字的二进制每位相加,如果出现3次,则可被3整除,那个出现一次的则不可能被3整除。
function tten(num) {
let str = num + ''
let n = 0
let dotIndex = str.indexOf('.')
let intNum = dotIndex > 0 ? str.substr(0, dotIndex) : str
let floatNum = dotIndex > 0 ? str.substr(dotIndex + 1, str.length - dotIndex) : ''
for (let i = 0; i < intNum.length; i++) {
n += intNum[i]*Math.pow(2, intNum.length - i - 1)
}
for (let i = 0; i < floatNum.length; i++) {
n += floatNum[i]*Math.pow(2, -1 * (i + 1))
}
return n
}
function add(num1, num2) {
num1 = num1 + ''
num2 = num2 + ''
let len1 = num1.length
let len2 = num2.length
let ret = []
while (len1 > 0 || len2 > 0) {
let n1 = num1[len1 - 1] || 0
let n2 = num2[len2 - 1] || 0
ret.unshift(n1 / 1 + n2 / 1)
len1--
len2--
}
return ret.join('')
}
function getNum(arr) {
let tmp = '0'
for (let i = 0; i < arr.length; i++) {
tmp = add(tmp, ttwo(arr[i]))
}
let ret = []
for (let i = 0; i < tmp.length; i++) {
if (tmp[i] == '0') {
ret.push(0)
} else {
if (tmp[i] % 3 == 0) {
ret.push(0)
} else {
ret.push(1)
}
}
}
return tten(ret.join(''))
}
权限前置条件:每个权限都是二进制表示,为2的n次方。如0001,0010,0100,1000。那么:
1,或,可以添加权限
2,与,可以判断权限
3,异或,可以删除权限。其实本部操作会变成toggle操作,有权限删除,无权限则增加。真正的删除是&(~code),就是除了权限位其他都为1,然后进行与操作。