C++/C知识点:进制转换

知识点:进制

进制也就是进位计数制,是人为定义的带进位的计数方法(有不带进位的计数方法,比如原始的结绳计数法,唱票时常用的“正”字计数法,以及类似的tally mark计数)。 对于任何一种进制---X进制,就表示每一位上的数运算时都是逢X进一位。 十进制是逢十进一,十六进制是逢十六进一,二进制就是逢二进一,以此类推,x进制就是逢x进位。

名词介绍

进位制/位置计数法

进位制/位置计数法是一种记数方式,故亦称进位记数法/位值计数法,可以用有限的数字符号代表所有的数值。可使用数字符号的数目称为基数(en:radix)或底数,基数为n,即可称n进位制,简称n进制。现在最常用的是十进制,通常使用10个阿拉伯数字0-9进行记数。

对于任何一个数,我们可以用不同的进位制来表示。比如:十进数57(10),可以用二进制表示为111001(2),也可以用五进制表示为212(5),也可以用八进制表示为71(8)、用十六进制表示为39(16),它们所代表的数值都是一样的。

进制一览

十进制

人类天然选择了十进制

由于人类解剖学的特点,双手共有十根手指,故在人类自发采用的进位制中,十进制是使用最为普遍的一种。成语“屈指可数”某种意义上来说描述了一个简单计数的场景,而原始人类在需要计数的时候,首先想到的就是利用天然的算筹——手指来进行计数。

十进制编码几乎就是数值本身。

数值本身是一个数学上的抽象概念。经过长期的演化、融合、选择、淘汰,系统简便、功能全面的十进制计数法成为人类文化中主流的计数方法,经过基础教育的训练,大多数的人从小就掌握了十进制计数方法。盘中放了十个苹果,通过数苹果我们抽象出来“十”这一数值,它在我们的脑海中就以“10”这一十进制编码的形式存放和显示,而不是其它的形式。从这一角度来说,十进制编码几乎就是数值本身。

十进制的基数为10,数码由0-9组成,计数规律逢十进一。

二进制

二进制有两个特点:它由两个数码0,1组成,二进制数运算规律是逢二进一。

为区别于其它进制,二进制数的书写通常在数的右下方注上基数2,或在后面加B表示,其中B是英文二进制Binary的首字母。

例如:二进制数10110011可以写成(10110011)2,或写成10110011B。对于十进制数可以不加标注,或加后缀D,其中D是英文十进制Decimal的首字母D。计算机领域我们之所以采用二进制进行计数,是因为二进制具有以下优点:

1.二进制数中只有两个数码0和1,可用具有两个不同稳定状态的元器件来表示一位数码。例如,电路中某一通路的电流的有无,某一节点电压的高低,晶体管的导通和截止等。

2.二进制数运算简单,大大简化了计算中运算部件的结构。

二进制数的加法和乘法基本运算法则各有四条,如下:

0+0=0,0+1=1,1+0=1,1+1=10

0×0=0,0×1=0,1×0=0,1×1=1

3.二进制天然兼容逻辑运算

但是,二进制计数在日常使用上有个不便之处,就是位数往往很长,读写不便,如:把十进制的100000D写成二进制就是11000011010100000B,所以计算机领域我们实际采用的是十六进制。二进制数转换为十六进制数时,长度缩减为原先的约四分之一,把十进制的100000写成八进制就是303240。十六进制的一个数位可代表二进制的四个数位。这样,十进制的100000写成十六进制就是186A0。

八进制

由于二进制数据的基数R较小,所以二进制数据的书写和阅读不方便,为此,在小型机中引入了八进制。八进制的基数R=8=2^3,有数码0、1、2、3、4、5、6、7,并且每个数码正好对应三位二进制数,所以八进制能很好地反映二进制。八进制用下标8或数据后面加O表示 例如:二进制数据 (11 101 010 . 010 110 100)2 对应八进制数据 (352.264)8或352.264O。

十六进制

由于二进制数在使用中位数太长,不容易记忆,所以又提出了十六进制数。

十六进制数有两个基本特点:它由十六个数码:数字0~9加上字母A-F组成(它们分别表示十进制数10~15),十六进制数运算规律是逢十六进一,即基数R=16=2^4,通常在表示时用尾部标志H或下标16以示区别,在c语言中用添加前缀0x以表示十六进制数。

