​JavaScript中的多种进制与进制转换 ​

news2024/12/24 20:46:11

进制介绍

JavaScript 中提供的进制表示方法有四种:十进制、二进制、十六进制、八进制。
对于数值字面量,主要使用不同的前缀来区分:

  • 十进制(Decimal):
    取值数字 0-9;不用前缀。
  • 二进制(Binary):
    取值数字 0 和 1 ;前缀 0b 或 0B
  • 十六进制(Hexadecimal):
    取值数字 0-9 和 a-f ;前缀 0x 或 0X
  • 八进制(Octal):
    取值数字 0-7 ;前缀 0o 或 0O (ES6规定)。

需要注意的是,非严格模式下浏览器支持:如果有前缀0并且后面只用到 0-7 八个数字的数值时,该数值视为八进制;但如果前缀0后面跟随的数字中有8或者9,则视为十进制。
严格模式下,如果数字加前缀0,则报错:Uncaught SyntaxError: Decimals with leading zeros are not allowed in strict mode。
各进制的数值,如果取值数字超过给定的范围,则会报错:Uncaught SyntaxError: Invalid or unexpected token。

在JavaScript内部的默认情况下,二进制、十六进制、八进制字面量数值,都会自动转为十进制进行运算。

0x22 // 34
0b111 // 7
0o33 // 27
0x22 + 0b111 // 41
0o33 + 12 // 39
(0x33).toString() // 51
(0x33).valueOf() // 51

除了十进制是Javascript默认的数字进制以外,其他三种进制方式平时使用较少,主要在处理底层数据、字节编码或者位运算等时候才会碰到。

进制转换

本文将主要讨论进制转换时的问题。
JavaScript 提供了原生函数,进行十进制与其他各进制之间的相互转换。
其中,从其他进制转换成十进制,有三种方式:parseInt()Number()+(一元运算符)。这三种方式都只能转换整数。
从十进制转换成其他进制,可以使用 Number.prototype.toString()。支持小数。

parseInt(str, radix)

第一个参数是需要解析的字符串;其他进制不加前缀。
第二个参数是一个进制基数,表示转换时按什么进制来理解这个字符串,默认值10,表示转十进制。
第二个参数如果非数字,则自动转数字,如无法转称数字则忽略该参数;是数字时,必须是 2-36 的整数,超出该范围,返回 NaN

parseInt('1111', 2) // 15
parseInt('1234', 8) // 668
parseInt('18af', 16) // 6319
parseInt('1111') // 1111

如果不传入第二参数,则 parseInt 会默认使用十进制来解析字符串;但是,如果字符串以 0x 开头,会被认为是十六进制数。
而其他进制的字符串,0o21(八进制)0b11(二进制) 不会以该进制基数自动转换,而是得到 0
所以,在使用 parseInt 进行进制转换时,为了保证运行结果的正确性和稳定性,第二个参数不能省略

parseInt('0x21') // 33
parseInt('0o21') // 0
parseInt('0b11') // 0
parseInt('111', 'add') // 111
parseInt('111', '787') // NaN

如果需要解析的字符串中存在对于当前进制基数无效的字符,则会从最高位取有效字符进行转换,没有效字符则返回NaN。

parseInt('88kk', 16) // 136,=== 0x88
parseInt('kk', 16) // NaN

Number()

可以把字符串转为数字,支持其他进制的字符串,默认转成十进制数字。
字符串中如果存在无效的进制字符时,返回 NaN
记住,需要使用进制前缀,0b0o0x

Number('0b11100') // 28
Number('0o33') // 27
Number('0x33') //51

Number('0x88kk') // NaN

+(一元运算符)

与 Number() 一样,可以把字符串转为数字,支持其他进制的字符串,默认转成十进制数字。
字符串中如果存在无效的进制字符时,返回 NaN
也需要使用进制前缀。

+'0b11100' // 28
+'0o33' // 27
+'0x33' //51

+'0x88kk' // NaN

可以看到,基本和 Number() 是一样的,都在本质上是对数字的一种转换处理。

Number.prototype.toString(radix)

它支持传入一个进制基数,用于将数字转换成对应进制的字符串,它支持转换小数
未指定默认值为 10,基数参数的范围 2-36,超过范围,报错:RangeError。

15..toString(2) // 1111
585..toString(8) // 1111
4369..toString(16) // 1111
(11.25).toString(2) // 1011.01

自定义转换

除了这些原生函数以外,也可以自己实现进制数字之间的转换函数。
根据相应的规则,就可以实现十进制与二进制、十六进制之间的转换的一些方法。

十进制与十六进制转换

以下代码是针对整数在十进制与十六进制之间的转换,根据基本规则进行换算。
十六进制是以 0-9a-f 进行描述数字的一种方式,其中 0-9 取本身数字的值,而 a-f 则取 10-15 的值。
且字母不区分大小写。

