进制转换
在数学中,不止只有我们常见的10进制,最近刷了几道关于进制转换的题目,在这里做个总结和记录吧。
基本概念
首先我们要先了解进制的基本概念,这里我直接从LeetCode官方这里引用了。
任何一种进位计数制都有一个基数,基数为 X 的进位计数制称为 X 进制,表示每一个数位上的数运算时都是逢 X 进一。
对于一个 X 进制的数,其具体数值由其中的每个数码和数码所在的数位决定。整数部分从右往左的第 m 个数位表示的权重是 ,其中 m 最小为 0;小数部分从左往右的第 n 个数位表示的权重是,其中 n 最小为 1。
八进制的 可以写成如下形式:
用我自己的话来说,就是数值*权重
进制转换的一般思路
一般来说,我们习惯将进制转换成十进制,这样便于理解和手算。当然,我们也可以不通过十进制作为中间态过度,比如我们熟悉的二进制和十六进制的转换。
非十进制转十进制
将非十进制数转成十进制数,只要将每个数位的加权和即可。
例如,将八进制数 转成十进制:
下面是程序的实现(只考虑整数),我们可以从高位到低位进行读取,按照下面的方式读入,其中n
表示是几进制数
|
|
十进制转非十进制
首先我们先来看手算,将十进制数转成 X 进制数,需要对整数部分和小数部分分别转换。
对于整数部分,转换方式是将十进制数的整数部分每次除以 X 直到变成 0,并记录每次的余数,反向遍历每次的余数即可得到 X 进制表示。
对于小数部分,转换方式是将十进制数的小数部分每次乘以 X 直到变成 0,并记录每次的整数部分,正序遍历每次的整数部分即可得到 X 进制表示。
下面是整数转换的过程,这里要注意的是转换时是从低位到高位,如果要输出的话要进行倒序,体现在程序中就是先递归再输出。
|
|
负进制
在洛谷的这道题中,我们遇到了一个新的概念:负进制
在负进制数中是用 作为基数,例如 (十进制)相当于 (进制),并且它可以被表示为 的幂级数的和数:
如果按照上面所写的转换过程,就会出现一个问题,比如在C++里对进行取模和相除的结果是:
; ;
虽然式子是成立的,但我们得到的余数是负数,这肯定是不行的,所以我们要想办法进行转换。
所以我们可以将余数减去一个除数,同时将商+1。由于除数(绝对值)肯定是大于余数的,此时余数就会转换成正数。
下面是具体实现的代码:
|
|
位运算
位运算的基本概念在组成原理这些课上已经讲过不知道多少遍了,这里就只提一下我觉得重要的点。
位运算共有6种,分别是:与(&
)、或(|
)、异或(^
)、取反(~
)、左移(<<
)和右移(>>
)。
这里要特别注意一下右移运算,它分为逻辑右移和算术右移:
- 算术右移时,高位补最高位
- 逻辑右移时,高位补0
在C++中,数据类型包含有符号类型和无符号类型,其中有符号类型使用关键字 signed
声明,无符号类型使用关键字 unsigned
声明,两个关键字都不使用时,默认是有符号类型。对于有符号类型,右移运算为算术右移;对于无符号类型,右移运算为逻辑右移。
在学习和刷题时,我们容易发现,左移运算对应乘法运算。将一个数左移 位,等价于将这个数乘以 。例如, 左移 位的结果是 ,等价于 。
算术右移运算对应除法运算。将一个数右移 位,相当于将这个数除以 。例如, 右移 位的结果是 ,等价于 ,结果向下取整。
这里要注意,对于负数,整数除法是向 取整,右移运算是向下取整,两者就不相同了。例如,的结果是 ,而 的结果是,两者是不相等的。