例如:十六进制数4AC8可写成(4AC8)16,或写成4AC8H。

位权概念

对于形式化的进制表示,我们可以从0开始,对数字的各个数位进行编号,即个位起往左依次为编号0,1,2,……;对称的,从小数点后的数位则是-1,-2,……

进行进制转换时,我们不妨设源进制(转换前所用进制)的基为R1,目标进制(转换后所用进制)的基为R2,原数值的表示按数位为AnA(n-1)……A2A1A0.A-1A-2……,R1在R2中的表示为R,则有(AnA(n-1)……A2A1A0.A-1A-2……)R1=(An*R^n+A(n-1)*R^(n-1)+……+A2*R^2+A1*R^1+A0*R^0+A-1*R^(-1)+A-2*R^(-2))R2

(由于此处不可选择字体,说明如下:An,A2,A-1等符号中,n,2,-1等均应改为下标,而上标的幂次均用^作为前缀)

举例:

一个十进制数110,其中百位上的1表示1个10^2,既100,十位的1表示1个10^1,即10,个位的0表示0个10^0,即0。

一个二进制数110,其中高位的1表示1个2^2,即4,低位的1表示1个2^1,即2,最低位的0表示0个2^0,即0。

一个十六进制数110,其中高位的1表示1个16^2,即256,低位的1表示1个16^1,即16,最低位的0表示0个16^0,即0。

可见,在数制中,各位数字所表示值的大小不仅与该数字本身的大小有关,还与该数字所在的位置有关,我们称这关系为数的位权

十进制数的位权是以10为底的幂,二进制数的位权是以2为底的幂,十六进制数的位权是以16为底的幂。数位由高向低,以降幂的方式排列。

进数转换

1.二进制数十六进制数转换为十进制数(按权求和)

二进制数、十六进制数转换为十进制数的规律是相同的。把二进制数(或十六进制数)按位权形式展开多项式和的形式,求其最后的和,就是其对应的十进制数——简称“按权求和”.

例如:把(1001.01)2 二进制计算。

解:(1001.01)2

=8*1+4*0+2*0+1*1+0*(1/2)+1*(1/4)

=8+0+0+1+0+0.25

=9.25

把(38A.11)16转换为十进制数

解:(38A.11)16

=3×16的2次方+8×16的1次方+10×16的0次方+1×16的-1次方+1×16的-2次方

=768+128+10+0.0625+0.0039

=906.0664

2.十进制数转换为二进制数,十六进制数(除2/16取余法)

整数转换.一个十进制整数转换为二进制整数通常采用除二取余法,即用2连续除十进制数,直到商为0,逆序排列余数即可得到――简称除二取余法.

例:将25转换为二进制数

解:25÷2=12 余数1

12÷2=6 余数0

6÷2=3 余数0

3÷2=1 余数1

1÷2=0 余数1

所以25=(11001)2

同理,把十进制数转换为十六进制数时,将基数2转换成16就可以了.

例:将25转换为十六进制数

解:25÷16=1 余数9

1÷16=0 余数1

所以25=(19)16

3.二进制数与十六进制数之间的转换

由于4位二进制数恰好有16个组合状态,即1位十六进制数与4位二进制数是一一对应的.所以,十六进制数与二进制数的转换是十分简单的.

(1)十六进制数转换成二进制数,只要将每一位十六进制数用对应的4位二进制数替代即可――简称位分四位.

例:将(4AF8B)16转换为二进制数.

解: 4 A F 8 B

0100 1010 1111 1000 1011

所以(4AF8B)16=(1001010111110001011)2

(2)二进制数转换为十六进制数,从左向右每四位一组,依次写出每组4位二进制数所对应的十六进制数――简称四位合一位.

例:将二进制数(000111010110)2转换为十六进制数.

解: 0001 1101 0110

1 D 6

所以(111010110)2=(1D6)16

转换时注意最后一组不足4位时必须加0补齐4位

数制转换的一般化

(1)R进制转换成十进制