function int2Hex (num = 0) {
  if (num === 0) {
    return '0'
  }
  const HEXS = '0123456789abcdef'
  let hex
  while (num) {
    hex = HEXS.charAt(num % 16) + hex
    num = Math.floor(num / 16)
  }
  return hex
}
function hex2Int (hex = '') {
  if (typeof hex !== 'string' || hex === '') {
    return NaN
  }
  const hexs = [...hex.toLowerCase()]
  let resInt = 0
  for (let i = 0; i < hexs.length; i++) {
    const hv = hexs[i]
    let num = hv.charCodeAt() < 58 ? +hv : ((code - 97) + 10)
    resInt = resInt * 16 + num
  }
  return resInt
}

如果要转换八进制,实际上与十六进制很类似,只需根据八进制的数值范围进行部分改动即可。八进制一般使用非常少,不单独列出。

下面将重点介绍二进制转换的相关知识,包括小数的二进制表示与转换。

十进制和二进制转换

在十进制与二进制的转换中,我们将考虑小数,理解小数是如何在这两者之间进行转换。
先选定一个数字,比如:11.125 ,我们看下该数字在二进制里的表示:

(11.125).toString(2) // 1011.001

可以看到,11.125 的二进制表示为:1011.001。下面将以这个数字为例进行转换操作。

十进制数字转换成二进制

首先需要了解的是,二进制小数表示方法是如何得来的:

  • 整数 部分,用二进制表示可以如此计算,数字 11:
    11 / 2 ———— 1
    5 / 2 ———— 1
    2 / 2 ———— 0
    1 / 2 ———— 1
    整数部分的规则,得到的结果是 从下往上,倒着排 1011 就是二进制的 11。

  • 小数 用二进制表示可以如此计算,小数 0.125
    例如十进制的 0.125
    0.125 × 2 = 0.25 ———— 0
    0.25 × 2 = 0.5 ———— 0
    0.5 × 2 = 1 ———— 1
    只有等于1时才结束,如果结果不等于1将会一直循环下去。
    小数部分的规则,得到的结果是 从上往下,顺着排 0.001 就是二进制的 0.125

    整数 + 小数,所以 11.125 的二进制表示方式:1011.001
    根据以上整数和小数分开计算的规则,就可以得出十进制转二进制的函数,如下:

    function c10to2 (num) {
      // 整数
      const numInteger = Math.floor(num)
      // 小数
      const numDecimal = num - numInteger
    
      let integers = []
      if (numInteger === 0) {
        integers = ['0']
      } else {
        let integerVal = numInteger
        while(integerVal !== 1) {
          integers.push(integerVal % 2 === 0 ? '0' : '1')
          integerVal = Math.floor(integerVal / 2)
        }
        integers.push('1')
      }
      const resInteger = integers.reverse().join('')
    
      let decimals = []
      if (numDecimal) {
        let decimalVal = numDecimal
        // 最多取49位的长度
        let count = 49
        while (decimalVal !== 1 && count > 0) {
          decimalVal = decimalVal * 2
          if (decimalVal >= 1) {
            decimals.push('1')
            if (decimalVal > 1) {
              decimalVal = decimalVal - 1
            }
          } else {
            decimals.push('0')
          }
          count--
        }
      }
      const resDecimal = decimals.join('')
    
      return resInteger + (resDecimal ? ('.' + resDecimal) : '')
    }
    

    小数在转换成二进制时,会存在无限循环的问题,上面的代码里截取了前49个值。
    所以,这里就会引出了一个问题,就是常见的一个数字精度问题:0.1 + 0.2 != 0.3

0.1+ 0.2 != 0.3

直接看一下 0.1 转二进制:
0.1 × 2 = 0.2
0.2 × 2 = 0.4
0.4 × 2 = 0.8
0.8 × 2 = 1.6
0.6 × 2 = 1.2
0.2 × 2 = 0.4 // 循环开始
0.4 × 2 = 0.8
0.8 × 2 = 1.6
0.6 × 2 = 1.2
...
...
无限循环

0.2 转二进制:
0.2 × 2 = 0.4
0.4 × 2 = 0.8
0.8 × 2 = 1.6
0.6 × 2 = 1.2
0.2 × 2 = 0.4 // 循环开始
0.4 × 2 = 0.8
0.8 × 2 = 1.6
0.6 × 2 = 1.2
...
...
无限循环

因为无法得到1,可以发现有限十进制小数, 0.1 转换成了无限二进制小数 0.00011001100...0.2 转成了 0.001100110011...
由于无限循环,必然会导致精度丢失,正好 0.1 + 0.2 计算得到的数字在丢失精度后的最后一位不为0,所以导致结果为:0.30000000000000004
如果截取精度后最后一位为0,那自然就不存在结果不相等的情况,如 0.1 + 0.6 === 0.7,事实上,0.1和0.6转二进制后都会丢失精度,但截取到的数值都是0,所以相等。
同样不相等的还设有 0.1 + 0.7 !== 0.8等等。
所以是计算时转二进制的精度丢失,才导致的 0.1 + 0.2 !== 0.3

