要求不使用减号的情况下实现减法运算
sub(a:number, b:number): string
只需要考虑 16 位整数的加减法, 测试用例如下:
- 1.sub(1000, 2) ==> '998'
- 2.sub(2, 1000) ==> '-998'
- 3.sub(100, 100) ==> '0'
- 4.sub(0, 0) ==> '0'
- 5.sub(0, 2) ==> '-2'
- 6.sub(-32768, 1) ==> '32767' (有符号数负溢出)
# 实现 ↵
依据二进制补码的数学原理可以写出:
00// 推荐位运算相关都使用 bigint 来实现, 01// bigint 有更好的整数特性, 比 number 的浮点数特性好得多 02 03/** 转补码, 并将结果对齐到 uint16 */ 04function complement(v: bigint): bigint { 05 return ((~v) + 1n) & 0xffffn; 06} 07 08export function ecznSub(a: number, b: number): string { 09 const an = BigInt(a); // 转成 bigint 10 const bn = BigInt(b); // 转成 bigint 11 12 // 计算结果 13 const result = (an + complement(bn)) & 0xffffn; 14 15 // 判断符号位, 转成字符串返回 16 if (result & 0x8000n) return `-${complement(result)}`; 17 18 return `${result}`; 19} 20 21console.group('开始 sub 测试用例'); 22 console.log(`sub(1000, 2) ==> ${ecznSub(1000, 2)}`) 23 console.log(`sub(2, 1000) ==> ${ecznSub(2, 1000)}`) 24 console.log(`sub(100, 100) ==> ${ecznSub(100, 100)}`) 25 console.log(`sub(0, 0) ==> ${ecznSub(0, 0)}`) 26 console.log(`sub(0, 2) ==> ${ecznSub(0, 2)}`) 27 console.log(`sub(-32768, 1) ==> ${ecznSub(-32768, 1)}`) 28console.groupEnd();
备注: 我已将 ecznSub 挂在 window 上了,可以自行打开 devtools 进行调试
# 注意到... ↵
当程序执行读取某个负数的时候,其实是加载了一个对应相反数的二进制补码,因此 -2 & 0xff 结果是 0b11111110 为 254
因此如果给你一段内存,从字节流离很难判断说这个到底是不是正数,因为有符号数是被定义出来的,从外表上看跟一个无符号数一模一样。
另外,建议位运算都用 BigInt 来完成,有比普通 number 更好的整数特性