前言

在一般的代码中很少会接触到进制和位运算,但这不代表我们可以不去学习它。作为一位编程人员,这些都是基础知识。如果你没有学过这方面的知识,也不要慌,接下来的知识并不会很难。本文你将会学习到:

  • 进制转换
  • 按位操作符
  • Javascript进制转换
  • 手动实现进制转换

进制转换

以下使用常见的十进制和二进制转换作为例子,其他进制的转换也是大同小异,感兴趣可以自己琢磨下。

十进制转二进制

根据 “逢十进一” 的法则进行计数时,每十个相同的单位组成一个和它相邻的较高的单位,这种计数法叫做十进制计数法,简称十进制。这种是我们最常用的计数法。

整数

整数使用 “除二取余,逆序排列” 来转换为二进制,下面是18转换为二进制的例子:

// 除二取余
18 / 2 = 9...0
9 / 2 = 4...1
4 / 2 = 2...0
2 / 2 = 1...0
1 / 2 = 0...1 // 倒序排列
10010

就这么简单,将得出的余数逆序排列,即可得出18的二进制表示

小数

小数使用的是 “乘二取整,顺序排列”,由于方法不同需要分开计算。下面是16.125转为二进制的例子:

16 / 2 = 8...0
8 / 2 = 4...0
4 / 2 = 2...0
2 / 2 = 1...0
1 / 2 = 0...1 0.125 * 2 = 0.25
0.25 * 2 = 0.5
0.5 * 2 = 1 10000.001

将小数相乘的结果,取结果的整数顺序排列,得出小数位的二进制表示

二进制转十进制

根据 “逢二进一 ” 的法则进行计数时,每两个相同的单位组成一个和它相邻的较高的单位,这种计数法叫做二进制计数 法,简称二进制。用二进制计数时,只需用两个独立的符号“0”和“1” 来表示。

整数

整数使用 “按权相加” 法,即二进制数首先写成加权系数展开式,然后按十进制加法规则求和。下面是101010转换位十进制的例子:

2^5 2^4 2^3 2^2 2^1 2^0
1 0 1 0 1 0
------------------------
32 + 0 + 8 + 0 + 2 + 0 = 42

上面从右数依次是2的0次方,2的1次方,2的2次方... , 只取位数为1的结果,将它们相加就可以得到十进制。

小数

10110.11转十进制:

2^4 2^3 2^2 2^1 2^0 2^-1 2^-2
1 0 1 1 0 . 1 1
-------------------------------
16 + 0 + 4 + 2 + 0 + 0.5 + 0.25 = 22.75

按位操作符

按位操作符(Bitwise operators) 将其操作数(operands)当作32位的比特序列(由0和1组成),前 31 位表示整数的数值,第 32 位表示整数的符号,0 表示正数,1 表示负数。例如,十进制数18,用二进制表示则为10010。按位操作符操作数字的二进制形式,但是返回值依然是标准的JavaScript数值。

按位与( AND)

对于每一个比特位,只有两个操作数相应的比特位都是1时,结果才为1,否则为0。

用法: a & b

     9 (base 10) = 00000000000000000000000000001001 (base 2)
14 (base 10) = 00000000000000000000000000001110 (base 2)
--------------------------------
14 & 9 (base 10) = 00000000000000000000000000001000 (base 2) = 8 (base 10)

在判断一个数字奇偶时,可以使用 a & 1

function assert(n) {
return n & 1 ? "奇数" : "偶数"
}
assert(3) // 奇数

因为奇数的二进制最后一位是1,而1的二进制最后一位也是1,通过 & 操作符得出结果为1

按位或(OR)

对于每一个比特位,当两个操作数相应的比特位至少有一个1时,结果为1,否则为0。

用法: a | b

     9 (base 10) = 00000000000000000000000000001001 (base 2)
14 (base 10) = 00000000000000000000000000001110 (base 2)
--------------------------------
14 | 9 (base 10) = 00000000000000000000000000001111 (base 2) = 15 (base 10)

将浮点数向下取整转为整数,可以使用 a | 0

12.1 | 0 // 12
12.9 | 0 // 12

按位异或(XOR)

对于每一个比特位,当两个操作数相应的比特位有且只有一个1时,结果为1,否则为0。

用法: a ^ b

     9 (base 10) = 00000000000000000000000000001001 (base 2)
14 (base 10) = 00000000000000000000000000001110 (base 2)
--------------------------------
14 ^ 9 (base 10) = 00000000000000000000000000000111 (base 2) = 7 (base 10)

按位非(NOT)

反转操作数的比特位,即0变成1,1变成0。

用法: ~ a

 9 (base 10) = 00000000000000000000000000001001 (base 2)
--------------------------------
~9 (base 10) = 11111111111111111111111111110110 (base 2) = -10 (base 10)

通过两次反转操作,可将浮点数向下取整转为整数