在 JavaScript 中所有数值都以 IEEE-754 标准的 64 bit 双精度浮点数进行存储的。
IEEE 754 标准的 64 位双精度浮点数的小数部分最多支持53位二进制位。
因浮点数小数位的限制而需要先截断二进制数字,再转换为十进制,所以在进行算术计算时会产生误差。

这里能看到,如果十进制小数要被转化为有限二进制小数,那么它计算后的小数第一位数必然要是 5 结尾才行(因为只有 0.5 × 2 才能变为整数)。

二进制数字转换成十进制

方法是:将二进制分成整数和小数两部分,分别进行转换,然后再组合成结果的十进制数值。

  1. 整数部分:这里直接使用 parseInt 函数,parseInt('1011', 2) => 11

  2. 小数部分:如 1011.001 的小数位 001,使用下表的计算方式。
    小数部分|0|0|1
    --|--|--|--
    基数的位数次幂|2-1|2-2|2^-3
    每位与基数乘积|0 × (2^-1)|0 × (2-2)|1×(2-3)
    每位乘积结果|0|0|0.125

    最后的结果是每位乘积结果相加:0+0+0.125 = 0.125

整数与小数合起来,就得到了 1011.001 的十进制数字:11.125

根据规则,代码实现如下所示:

function c2To10 (binaryStr = '') {
  if (typeof binaryStr !== 'string' || binaryStr === '') {
    return NaN
  }
  const [ binIntStr, binDecStr ] = binaryStr.split('.')
  let binDecimal = 0
  if (binDecStr) {
    binDecimal = [...binDecStr].reduce((res, val, index) => {
      res += Number(val) * (2 ** (-(index + 1)))
      return res
    }, 0)
  }
  return parseInt(binIntStr, 2) + binDecimal
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/51505.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

08【SpringMVC的放行规则】

文章目录二、SpringMVC的放行规则2.1 SpringMVC提供的拦截规则2.2 缺省Servlet放行2.3 resources放行2.4 Handler放行2.5 放行规则小结二、SpringMVC的放行规则 2.1 SpringMVC提供的拦截规则 *.form&#xff1a;代表以*.form结尾的后缀请求都会进入springmvc管/&#xff1a;代…

Vue2.0开发之——Vue基础用法-axios(29)

一 概述 axios-使用axios发起基本的Get请求axios-结合async和await调用axiosaxios-使用解构赋值axios-基于axios.get和axios.post发起请求 二 axios-使用axios发起基本的Get请求 2.1 axios介绍 axios(发音&#xff1a;艾克C奥斯)是前端圈最火的、专注于数据库请求的库 在后面…

Linux---awk

Linux三剑客之一awk 简单介绍一下awk的用法 再谈三剑客 grep awk sed 三个并称Linux的三剑客 awk:适合编辑,处理匹配到的文本内容 grep:擅长单纯的查找或匹配文本内容 链接: Linux—grep sed:适合格式化文本内容&#xff0c;对文本进行复杂处理 链接: Linux—sed 文章目录Lin…

如何选择合适的香港物理服务器?

所有企业在部署自己的网络业务时&#xff0c;要有目标&#xff0c;正确的技术&#xff0c;尤其是服务器&#xff0c;可以帮助他们实现这些目标。比如&#xff0c;国内站长开展大型外贸业务又想要国内访问速度快&#xff0c;可以选择合适的香港物理服务器来解决这个问题。那么&a…

天舟系列货运飞船介绍

天舟系列货运飞船是由中国空间技术研究院研制的一款货运飞船&#xff0c;其主要任务是在我国空间站建造及运营期间进行物资运输补给。 天舟系列货运飞船主要用于对中国空间站在轨运行期间&#xff0c;。天舟系列货运飞船包括天舟一号、天舟二号、天舟三号、天舟四号、天舟五号等…

Chatbot(五)

一、走进聊天机器人 目标 知道常见的bot的分类知道企业中常见的流程和方法 1.1 目前企业中的常见的聊天机器人 QA BOT (问答机器人) : 回答问题 1.代表:智能名服 2.比如: 提问和回答TASK BOT(任务机器人): 助人们做事情 1.代表: siri 2.比如:设五明天早上9点的闹钟CHAT BOT…

虹科方案|HK-ATTO 和西部数据为性能要求苛刻的应用构建存储解决方案

解决方案特点 科学、医疗、工程和其他高性能环境需要同样高性能的存储。该解决方案必须存储大量数据。它还必须提供突破当今固态驱动器设备极限的速度。同时&#xff0c;组织需要一个软件定义的组件&#xff0c;使他们能够构建满足其技术和预算要求的完整存储基础架构。 昂贵的…

[附源码]Python计算机毕业设计Django动漫电影网站

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

初学者学习JS很吃力怎么办?到底该如何学习JS?

前言 觉得吃力是很正常的&#xff0c;首先这证明你在某些知识点上没有理解透彻&#xff0c;JS挺多的知识点点其实是比较抽象的&#xff0c;比如闭包、原型和原型链等&#xff0c;其次便是不会变通运用&#xff0c;这主要是敲代码熟练度的问题&#xff0c;所以我针对你这种情况…

PCA主成分分析法浅理解

ML课刚学&#xff0c;发现更多是对线性代数的回顾。更进一步说&#xff0c;统计机器学习方法就是以高数、线代和概率论为基石构筑的“一栋大厦”。下面主要沿着老师ppt的思路讲讲对PCA方法的个人理解。 这里u1Tx(i)u_1^Tx^{(i)}u1T​x(i)是x(i)x^{(i)}x(i)在单位方向向量u1u_1u…

webpack常用配置(二)之拆分配置

在《webpack常用配置&#xff08;一&#xff09;》里面是把关于webpack的配置放在了根目录下的webpack.config.js中&#xff0c;但是我们知道在开发环境下和在真正打包上线运行的环境是不一样的&#xff0c;所有我们需要把对webpack的配置拆分成 1.通用配置&#xff1a;webpack…

8.跨域请求

目录 1 一些概念 1.1 同源 1.2 同源策略 1.3 跨域 2 JSONP 2.1 原理 2.2 jQuery中的JSONP 2.2.1 默认情况 2.2.2 自定义键与函数名称 2.2.3 淘宝搜索建议请求 1 一些概念 1.1 同源 两个页面的 协议&#xff0c;域名与端口都相同&#xff0c;则两个页面…

[附源码]Python计算机毕业设计Django高校实验室仪器设备管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

大数据(9h)FlinkSQL双流JOIN

文章目录1、环境2、Temporal Joins2.1、基于处理时间&#xff08;重点&#xff09;2.1.1、设置状态保留时间2.2、基于事件时间3、Lookup Join&#xff08;重点&#xff09;4、Interval Joins&#xff08;基于间隔JOIN&#xff09;重点是Lookup Join和Processing Time Temporal …

【Ubuntu】修改ubuntu和windows双系统启动顺序

目录一、问题描述二、背景知识1. GRUB是什么2. GRUB配置文件3./etc/default/grub 主配置文件二、问题分析三、解决方案1. 修改grub主配置文件2. 更新grub配置文件一、问题描述 UbuntuWindows双系统默认使用GRUB作为引导管理器&#xff0c;而且通常默认启动Ubuntu。这样过于死板…

用Python分析了30000+《独行月球》影评数据,看看观众们怎么说~

文章目录&#x1f3f3;️‍&#x1f308; 1. 导入模块&#x1f3f3;️‍&#x1f308; 2. Pandas数据处理2.1 读取数据2.2 数据大小2.3 查看索引、数据类型和内存信息&#x1f3f3;️‍&#x1f308; 3. Pyecharts数据可视化3.1 《独行月球》评分分布-13.2 《独行月球》评分分布…

TypeScript学习笔记

TypeScript学习笔记 TypeScript 与 JavaScript 的区别 TypeScript 是 JavaScript 的超集&#xff0c;扩展了 JavaScript 的语法。TypeScript 可处理已有的 JavaScript 代码&#xff0c;并只对其中的 TypeScript 代码进行编译。TypeScript 文件的后缀名 .ts &#xff08;.ts&am…

Milvus的索引方式

索引方式&#xff1a; FLAT&#xff1a;准确率高&#xff0c; 适合数据量小 暴力求解相似。 IVF-FLAT&#xff1a;量化操作&#xff0c; 准确率和速度的平衡 IVF:inverted file 先对空间的点进行聚类&#xff0c;查询时先比较聚类中心距离&#xff0c;再找到最近的N个点。 IV…

redis5.0集群搭建(两台服务器)

文章目录1. 前言2. 配置两台机器内网互联3. redis安装4. redis集群5.0之前和5.0之后版本的区别4.1 redis5.0之前的版本创建集群4.2 redis5.0之后的版本创建集群4.3 redis5.0之前的版本需要依赖ruby环境5. redis5.0集群搭建5.1 创建redis-cluster目录5.2 将之前的redis.conf拷贝…

windbg使用教程

下载 https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-download-tools 安装&#xff0c;打开exe 我选择了下载 打开X64 Debuggers And Tools-x64_en-us.msi 要安装对应系统位数 不然打不开 安装完成后没有反应。还以为我弄错了呢&#…