任意R进制数据按权展开、相加即可得十进制数据。例如:N = 1101.0101B = 1*2^3+1*2^2+0*2^1+1*2^0+0*2^-1+1*2^-2+0*2^-3+1*2^-4 = 8+4+0+1+0+0.25+0+0.0625 = 13.3125

N = 5A.8H = 5*16^1+A*16^0+8*16^-1 = 80+10+0.5 = 90.5

(2)十进制转换R 进制

十进制数转换成R 进制数,须将整数部分和小数部分分别转换.

1.整数转换——---除R 取余法 规则:(1)用R 去除给出的十进制数的整数部分,取其余数作为转换后的R 进制数据的整数部分最低位数字; (2)再用R去除所得的商,取其余数作为转换后的R 进制数据的高一位数字; (3)重复执行(2)操作,一直到商为0结束。例如:115 转换成 Binary数据和Hexadecimal数据 (图2-4) 所以 115 = 1110011 B = 73 H

2.小数转换————---乘R 取整法 规则:(1)用R 去乘给出的十进制数的小数部分,取乘积的整数部分作为转换后R 进制小数点后第一位数字; (2)再用R 去乘上一步乘积的小数部分,然后取新乘积的整数部分作为转换后R 进制小数的低一位数字; (3)重复(2)操作,一直到乘积为0,或已得到要求精度数位为止。

3.小数转换——整数退位法:举例:0.321d转成二进制,由于321不是5的倍数,用取余法、取整法可能要算很久,这时候我们可以采用整数退位法。原理如下:

n为转成的二进制数的小数位数

(x)10=(y)2

(x)10*2^n=(y)2*2^n

D=(x)10*2^n:计算10进制数,取整

D→T转成2进制数

(y)2=T/2^n=T*2^(-n),T退位,位数不足前端补零

举例:

0.321转成二进制数,保留7位

0.321*2^7=41.088,取整数41

41=32+8+1即100000+1000+1=101001

退位,因只有6位而要求保留7位,所以是0.0101001

用在线转换工具校验,正确

and、or、xor运算

所有进制的and(和)、or(或)、xor(异或)运算都要转化为二进制进行运算,然后对齐位数,进行运算,具体的运算方法和普通的and、or、xor相同,如:1and1=1,1and0=0,0and0=0,1or1=1,1or0=1,0or0=0,1xor1=0,1xor0=1,0xor0=0。就是一般的二进制运算。 

如:35(H)and5(O)=110101(B)and101(B)=111101(B)=75(O)=3D(H)

经典方法

十转n

#include <iostream>
using namespace std;

string digit = "0123456789ABCDEF";
string Dtom(int n,int m)
{
	string a = "";
	while(n > 0)
	{
		a = digit[n % m] + a;
		n /= m;
	}
	return a;
}

int main()
{
	int n, m;  
	cin >> n >> m;
	cout << Dtom(n, m) << endl;		
	return 0;
}

n转十

#include <iostream>
using namespace std;

int main()
{
	int m;
	cin >> m;
	string s;
	cin >> s;
	int ans = 0;
	for(int i = 0;i < s.size();i++)
	{
		if('0' <= s[i] && '9' >= s[i])
		{
			ans = ans * m + (s[i] - '0');
		}
		else
		{
			ans = ans * m + (s[i] - 'A' + 10);
		}
	}
	cout << ans << endl;
	return 0;
}

 

经典例题

Problem A: 牛记数 

Description

一头奶牛在研究数字的表示法,它只会二进制数,在泥地上它用一个脚印表示0,而用它的脚来表示1. 显然,它最多能表示4个位置上的1.
现给定一个范围[s,t]  ( 1 <= s,t <= 15,000,000),请问这头牛可以表示其中的多少个数.

Input

* 只一行: 两个整数s 和t.

Output

* 只一行: 用不多于4个1的二进制数可表示在[s,t]中的数的个数.