~~16.125 // 16
~~16.725 // 16

左移(Left shift)

将 a 的二进制形式向左移 b (< 32) 比特位,右边用0填充。

用法: a << b

     9 (base 10): 00000000000000000000000000001001 (base 2)
--------------------------------
9 << 2 (base 10): 00000000000000000000000000100100 (base 2) = 36 (base 10)

左移一位相当于在原数字基础上乘2,利用这一特点,实现2的n次方:

function power(n) {
return 1 << n
}
power(3) // 8

有符号右移

将 a 的二进制表示向右移 b (< 32) 位,丢弃被移出的位。

用法: a >> b

     9 (base 10): 00000000000000000000000000001001 (base 2)
--------------------------------
9 >> 2 (base 10): 00000000000000000000000000000010 (base 2) = 2 (base 10)

相比之下, -9 >> 2 得到 -3,因为符号被保留了。

     -9 (base 10): 11111111111111111111111111110111 (base 2)
--------------------------------
-9 >> 2 (base 10): 11111111111111111111111111111101 (base 2) = -3 (base 10)

与左移相反,右移一位在原数字基础上除以2

64 >> 1 // 32

无符号右移

将 a 的二进制表示向右移 b (< 32) 位,丢弃被移出的位,并使用 0 在左侧填充。

用法: a >>> b

在非负数来说, 9 >>>2 9 >> 2 都是一样的结果

      9 (base 10): 00000000000000000000000000001001 (base 2)
--------------------------------
9 >>> 2 (base 10): 00000000000000000000000000000010 (base 2) = 2 (base 10)

而对于负数来说,结果就大有不同了,因为 >>> 不保留符号,当负数无符号右移时,会使用0填充

      -9 (base 10): 11111111111111111111111111110111 (base 2)
--------------------------------
-9 >>> 2 (base 10): 00111111111111111111111111111101 (base 2) = 1073741821 (base 10)

可以使用无符号右移来判断一个数的正负

function isPos(n) {
return (n === (n >>> 0)) ? true : false;
} isPos(-1); // false
isPos(1); // true

虽然 -1 >>> 0 不会发生右移,但 -1 的二进制码已经变成了正数的二进制码, -1 >>> 0 结果为4294967295

Javascript进制转换

toString

toString 常用于将一个变量转为字符串,或是判断一个变量的类型,例如:

let arr = []
Object.prototype.toString.call(arr) // [object Array]

你应该没想过 toString 可以用于进制转换,请看下面例子:

(18).toString(2)  // 10010(base 2)
(18).toString(8) // 22 (base 8)
(18).toString(16) // 12 (base 16)

参数规定表示数字的基数,是 2 ~ 36 之间的整数,若省略该参数,则使用基数 10。该参数可以理解为转换后的进制表示。

parseInt

parseInt 常用于数字取整,它同样可以传入参数用于进制转换,请看下面例子:

parseInt(10010, 2) // 18 (base 10)
parseInt(22, 8) // 18 (base 10)
parseInt(12, 16) // 18 (base 10)

第二个参数表示要解析的数字的基数,该值介于 2 ~ 36 之间。如果省略该参数或其值为 0,则数字将以 10 为基础来解析。如果该参数小于 2 或者大于 36,则 parseInt 将返回 NaN。

记得有道面试题是这样的:

// 问:返回的结果
[1, 2, 3].map(paseInt)

接下来,我们来一步一步的看下过程发生了什么?

parseInt(1, 0) // 基数为 0 时,以 10 为基数进行解析,结果为 1
parseInt(2, 1) // 基数不符合 2 ~ 36 的范围,结果为 NaN
parseInt(3, 2) // 这里以 2 为基数进行解析,但 3 很明显不是一个二进制表示,故结果为 NaN //题目结果为
[1, NaN, NaN]

手动实现进制转换

虽然 JavaScript 为我们内置了进制转换的函数,但手动实现进制转换有利于我们理解过程,提高逻辑能力。对于初学者来说也是一个很不错的练习例子。以下只简单实现非负整数的转换。

十进制转二进制

基于 “除二取余” 思路实现

function toBinary(value) {
if (isNaN(Number(value))) {
throw `${value} is not a number`
}
let bits = []
while (value >= 1) {
bits.unshift(value % 2)
value = Math.floor(value / 2)
}
return bits.join('')
}

使用

toBinary(36) // 100100
toBinary(12) // 1100

二进制转十进制

基于 “取幂相加” 思路实现

function toDecimal(value) {
let bits = value.toString().split('')
let res = 0
while (bits.length) {
let bit = bits.shift()
if (bit == 1) {
// ** 为幂运算符,如:2**3 为 8
res += 2 ** bits.length
}
}
return res
}

使用

toDecimal(10011) // 19
toDecimal(11111) // 33

写在最后

