Math方法和位运算几乎是被忽略得最严重的知识点, 和正则同样, 不用不知道, 一用处处查. 为了告别这种低效的编程模式, 我特意总结此篇, 系统梳理了这两个知识点. 以此为册, 助你攻破它们.javascript
原文: louiszhai.github.io/2016/07/01/…html
截至ES6, JavaScript 中内置(build-in)构造器/对象共有19个, 其中14个是构造器(Number,Boolean, String, Object, Function, Array, RegExp, Error, Date, Set, WeakSet, Map, Proxy, Promise), Global 不能直接访问, Arguments仅在函数调用时由JS引擎建立, 而 Math, JSON, Reflect 是以对象形式存在的, 本篇将带你走进 JS 内置对象-Math以及与之息息相关的位运算, 一探究竟.java
众所周知, 若是须要使用js进行一些常规的数学运算, 是一件十分麻烦的事情. 为了解决这个问题, ECMAScript 在1.1版本中便引入了 Math. Math 之因此被设计成一个对象, 而不是构造器, 是由于对象中的方法或属性能够做为静态方法或常量直接被调用, 方便使用, 同时, Math 也没有建立实例的必要.git
属性名 | 描述 | 值 |
---|---|---|
Math.E | 欧拉常数,也是天然对数的底数 | 约2.718 |
Math.LN2 | 2的天然对数 | 约0.693 |
Math.LN10 | 10的天然对数 | 约2.303 |
Math.LOG2E | 以2为底E的对数 | 约1.443 |
Math.LOG10E | 以10为底E的对数 | 约0.434 |
Math.PI | 圆周率 | 约3.14 |
Math.SQRT1_2 | 1/2的平方根 | 约0.707 |
Math.SQRT2 | 2的平方根 | 约1.414 |
Math对象本就有不少用于运算的方法, 值得关注的是, ES6 规范又对Math对象作了一些扩展, 增长了一系列便捷的方法. 而这些方法大体能够分为如下三类.github
方法名 | 描述 |
---|---|
Math.sin(x) | 返回x的正弦值 |
Math.sinh(x) ES6新增 | 返回x的双曲正弦值 |
Math.cos(x) | 返回x的余弦值 |
Math.cosh(x) ES6新增 | 返回x的双曲余弦值 |
Math.tan(x) | 返回x的正切值 |
Math.tanh(x) ES6新增 | 返回x的双曲正切值 |
Math.asin(x) | 返回x的反正弦值 |
Math.asinh(x) ES6新增 | 返回x的反双曲正弦值 |
Math.acos(x) | 返回x的反余弦值 |
Math.atan(x) | 返回x的反正切值 |
Math.atan2(x, y) | 返回 y/x 的反正切值 |
Math.atanh(x) ES6新增 | 返回 x 的反双曲正切值 |
方法名 | 描述 | 例子 |
---|---|---|
Math.sqrt(x) | 返回x的平方根 | Math.sqrt(9);//3 |
Math.exp(x) | 返回欧拉常数(e)的x次幂 | Math.exp(1);//约2.718 |
Math.pow(x,y) | 返回x的y次幂, 若是y未初始化, 则返回x | Math.pow(2, 3);//8 |
Math.expm1(x) ES6新增 | 返回欧拉常数(e)的x次幂减去1的值 | Math.exp(1);//约1.718 |
Math.log(x) | 返回x的天然对数 | Math.log(1);//0 |
Math.log1p(x) ES6新增 | 返回x+1后的天然对数 | Math.log1p(0);//0 |
Math.log2(x) ES6新增 | 返回x以2为底的对数 | Math.log2(8);//3 |
Math.log10(x) ES6新增 | 返回x以10为底的对数 | Math.log10(100);//2 |
Math.cbrt(x) ES6新增 | 返回x的立方根 | Math.cbrt(8);//约2 |
Math.clz32() ES6新增 | 返回一个数字在转换成 32位无符号整型数字的二进制形式后, 开头的 0 的个数 | Math.clz32(2);//30 |
Math.hypot(x,y,z) ES6新增 | 返回全部参数的平方和的平方根 | Math.hypot(3,4);//5 |
Math.imul(x,y) ES6新增 | 返回两个参数的类C的32位整数乘法运算的运算结果 | Math.imul(0xffffffff, 5);//-5 |
方法名 | 描述 | 例子 |
---|---|---|
Math.abs(x) | 返回x的绝对值 | Math.abs(-5);//5 |
Math.floor(x) | 返回小于x的最大整数 | Math.floor(8.2);//8 |
Math.ceil(x) | 返回大于x的最小整数 | Math.ceil(8.2);//9 |
Math.trunc(x) ES6新增 | 返回x的整数部分 | Math.trunc(1.23);//1 |
Math.fround(x) ES6新增 | 返回离它最近的单精度浮点数形式的数字 | Math.fround(1.1);//1.100000023841858 |
Math.min(x,y,z) | 返回多个数中的最小值 | Math.min(3,1,5);//1 |
Math.max(x,y,z) | 返回多个数中的最大值 | Math.max(3,1,5);//5 |
Math.round(x) | 返回四舍五入后的整数 | Math.round(8.2);//8 |
Math.random() | 返回0到1之间的伪随机数 | Math.random(); |
Math.sign(x) ES6新增 | 返回一个数的符号( 5种返回值, 分别是 1, -1, 0, -0, NaN. 表明的各是正数, 负数, 正零, 负零, NaN) | Math.sign(-5);//-1 |
Number.prototype中有一个方法叫作toFixed(), 用于将数值装换为指定小数位数的形式. 编程
var num = 1234.56789;
console.log(num.toFixed(),num.toFixed(0));//1235,1235
console.log(num.toFixed(1));//1234.6
console.log(-1.235.toFixed(2));//-1.24复制代码
以上, 数值运算中, 存在以下规律:api
Math.max.apply(null,[5,3,8,9]); // 9
. 可是Math.min 不传参数返回 Infinity
, Math.max 不传参数返回 -Infinity
.除去上述方法, Math做为对象, 继承了来之Object对象的方法. 其中一些以下:数组
Math.valueOf();//返回Math对象自己
+Math; //NaN, 试图转换成数字,因为不能转换为数字,返回NaN
Math.toString();//"[object Math]"复制代码
Math对象提供的方法种类繁多, 且覆盖面很是全面, 基本上可以知足平常开发所需. 但同时咱们也都知道, 使用Math对象的方法进行数值运算时, js代码通过解释编译, 最终会以二进制的方式进行运算. 这种运算方式效率较低, 那么能不能进一步提升运算的效率的呢? 若是咱们使用位运算就可. 这是由于位运算本就是直接进行二进制运算.app
因为位运算是基于二进制的, 所以咱们须要先获取数值的二进制值. 实际上, toString 方法已经帮咱们作好了一部分工做, 以下:dom
//正整数可经过toString获取
12..toString(2);//1100
//负整数问题就来了
(-12).toString(2);//-1100复制代码
已知: 负数在计算机内部是采用补码表示的. 例如 -1, 1的原码是 0000 0001, 那么1的反码是 1111 1110, 补码是 1111 1111.
故: 负数的十进制转换为二进制时,符号位不变,其它位取反后+1. 即: -x的二进制 = x的二进制取反+1
. 由按位取反可借助^运算符, 故负整数的二进制能够借助下面这个函数来获取:
function getBinary(num){
var s = (-num).toString(2),
array = [].map.call(s,function(v){
return v^1;
});
array.reduceRight(function(previousValue, value, index, array){
var v = previousValue ^ value;
array[index] = v;
return +!v;
},1);
return array.join('');
}
getBinary(-12);//0100, 前面未补全的部分所有为1复制代码
而后, 多试几回就会发现:
getBinary(-1) == 1..toString(2); //true
getBinary(-2) == 2..toString(2); //true
getBinary(-4) == 4..toString(2); //true
getBinary(-8) == 8..toString(2); //true复制代码
这代表:
一样, 负数的二进制转十进制时, 符号位不变, 其余位取反后+1. 可参考:
function translateBinary2Decimal(binaryString){
var array = [].map.call(binaryString,function(v){
return v^1;
});
array.reduceRight(function(previousValue, value, index, array){
var v = previousValue ^ value;
array[index] = v;
return +!v;
},1);
return parseInt(array.join(''),2);
}
translateBinary2Decimal(getBinary(-12));//12复制代码
由上, 二进制转十进制和十进制转二进制的函数, 大部分均可以共用, 所以下面提供一个统一的函数解决它们的互转问题:
function translateBinary(item){
var s = null,
array = null,
type = typeof item,
symbol = !/^-/.test(item+'');
switch(type){
case "number":
s = Math.abs(item).toString(2);
if(symbol){
return s;
}
break;
case "string":
if(symbol){
return parseInt(item,2);
}
s = item.substring(1);
break;
default:
return false;
}
//按位取反
array = [].map.call(s,function(v){
return v^1;
});
//+1
array.reduceRight(function(previousValue, value, index, array){
var v = (previousValue + value)==2;
array[index] = previousValue ^ value;
return +v;
},1);
s = array.join('');
return type=="number"?'-'+s:-parseInt(s,2);
}
translateBinary(-12);//"-0100"
translateBinary('-0100');//-12复制代码
二进制数 | 二进制值 |
---|---|
0xAAAAAAAA | 10101010101010101010101010101010 |
0x55555555 | 01010101010101010101010101010101 |
0xCCCCCCCC | 11001100110011001100110011001100 |
0x33333333 | 00110011001100110011001100110011 |
0xF0F0F0F0 | 11110000111100001111000011110000 |
0x0F0F0F0F | 00001111000011110000111100001111 |
0xFF00FF00 | 11111111000000001111111100000000 |
0x00FF00FF | 00000000111111110000000011111111 |
0xFFFF0000 | 11111111111111110000000000000000 |
0x0000FFFF | 00000000000000001111111111111111 |
如今也可使用上述方法来验证下经常使用的二进制值对不对. 以下:
translateBinary(0xAAAAAAAA);//"10101010101010101010101010101010"复制代码
&运算符用于链接两个数, 链接的两个数它们二进制补码形式的值每位都将参与运算, 只有相对应的位上都为1时, 该位的运算才返回1. 好比 3 和 9 进行按位与运算, 如下是运算过程:
0011 //3的二进制补码形式
& 1001 //9的二进制补码形式
--------------------
0001 //1,相同位数依次运算,除最后一位都是1,返回1之外, 其它位数因为不一样时为1都返回0复制代码
由上, 3&9的运算结果为1. 实际上, 因为按位与(&)运算同位上返回1的要求较为严苛, 所以, 它是一种趋向减少最大值的运算.(不管最大值是正数仍是负数, 参与按位与运算后, 该数老是趋向减小二进制值位上1的数量, 所以老是有值减少的趋势. ) 对于按位与(&)运算, 知足以下规律:
由公式1, 咱们能够对非整数取整. 即 x&x === x&-1 === Math.trunc(x)
以下:
console.log(5.2&5.2);//5
console.log(-5.2&-1);//-5
console.log(Math.trunc(-5.2)===(-5.2&-1));//true复制代码
由公式4, 咱们能够由此判断数值是否为奇数. 以下:
if(1 & x){//若是x为奇数,它的二进制补码形式最后一位必然是1,同1进行按位与运算后,将返回1,而1又会隐式转换为true
console.log("x为奇数");
}复制代码
|不一样于&, |运算符链接的两个数, 只要其二进制补码形式的各位上有一个为1, 该位的运算就返回1, 不然返回0. 好比 3 和 12 进行按位或运算, 如下是运算过程:
0011 //3的二进制补码形式
| 1100 //12的二进制补码形式
--------------------
1111 //15, 相同位数依次运算,遇1返回1,故最终结果为4个1.复制代码
由上, 3|12的运算结果为15. 实际上, 因为按位与(&)运算同位上返回0的要求较为严苛, 所以, 它是一种趋向增大最小值的运算. 对于按位或(|)运算, 知足以下规律:
稍微利用公式1, 咱们即可以将非整数取整. 即 x|0 === Math.trunc(x)
以下:
console.log(5.2|0);//5
console.log(-5.2|0);//-5
console.log(Math.trunc(-5.2)===(-5.2|0));//true复制代码
为何 5.2|0 运算后会返回5呢? 这是由于浮点数并不支持位运算, 运算前, 5.2会转换为整数5再和0进行位运算, 故, 最终返回5.
~运算符, 返回数值二进制补码形式的反码. 什么意思呢, 就是说一个数值二进制补码形式中的每一位都将取反, 若是该位为1, 取反为0, 若是该位为0, 取反为1. 咱们来举个例子理解下:
~ 0000 0000 0000 0000 0000 0000 0000 0011 //3的32位二进制补码形式
--------------------------------------------
1111 1111 1111 1111 1111 1111 1111 1100 //按位取反后为负数(最高位(第一位)表示正负,1表明负,0表明正)
--------------------------------------------
1000 0000 0000 0000 0000 0000 0000 0011 //负数的二进制转换为十进制时,符号位不变,其它位取反(后+1)
1000 0000 0000 0000 0000 0000 0000 0100 // +1
--------------------------------------------
-4 //最终运算结果为-4复制代码
实际上, 按位非(~)操做不须要这么兴师动众地去计算, 它有且仅有一条运算规律:
~x === -x-1
.~5 ==> -5-1 === -6;
~-2016 ==> 2016-1 === 2015;复制代码
由上述公式可推出: ~~x === -(-x-1)-1 === x
. 因为位运算摈除小数部分的特性, 连续两次按位非也可用于将非整数取整. 即, ~~x === Math.trunc(x)
以下:
console.log(~~5.2);//5
console.log(~~-5.2);//-5
console.log(Math.trunc(-5.2)===(~~-5.2));//true复制代码
按位非(~)运算符只能用来求数值的反码, 而且还不能输出反码的二进制字符串. 咱们来稍微扩展下, 使它变得更易用.
function waveExtend(item){
var s = typeof item == 'number' && translateBinary(~item);
return typeof s == 'string'?s:[].map.call(item,function(v){
return v==='-'?v:v^1;
}).join('').replace(/^-?/,function(m){return m==''?'-':''});
}
waveExtend(-8);//111 -8反码,正数省略的位所有为0
waveExtend(12);//-0011 12的反码,负数省略的位所有为1复制代码
实际上, 按位非(~)运算符要求其运算数为整型, 若是运算数不是整型, 它将和其余位运算符同样尝试将其转换为32位整型, 若是没法转换, 就返回NaN. 那么~NaN等于多少呢?
console.log(~function(){alert(20);}());//先alert(20),而后输出-1复制代码
以上语句意在打印一个自执行函数的按位非运算结果. 而该自执行函数又没有显式指定返回值, 默认将返回undefined. 所以它其实是在输出~undefined的值. 而undefined值不能转换成整型, 经过测试, 运算结果为-1(即~NaN === -1). 咱们不妨来看看下来测试, 以便加深理解.
console.log(~'abc');//-1
console.log(~[]);//-1
console.log(~{});//-1
console.log(~function(){});//-1
console.log(~/\d/);//-1
console.log(~Infinity);//-1
console.log(~null);//-1
console.log(~undefined);//-1
console.log(~NaN);//-1复制代码
^运算符链接的两个数, 它们二进制补码形式的值每位参与运算, 只有相对应的每位值不一样, 才返回1, 不然返回0.
(相同则消去, 有些相似两两消失的消消乐). 以下:
0011 //3的二进制补码形式
^ 1000 //8的二进制补码形式
--------------------
1011 //11, 相同位数依次运算, 值不一样的返回1复制代码
对于按位异或(^)操做, 知足以下规律:
8^8=0
, 公式为 a^a=0
.0^-98=-98
, 公式为 0^a=a
.x-1
, 若它为偶数, 则返回 x+1
. 如: 1^-9=-10
, 1^100=101
. 公式为 1^奇=奇-1
, 1^偶=偶+1
; 推而广之, 任意整数x与2的n次方进行按位异或运算, 若它的二进制补码形式的倒数第n+1位是1, 则返回 x-2的n次方
, 反之若为0, 则返回 x+2的n次方
.-x-1
, 至关于~x运算 . 如: -1^100=-101
, -1^-9=8
. 公式为 -1^x=-x-1=~x
.3^8^8=3
, 公式为 a^b^b=a
或 a^b^a=b
.3^9=10
, 3^10=9
, 9^10=3
; 公式为 a^b=c
, a^c=b
, b^c=a
.以上公式中, 1, 2, 3和4都是由按位异或运算特性推出的, 公式5可由公式1和2推出, 公式6可由公式5推出.
因为按位异或运算的这种可交换的性质, 咱们可用它辅助交换两个整数的值. 以下, 假设这两个值为a和b:
var a=1,b=2;
//常规方法
var tmp = a;
a=b;
b=tmp;
console.log(a,b);//2 1
//使用按位异或~的方法
a=a^b; //假设a,b的原始值分别为a0,b0
b=a^b; //等价于 b=a0^b0^b0 ==> b=a0
a=a^b; //等价于 a=a0^b0^a0 ==> a=b0
console.log(a,b);//2 1
//以上可简写为
a^=b;b^=a;a^=b;复制代码
由上能够看出:
a操做符b === b操做符a
.<<运算符, 表示将数值的32位二进制补码形式的除符号位以外的其余位都往左移动若干位数. 当x为整数时, 有: x<<n === x*Math.pow(2,n)
以下:
console.log(1<<3);//8
console.log(100<<4);//1600复制代码
如此, Math.pow(2,n) 即可简写为 1<<n.
对于表达式 x<<n
, 当运算数x没法被转换为整数时,运算结果为0.
console.log({}<<3);//0
console.log(NaN<<2);//0复制代码
当运算数n没法被转换为整数时,运算结果为x. 至关于 x<<0
.
console.log(2<<NaN);//2复制代码
当运算数x和n均没法被转换为整数时,运算结果为0.
console.log(NaN<<NaN);//0复制代码
>>运算符, 除了方向向右, 其余同<<运算符. 当x为整数时, 有: x>>n === Math.floor(x*Math.pow(2,-n))
. 以下:
console.log(-5>>2);//-2
console.log(-7>>3);//-1复制代码
右移负整数时, 返回值最大为-1.
右移正整数时, 返回值最小为0.
其余规律请参考 有符号左移时运算符之一为NaN的场景.
>>>运算符, 表示连同符号也一块儿右移.
注意:无符号右移(>>>)会把负数的二进制码当成正数的二进制码. 以下:
console.log(-8>>>5);//134217727
console.log(-1>>>0);//4294967295复制代码
以上, 虽然-1没有发生向右位移, 可是-1的二进制码, 已经变成了正数的二进制码. 咱们来回顾下这个过程.
translateAry(-1);//-1,补全-1的二进制码至32位: 11111111111111111111111111111111
translateAry('11111111111111111111111111111111');//4294967295复制代码
可见, -1的二进制原码本就是32个1, 将这32个1当正数的二进制处理, 直接还原成十进制, 恰好就是 4294967295.
由此, 使用 >>>运算符, 即便是右移0位, 对于负数而言也是翻天覆地的变化. 可是对于正数却没有改变. 利用这个特性, 能够判断数值的正负. 以下:
function getSymbol(num){
return num === (num>>>0)?"正数":"负数";
}
console.log(getSymbol(-100), getSymbol(123));//负数 正数复制代码
其余规律请参考 有符号左移时运算符之一为NaN的场景.
使用运算符, 若是不知道它们的运算优先级. 就像驾驶法拉利却分不清楚油门和刹车同样恐怖. 所以我为您准备了经常使用运算符的运算优先级表. 请对号入座.
优先级 | 运算符 | 描述 |
---|---|---|
1 | 后置++ , 后置-- , [] , () 或 . | 后置++,后置--,数组下标,括号 或 属性选择 |
2 | - , 前置++ , 前置-- , ! 或 ~ | 负号,前置++,前置--, 逻辑非 或 按位非 |
3 | * , / 或 % | 乘 , 除 或 取模 |
4 | + 或 - | 加 或 减 |
5 | << 或 >> | 左移 或 右移 |
6 | > , >= , < 或 <= | 大于, 大于等于, 小于 或 小于等于 |
7 | == 或 != | 等于 或 不等于 |
8 | & | 按位与 |
9 | ^ | 按位异或 |
10 | 或 | 按位或 |
11 | && | 逻辑与 |
12 | 逻辑或 | 逻辑或 |
13 | ?: | 条件运算符 |
14 | =,/=,*=,%=,+=,-=,<<=,>>=,&=,^=,按位或后赋值 | 各类运算后赋值 |
15 | , | 逗号 |
能够看到, ① 除了按位非(~)之外, 其余的位运算符的优先级都是低于+-运算符的; ② 按位与(&), 按位异或(^) 或 按位或(|) 的运算优先级均低于比较运算符(>,<,=等); ③位运算符中按位或(|)优先级最低.
使用有符号右移(>>)运算符, 以及按位异或(^)运算符, 咱们能够实现一个 Math.abs方法. 以下:
function abs(num){
var x = num>>31, //保留32二进制中的符号位,根据num的正负性分别返回0或-1
y = num^x; //返回正数,且利用按位异或中的公式2,若num为正数,num^0则返回num自己;若num为负数,则至关于num^-1,利用公式4, 此时返回-num-1
return y-x; //若num为正数,则返回num-0即num;若num为负数则返回-num-1-(-1)即|num|
}复制代码
一般, 比较两个数是否符号相同, 咱们使用x*y>0 来判断便可. 但若是利用按位异或(^), 运算速度将更快.
console.log(-17 ^ 9 > 0);//false复制代码
好比 123%8, 实际上就是求一个余数, 而且这个余数还不大于8, 最大为7. 而后剩下的就是比较二进制值里, 123与7有几成类似了. 便不难推出公式: x%(1<<n)==x&(1<<n)-1
.
console.log(123%8);//3
console.log(123&(1<<3)-1);//3 , 为何-1时不用括号括起来, 这是由于-优先级高于&复制代码
不妨先判断n的奇偶性, 为奇数时计数器增长1, 而后将n右移一位, 重复上面步骤, 直到递归退出.
function getTotalForOne(n){
return n?(n&1)+arguments.callee(n>>1):0;
}
getTotalForOne(9);//2复制代码
加法运算, 从二进制值的角度看, 有 ①同位相加 和 ②遇2进1 两种运算(实际上, 十进制运算也是同样, 同位相加, 遇10进1).
首先咱们看看第①种, 同位相加, 不考虑②遇2进1.
1 + 1 = 0
1 + 0 = 1
0 + 1 = 1
0 + 0 = 0复制代码
以上运算过程有没有很熟悉. 是否是和按位异或(^)运算有着惊人的类似. 如:
1 ^ 1 = 0
1 ^ 0 = 1
0 ^ 1 = 1
0 ^ 0 = 0复制代码
所以①同位相加的运算, 彻底可由按位异或(^)代替, 即: x^y.
那么②遇2进1 应该怎么实现呢? 实际上, 非位移位运算中, 只有按位与(&)才能知足遇2的场景, 且只有有符号左移(<<)能知足进1的场景.
如今范围缩小了, 就看&和<<运算符能不能真正知足须要了. 值得高兴的是, 按位与(&)只有在同位都是1的状况下才返回1, 其余状况均返回0. 若是对其运算结果再作左移一位的运算, 即: (x&y)<<1. 恰好知足了②遇2进1的场景.
由于咱们是将①同位相加和②遇2进1的两种运算分开进行. 那么最终的加法运算结果应该还要作一次加法. 以下:
最终公式: x + y = x^y + (x&y)<<1
这个公式并不完美, 由于它仍是使用了加法, 推导公式怎么能直接使用推导结果呢? 太可怕了, 就不怕掉入递归深渊吗? 下面咱们就来绕过这个坑. 而绕过这个坑有一个前提, 那就是只要 x^y 或 (x&y)<<1中有一个值为0就好了, 这样便不用进行加法运算了. 讲了这么多, 不如看代码.
function add(x, y){
var _x = x^y,
_y = (x&y)<<1;
return !_x && _y || !_y && _x || arguments.callee(_x,_y);
}
add(12345678,87654321);//999999999
add(9527,-12);//9515复制代码
最后补充一点: 位运算通常只适用 [-2^31, 2^31-1] (即 -2147483648~2147483647) 之内的正负数. 超过这个范围, 计算将可能出现错误. 以下:
console.log(1<<31);//-2147483648复制代码
因为数值(2^31)超过了31位(加上保留的一个符号位,共32位), 故计算出错, 因而按照负数的方式解释二进制的值了.说好的不改变符号呢!!!
本文啰嗦几千字, 就为了说清楚两个事儿. ① Math对象中, 比较经常使用的就是数值运算方法, 不妨多看看, 其余的知道有这个api就好了. ② 位运算中, 则须要基本了解每种位运算符的运算方式, 若是能注意运算中 0和1等特殊数值 的一些妙用就更好了. 不管如何, 本文不可能面面俱到. 若是您对负数的位运算不甚理解, 建议去补下计算机的补码. 但愿能对您有所帮助.
相反数
: 只有符号不一样的两个数, 咱们就说其中一个是另外一个的相反数.补码
: 在计算机系统中, 数值一概用补码来表示和存储, 且正数的原码和补码相同, 负数的补码等于其原码按位取反再加1.本问就讨论这么多内容, 若是您有什么问题或好的想法欢迎在下方参与留言和评论.
本文做者: louis
本文连接: louiszhai.github.io/2016/07/01/…
参考文章