好久没有写文章了,心血来潮想写一下关于JavaScript去实现各种计算机进制转换的实现,从而加深对进制的知识有更深的认知。前端开发在日常的工作中,基本上很难遇到需要进行对我们常用的十进制做转换的需求,但是作为计算器原理重要的一部分,如果有时间不妨搞清楚,对日后阅读源码或者面试也是有帮助的。
十进制是我们常用的计数方式,如:1,5,9,10,100;而二进制是计算使用计算方式,二进制有0和1组成。例如我们用十进制表示10
,那么对应的二进制 1010
。
可以查看基维百科了解各种进制的规则。
十进制转换二进制是有一个公式的,大家可以记住这个公式。要转换的十进制数为除数
,2
作为被除数
,那么除数
/被除数
会得到余数
和商
。然后将余数
按顺序保存,接着将商
继续除2
,直到商
等于0
,这时候我们得到一串由多次运算得出的余数
组成的字符串,这个时候将余数
翻转就得到除数
对应的二进制数了。
上面的文字太多,可能比较绕,我们可以看看下面的这张图:
以十进制的123,转换为二进制的流程。
下面我们上代码,看看要如何去编写js代码去实现简单的十进制转二进制
function DecimalToBinary(number) {
let temp = number;
let result = '';
while (temp > 0) {
console.log(`======${temp}=======`);
const remainder = temp % 2; // 获取余
temp = parseInt(temp / 2, 10); // 获取商
console.log(`${temp} ${remainder}`);
result = remainder + result; // 从前拼接字符
}
const nativeResult = number.toString(2);
console.log('原生转换结果:', nativeResult);
console.log('函数转换结果:', result);
console.log('是否一致:', result === nativeResult);
}
DecimalToBinary(123);
我们看看输出结果:
使用toString
和我们自己编写的函数转换结果进行对比一致,并且与上述的公式输出一致。
根据JavaScript规范,https://tc39.es/ecma262/multipage/ecmascript-data-types-and-values.html#sec-numeric-types-number-tostring;对边界加上判断:
function DecimalToBinary(number) {
let result = '';
// 非number抛出异常
if (typeof number !== 'number') {
throw TypeError('argument is not number');
// NaN返回"NaN"
} else if (number !== number) {
result = 'NaN';
// 0或-0直接返回
} else if (number === 0 || number === -0) {
result = number === 0 ? '0' : '-0';
// 正负无穷大返回正负无穷大
} else if (number === Infinity || number === -Infinity) {
result = number === Infinity ? 'Infinity' : '-Infinity';
} else {
let temp = number;
while (temp > 0) {
console.log(`======${temp}=======`);
const remainder = temp % 2; // 获取余
temp = parseInt(temp / 2, 10); // 获取商
console.log(`${temp} ${remainder}`);
result = remainder + result;
}
}
const nativeResult = number.toString(2);
console.log('原生转换结果:', nativeResult);
console.log('函数转换结果:', result);
console.log('是否一致:', result === nativeResult);
}
DecimalToBinary(123);
在这个时候我们尝试给一个超大的数字,就会发现出问题。例如我们传入一个1000000000000000000000
进行转换二进制,这个时候JavaScript
会将我们的数字转换成科学计数法
,会以1e+21
来表示,这个时候运行代码会发现和原生的转换不一致。
这是因为在JavaScript
中,数字长度超过21
位时,将会自动将数字转换为科学计数法
来表示。另外值得一提的是,在JavaScript
中,当数字2的53次方
时,数值将会失去精度,导致数字的值存在偏差。
所以在这个时候,我们需要修改一下我们的代码,要求传入的数字以字符串的形式传入,然后我们实现一个大数相除
来得出最终的二进制
数。
首先我们需要实现一个大数除法的函数,但是这个函数并不是完整去实现除法的计算,因为在十进制
转二进制
的情况下,并不需要去计算小数点后面的结果,只需要知道整数
的商
和余数
即可,所以在进行大数相除的时候,当计算到需要小数点的时候,就可以停止了。
function BigNumberDivision(divisor, dividend) {
let startIndex = 0;
let currdivisor = '';
let result = '';
let remainder;
currdivisor += divisor[startIndex];
while (currdivisor !== '') {
// 转为数字进行运算;
const numberCurrDivisor = +currdivisor;
// 除数小于被除数时借位
if (numberCurrDivisor < dividend) {
// 当前计算的是0,不需要计算
if (numberCurrDivisor === 0) {
result += parseInt(currdivisor, 10);
// 如果上一次的余数为0,并且当前被除数需要借位,那么补0到结果中
} else if (remainder === 0) {
result += '0';
}
startIndex += 1;
if (divisor[startIndex]) {
currdivisor += divisor[startIndex];
} else {
// 当没有的借位的情况下,并且当前result为空,将补0
if (result === '') {
result = '0';
if (!remainder) {
remainder = numberCurrDivisor % dividend;
}
}
currdivisor = '';
}
} else {
const quotient = numberCurrDivisor / dividend;
remainder = numberCurrDivisor % dividend;
result += parseInt(quotient, 10);
// 如果能除尽
if (remainder === 0) {
// 是否已经是最后一个数,如果已经是最后一个数,那么currdivisor可以为空,退出循环
if (startIndex >= divisor.length - 1) {
currdivisor = '';
// 不是最后一个数,将后一位数加入currdivisor,进入下一次循环
} else {
startIndex += 1;
// 后一位是0不运算,直接计入结果,并进入下一轮
currdivisor = divisor[startIndex];
}
// 不能除尽
} else {
currdivisor = remainder;
}
}
}
return {
quotient: result,
remainder: `${remainder}`,
};
}
BigNumberDivision函数最终返回一个整数商
和余数
给到DecimalToBinary
进行递归运算。
function DecimalToBinary(numberStr) {
let result = '';
if (typeof numberStr !== 'string' || !/^(-?\d+)(\.\d+)?$/.test(numberStr)) {
throw TypeError('输入的参数必须为数字字符串!');
} else if (numberStr === '0' || numberStr === '-0' || numberStr === 'Infinity' || numberStr === '-Infinity') {
result = numberStr;
} else {
let temp = numberStr;
while (temp !== '0') {
console.log(`======${temp}=======`);
const { quotient, remainder } = BigNumberDivision(temp, 2); // 获取余和商
temp = quotient; // 获取商
console.log(`${temp} ${remainder}`);
result = remainder + result;
}
}
const nativeResult = Number(numberStr).toString(2);
console.log('原生转换结果:', nativeResult);
console.log('函数转换结果:', result);
console.log('是否一致:', result === nativeResult);
}
最终看看运行效果
DecimalToBinary(`${Math.pow(2, 53)}`);
//原生转换结果: 100000000000000000000000000000000000000000000000000000
//函数转换结果: 100000000000000000000000000000000000000000000000000000
//是否一致: true
当传入超过JavaScript
最长长度的数字时,原生转换会出现转换错误,但是DecimalToBinary
依然能正确转换。
DecimalToBinary('9007199254740993');
//计算数字: 9007199254740993
//原生转换结果: 100000000000000000000000000000000000000000000000000000
//函数转换结果: 100000000000000000000000000000000000000000000000000001
DecimalToBinary('9007199254740994');
//计算数字: 9007199254740993
//原生转换结果: 100000000000000000000000000000000000000000000000000010
//函数转换结果: 100000000000000000000000000000000000000000000000000010
DecimalToBinary('9007199254740995');
//计算数字: 9007199254740993
//原生转换结果: 100000000000000000000000000000000000000000000000000100
//函数转换结果: 100000000000000000000000000000000000000000000000000011
以后有空再写十进制的浮点数
和负数
转二进制
以及二进制
转换为十进制
的实现方式吧。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有