本文为大家介绍了进制和位运算的相关知识,旨在温故知新。我们只需要大概了解就好,因为在开发中真的用得少,至少我只用过 ~~ 来取整。而类似于~~这种取整操作还是尽量少用为好,对于其他开发者来说,可能会影响到代码可读性。

【JavaScript】进制转换&位运算,了解一下?的更多相关文章

  1. C#的格式化(进制转换|位运算)

    1.首先做一下知识的普及C或c Currency 货币格式D或d Decimal 十进制格式E或e Exponent 指数格式F或f Fixed point (float)固定精度格式G或g Gene ...

  2. javascript中的类型转换(进制转换|位运算)

    1:parseInt(string) : 这个函数的功能是从string的开头开始解析,返回一个整数 parseInt("123hua"); //输出 123 parseInt(& ...

  3. Python笔记_第一篇_面向过程_第一部分_3.进制、位运算、编码

    通过对内存这一个部分的讲解,对编程会有一个相对深入的认识.数据结构是整个内存的一个重要内容,那么关于数据结构这方面的问题还需要对进制.位运算.编码这三个方面再进行阐述一下.前面说将的数据结构是从逻辑上 ...

  4. 4.Python 进制和位运算

    .button, #logout { color: #333; background-color: #fff; border-color: #ccc; } span#login_widget > ...

  5. javascript进制转换

    其他进制转十进制 原理 parseInt 或者 Number.parseInt 语法 parseInt(string, radix); string 必需.要被解析的字符串. radix 可选.表示要 ...

  6. JavaScript 进制转换

    //十进制转其他 var x=111; alert(x.toString(8)); alert(x.toString(16)); //其他转十进制 var x='112'; alert(parseIn ...

  7. javascript 进制转换(2进制、8进制、10进制、16进制之间的转换)

    //十进制转其他 var x=110; alert(x); alert(x.toString(8)); alert(x.toString(32)); alert(x.toString(16)); // ...

  8. Codeforces Round #299 (Div. 2) B. Tavas and SaDDas【DFS/*进制思维/位运算/一个数为幸运数,当且仅当它的每一位要么是4,要么是7 ,求小于等于n的幸运数个数】

    B. Tavas and SaDDas time limit per test 1 second memory limit per test 256 megabytes input standard ...

  9. Python 进制转换、位运算

    一.进制转换 编程用十进制,十进制转换为二进制.八进制.十六进制 In [135]: bin(23) Out[135]: '0b10111' In [136]: oct(23) Out[136]: ' ...

随机推荐

  1. 悄摸直播(二)—— 播流器实现(拉取rtmp服务器中的数据流,播放直播画面)

    悄摸直播 -- JavaCV实现本机摄像头画面远程直播 播流器 一.功能说明 从rtmp服务器中获取视频流数据 + 展示直播画面 二.代码实现 /** * 播流器 * @param inputPath ...

  2. 第五篇:python购物车小程序开发demo

    功能:自定义工资水平,可选商品加购余额实时提醒用到的知识点:列表.if多分支.循环.高亮输出未解决bug删除商品后不能自动退出 代码如下: if shopping_list: shopping_lis ...

  3. Logback源码分析

    在日常开发中经常通过打印日志记录程序执行的步骤或者排查问题,如下代码类似很多,但是,它是如何执行的呢? package chapters; import org.slf4j.Logger; impor ...

  4. windows环境下使用python3.x自带的CGI服务器测试cgi脚本(转)

    1.在桌面上新建一个文件夹作为服务器目录文件夹(文件夹名称自定义,文件夹位置自定义),在www文件下再建一个文件夹,文件夹名为“cgi-bin”,须是这个文件名,其他试过不行(原因暂时未知)

  5. java8 stream自定义分组求和并排序

    public static void main(String[] args) { List<GroupDetailDTO> list = new ArrayList<>(); ...

  6. 【java面试】线程篇

    1.什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位. 2.线程和进程有什么区别? 线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任 ...

  7. Windows10 java环境配置

    1.下载 JDK 下载地址:https ://www.oracle.com/technetwork/java/javase/downloads/index-jsp-138363.html 点击下载按钮 ...

  8. 个人第四次作业——Alpha项目测试

    一.格式描述 这个作业属于哪个课程 https://edu.cnblogs.com/campus/xnsy/GeographicInformationScience/ 这个作业要求在哪里 https: ...

  9. testng使用详解

    一.testng 介绍 TestNG 是一个测试框架,其灵感来自 JUnit 和 NUnit,但同时引入了一些新的功能,使其功能更强大,使用更方便. TestNG 设计涵盖所有类型的测试:单元,功能, ...

  10. Intellij IDEA中将打开的代码与类文件进行关联

    Intellij IDEA中在导航栏打开多个类时,如何快速定位到某个类所在的目录? 经过研究,可以通过以下设置完成: 设置完成后,点击导航栏中的类,左边的Project导航就可以快速定位到该类所在的目 ...