前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >用JavaScript实现正整数十进制转二进制

用JavaScript实现正整数十进制转二进制

作者头像
LamHo
发布2023-05-11 09:05:52
7450
发布2023-05-11 09:05:52
举报
文章被收录于专栏:小前端看世界小前端看世界

前言

好久没有写文章了,心血来潮想写一下关于JavaScript去实现各种计算机进制转换的实现,从而加深对进制的知识有更深的认知。前端开发在日常的工作中,基本上很难遇到需要进行对我们常用的十进制做转换的需求,但是作为计算器原理重要的一部分,如果有时间不妨搞清楚,对日后阅读源码或者面试也是有帮助的。

十进制转二进制

十进制是我们常用的计数方式,如:1,5,9,10,100;而二进制是计算使用计算方式,二进制有0和1组成。例如我们用十进制表示10,那么对应的二进制 1010

可以查看基维百科了解各种进制的规则。

基维百科

简单实现正整数十进制转换二进制

十进制转换二进制是有一个公式的,大家可以记住这个公式。要转换的十进制数为除数2作为被除数,那么除数/被除数会得到余数。然后将余数按顺序保存,接着将继续除2,直到等于0,这时候我们得到一串由多次运算得出的余数组成的字符串,这个时候将余数翻转就得到除数对应的二进制数了。

上面的文字太多,可能比较绕,我们可以看看下面的这张图:

以十进制的123,转换为二进制的流程。

下面我们上代码,看看要如何去编写js代码去实现简单的十进制转二进制

代码语言:javascript
复制
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;对边界加上判断:

代码语言:javascript
复制
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次方时,数值将会失去精度,导致数字的值存在偏差。

所以在这个时候,我们需要修改一下我们的代码,要求传入的数字以字符串的形式传入,然后我们实现一个大数相除来得出最终的二进制数。

首先我们需要实现一个大数除法的函数,但是这个函数并不是完整去实现除法的计算,因为在十进制二进制的情况下,并不需要去计算小数点后面的结果,只需要知道整数余数即可,所以在进行大数相除的时候,当计算到需要小数点的时候,就可以停止了。

代码语言:javascript
复制
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进行递归运算。

代码语言:javascript
复制
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);
} 

最终看看运行效果

代码语言:javascript
复制
DecimalToBinary(`${Math.pow(2, 53)}`);

//原生转换结果: 100000000000000000000000000000000000000000000000000000
//函数转换结果: 100000000000000000000000000000000000000000000000000000
//是否一致: true

当传入超过JavaScript最长长度的数字时,原生转换会出现转换错误,但是DecimalToBinary依然能正确转换。

代码语言:javascript
复制
DecimalToBinary('9007199254740993');

//计算数字: 9007199254740993
//原生转换结果: 100000000000000000000000000000000000000000000000000000
//函数转换结果: 100000000000000000000000000000000000000000000000000001

DecimalToBinary('9007199254740994');

//计算数字: 9007199254740993
//原生转换结果: 100000000000000000000000000000000000000000000000000010
//函数转换结果: 100000000000000000000000000000000000000000000000000010

DecimalToBinary('9007199254740995');

//计算数字: 9007199254740993
//原生转换结果: 100000000000000000000000000000000000000000000000000100
//函数转换结果: 100000000000000000000000000000000000000000000000000011

以后有空再写十进制的浮点数负数二进制以及二进制转换为十进制的实现方式吧。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-05-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 十进制转二进制
    • 简单实现正整数十进制转换二进制
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档