HINT
样例解释:
数    2进制数  1的个数 是否可表示
100  1100100   3       Yes
101  1100101   4       Yes
102  1100110   4       Yes
103  1100111   5       No
104  1101000   3       Yes
105  1101001   4       Yes
#include <iostream>
using namespace std;
int a[50];
bool check(int n)
{
    int l = 1,r = n;
    while(a[l] == a[r])
    {
        if(l == r || l + 1 == r)
        {
            return true;
        }
        l++;
        r--;
    }
    return false;
}
int change(int x,int r)
{
    int n = 0;
    while(x > 0)
    {
        n++;
        a[n] = x % r;
        x /= r;
    }
    return n;
}
int main()
{
    int n,s,cnt,x,f;
    cin >> n >> s;
    x = s;
    while(n > 0)
    {
        cnt = 0;
        x++;
        for(int i = 2;i <= 10;i++)
        {
            f = change(x,i);
            if(check(f))
            {
                cnt++;
            }
            if(cnt == 2)
            {
                cout << x << endl;
                n--;
                break;
            }
        }
    }
    return 0;
}

Problem B: 回文数 

Description

我们说一个数字如果从左到右和从右到左是一样得就是回文数。例如75457就是一个回文数。当然,这性质还依赖它的进制。17在十进制下不是回文数,不过在二进制下就是回文数了(10001) 。现在就是要一个数在2到16进制下是否回文数。

Input

输入数据由多个整数构成。每个给出的数字 0 < n < 50000各占一行,并且都是以十进制形式给出。输入以零为结束。

Output

你的程序要输出令所给数 I 是回文数的进制。如果这个数在2到16进制里都不是回文数,你的程序就要输出这个数不是回文数的信息:not a palindrom。

17
19
0
  • Sample Input
Number 17 is palindrom in basis 2 4 16
Number 19 is not a palindrom
  • Sample Output

 

#include <iostream>
using namespace std;
int a[50];
bool check(int n)
{
    int l = 1,r = n;
    while(a[l] == a[r])
    {
        if(l == r || l + 1 == r)
        {
            return true;
        }
        l++;
        r--;
    }
    return false;
}
int change(int x,int r)
{
    int n = 0;
    while(x > 0)
    {
        n++;
        a[n] = x % r;
        x /= r;
    }
    return n;
}
int main()
{
    int x,cnt,f,r[25];
    r[0] = 0;
    while(cin >> x)
    {
        if(x == 0)
        {
            break;
        }
        cnt = 0;
        for(int i = 2;i <= 16;i++)
        {
            f = change(x,i);
            if(check(f))
            {
                r[cnt++] = i;
            }
        }
        if(cnt == 0)
        {
            cout << "Number " << x << " is not a palindrom" << endl;
        }
        else
        {
            cout << "Number " << x << " is palindrom in basis";
            for(int i = 0;i < cnt;i++)
            {
                cout << " " << r[i];
            }
            cout << endl;
        }
    }
    return 0;
}

Problem C: niven数 

 

Description

一个数的自身能够被其各位数之和整除,则称这个数为Niven数。
例如:111是Niven数。因为111 mod (1+1+1)=0。
同样地, 我们也可以在另一个b进制数中指定一个数字,如果它的数字之和能够整除它,则b进制数中的该数字是Niven数。
例如:二进制数 1010是Niven数,因为:二进制数1010转为十进制后是10,而10 mod(1+0+1+0)=0;
 
给出 数制b (2<=b<=10) 和一个b数制的数,你要判断这个数是否是Niven数。
输入数据包含多组数据。

Input

每个测试数据占一行,先是数制b,之后是一个合法的数制中的数。
b为0表示测试块结束。

Output

如果该数在该数制为Niven数,就输出"yes",否则输出"no"。
两个测试块之间用空行隔开。

 

#include <iostream>
using namespace std;
int main()
{
    string a;
    int r;
    while(cin >> r && r != 0)
    {
        cin >> a;
        int n = 0,sum = 0,len = a.size();
        for(int i = 0;i < len;i++)
        {
            sum += a[i] - '0';
            n = a[i] - '0' + n * r;
        }
        if(n % sum == 0)
        {
            cout << "yes" << endl;
        }
        else
        {
            cout << "no" << endl;
        }
    }
    return 0;
}

有用的视频

 【最强干货】详解二进制,八进制,十进制,十六进制的相互转换_哔哩哔哩_bilibili

这一定是你听过的,最简单的进制转换讲解_哔哩哔哩_bilibili

参考文献

进制_百度百科

小视野信息学竞赛OJ

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值