C++-030-位运算与进制

C+±030-位运算与进制-2020-3-11

一、位运算

1>二进制

二进制是计算技术中广泛采用的一种数制。二进制数据是用0和1两个数码来表示的数。它的基数为2,进位规则是"逢二进一",借位规则是"借一当二",由18世纪德国数理哲学大师莱布尼兹发现。当前的计算机系统使用的基本上是二进制系统(曾有人研究过三进制系统)。
1.二进制加法

二进制 十进制
0000 0
0001 1
0010 2
0011 3
0100 4
0101 5
0110 6
0111 7

有四种情况:
0+0=0
0+1=1
1+0=1
1+1=10 //进位为1
例如,计算(1101)2+(1011)2的和。//2是位于括号外右下角
解:
1101//1000+100+1
‘+’
1011//1000+10+1


//1+1=10
//10+10=100
//100+100=1000
//1000+1000=10000
//10000+1000=11000
11000
2.二进制减法
有四种情况:
0-0=0
1-0=1
1-1=0
10-1=1
例如
3-1=0011-0001=0010
5-2=0101-0010=0011
3.二进制乘法
0 * 0 = 0 
0 * 1 = 0,
1 * 0 = 0,
1 * 1 = 1
4.二进制除法
0÷0 = 0
0÷1 = 0
1÷0 = 0 (无意义)
1÷1 = 1
原码:
计算机存储的二进制数中,第一个数表示是正数还是负数,即0表示正数;1表示负数。剩下的数表示所要表示的数的绝对值,如(0010)2=2;(1010)2=-2。//2是括号外右下角
反码:
原码在计算机中使用不方便,因此引入了反码,正数的反码与原码相同,负数的反码,原码按位取反。反码就是负数在二进制除了第一个数表示符号外,其他的数都依次取反,比如127=01111111,而-127=10000000;
补码:
虽然反码方便但是在正数和负数的计算中会出错,因为0000=0,1111=-0=0,有两个数表示同一个数,所以在计算中会少一,补码就是在负数的反码上加上一。多数机器的整数采用补码表示法。正数补码与原码相同,负数补码,最高位为1,其余位为原码取反再加1,比如-5=11111010(反码),补码为-5=11111011。
如求补码11111011的十进制数,即最高位不动,其余位取反得10000100,加1得10000101,即-5。如表是一些整数的原码、反码和补码的表示方法。

16位操作系统的数据 原码 反码 补码
+7 00000111 00000111 00000111
-7 10000111 11111000 11111001
+0 00000000 00000000 00000000
-0 10000000 11111111 00000000

补码的加减法运算十分方便,它不必判断数的正负,只要符号位参加运算,便能自动得到正确的结果。假设机器字长为8位,
下列例子说明

补码的加法
1.
十进制----------------------二进制
25---------------------------00011001
±----------------------------+
32---------------------------00100000
———————————————
57---------------------------00111001

2.
十进制----------------------二进制
32---------------------------00100000
±----------------------------+
(-25)------------------------11100111
———————————————
7-----------------------------↓00000111
——————————1自动丢弃
3.
十进制----------------------二进制
25---------------------------00011001
±----------------------------+
(-32)------------------------11100000
———————————————
-7----------------------------11111001
4.
十进制----------------------二进制
-25---------------------------11100111
±----------------------------+
(-32)-------------------------11100000
———————————————
57---------------------------↓11000111
——————————1自动丢弃
补码的减法运算与此同理,下面以几个例子来说明
1.
十进制----------------------二进制
25---------------------------00011001//00011001对减数求补,将减法转化为加法
-----------------------------+
(-32)-------------------------11100000//-00100000
———————————————
-7---------------------------11111001
2.
十进制----------------------二进制
32---------------------------00100000//00100000对减数求补,将减法转化为加法
------------------------------+
(-25)------------------------00011001//-11100111
———————————————
57---------------------------00111001
3.
十进制----------------------二进制
-25---------------------------11100111//11100111对减数求补,将减法转化为加法
-----------------------------+
-(+32)-------------------------11100000//-00100000
———————————————
57---------------------------↓11000111
——————————1自动丢弃
4.
十进制----------------------二进制
-25---------------------------11100111//11100111对减数求补,将减法转化为加法
-----------------------------+
-(-32)------------------------00100000//-11100000
———————————————
7-----------------------------↓00000111
———————————1自动丢弃

2>位运算符

C++语言提供表所列出的位运算符

运算符 含义
& 按位与(and)
| 按位或(or)
^ 按位异或(xor)
~ 取反(not)
<< 左移(shl)
>> 右移(shr)

位运算的优先级:not>and,shl,shr>or,xor。
输入十进制以二进制显示

//输入十进制以二进制显示
#include<iostream>
using namespace std;
int main()
{
	int m,number,s[32];
	cin>>number;
	for(int i=1;i<=32;i++)//32位的编译器
	s[i-1]=number>>(i-1)&1;//将每一位移到最右端与1进行与运算
	for(int i=31;i>=0;i--)
	cout<<s[i]<<' ';
	return 0; 
} 
3
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1
--------------------------------
Process exited with return value 0
Press any key to continue . . .

输入二进制以十进制显示

//输入二进制以十进制显示
#include<iostream>
using namespace std;
int show10(char *c)
{
	int num=0;
	for(int i=0;i<=31;i++)
	num=(num<<1)+c[i];
	return num;
} 
int main()
{
	int x;
    char c[32];
    for(int i=0;i<=31;i++)//以字符形式输入32位的二进制数
	cin>>c[i];
	for(int i=0;i<=31;i++) //字符转换为数字
	c[i]=c[i]-'0';
	cout<<show10(c)<<endl; 
	return 0; 
} 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1
3

--------------------------------
Process exited with return value 0
Press any key to continue . . .

位运算符

1.按位与运算符

按位与运算符(&):参加运算的两个运算量,如果两个相应的位都位1,则该位的结果值位1,否则为0。即:
0&0=0;
0&1=0;
1&0=0;
1&1=1;
按位与运算符通常用于二进制取位操作,例如一个数and 1的结果就是取二进制的最末位。这可以用来判断一个整数的奇偶,二进制的最末位为0表示该数为偶数;最末位为1表示该数为奇数。

//判断奇偶性 
#include<iostream>
using namespace std;

int main()
{
	int x;
    cin>>x;
    if((x&1)==0)//注意位运算的优先级很低,所以必须加括号
	cout<<x<<"是偶数"<<endl;
	else
	cout<<x<<"是奇数"<<endl; 
	return 0; 
} 
3
3是奇数

--------------------------------
Process exited with return value 0
Press any key to continue . . .

如果A,B为整数,实际上可看成长度为32的二进制数各个位做上述操作。例如当A=10(二进制位1010),B=12(二进制为1100)时,A&B=8(1010 & 1100=1000)。

//两个整数按位与 
#include<iostream>
using namespace std;

int main()
{
    int a=10;
    int b=12;
    int c=a & b;
    cout<<c<<endl;//输出结果为8 
	return 0; 
} 
8

--------------------------------
Process exited with return value 0
Press any key to continue . . .

2.按位或运算符

按位或运算符(|):两个相应位中只要有一个为1,该位的结果值位1。即:
0|0=0;0|1=1;1|0=0;1|1=1;
按位或运算通常用于二进制特定位上的无条件赋值,例如一个数or1的结果就是把二进制最末位强行变成1。如果需要把二进制最末位变成0,对这个数or1之后再减1就可以了,其实际意义就是把这个数强行变成最接近的偶数。

//求最接近原数的偶数 
#include<iostream>
using namespace std;

int main()
{
    int x;
	cin>>x;
	if(x&1==1)
	x=(x|1)-1;//注意位运算的优先级很低,所以必须加括号
	cout<<x<<"是最接近原数的偶数"<<endl; 
	return 0; 
} 
7
6是最接近原数的偶数

--------------------------------
Process exited with return value 0
Press any key to continue . . .

如果A,B为整数,实际上可看成长度为32的二进制数各个位做上述操作。例如当A=10(二进制为1010),B=12(二进制为1100)时,A|B=14(1010|1100=1110)。

//两个整数按位或 
#include<iostream>
using namespace std;

int main()
{
    int a=10;
    int b=12;
    int c=a|b;
    cout<<c<<endl;//输出结果为14 
	return 0; 
} 
14

--------------------------------
Process exited with return value 0
Press any key to continue . . .

3.按位异或运算符

按位异或运算符(^):它的规则是参加运算的两个相应位同号,则结果为0,异号则为1。xor的直观意思就是"是不是不一样"。即:

0^0=0;
0^1=1;
1^0=1;
1^1=0;

如果A,B为整数,实际上可看成长度为32的二进制各个位做上述操作。例如当A=10(二进制为1010),B=12(二进制1100)时,A^B=6(1010^1100=0110)

//两个整数异或 
#include<iostream>
using namespace std;

int main()
{
    int a=10;
    int b=12;
    int c=a^b;
    cout<<c<<endl;//输出结果为6
	return 0; 
} 
6

--------------------------------
Process exited with return value 0
Press any key to continue . . .

xor运算的逆运算是它本身,也就是说两次异或同一个数最后结果不变,即(a xor b) xor b=a。xor运算可以用于简单的加密,例如甲方欲发送1314520这个数字给乙方,约定任取一个数加12345678作为密钥。则甲方首先计算1314520 xor 12345678 的值即11038614后,将11038614发送给乙方,乙方再次计算11038614 xor 12345678 的值,就可得到1314520的值。

//异或加密 
#include<iostream>
using namespace std;

int main()
{
    int x=1314520;
    x=x^12345678;
    cout<<"加密后的值为:"<<x<<endl;
	x=x^12345678;
	cout<<"解密后的值为:"<<x<<endl; 
	return 0; 
} 
加密后的值为:11038614
解密后的值为:1314520

--------------------------------
Process exited with return value 0
Press any key to continue . . .

异或的另一个用处是交换两个整数,不用临时变量,但是这种方法经验检测有一定的局限性,例如不能写再函数里,否则结果会出错,例如快速排序算法里的swap函数如这样写:
a=a^b;
b=a^b;
a=a^b;
会出现a和b代表相同元素交换处’0’的情况。
所以平常的交换值,还是使用最朴素的两数交换的方法。此外根据测试,再Dev-C++环境下,使用该方法并未见明显的时间优势。

//交换两个整数,不用临时变量 
#include<iostream>
using namespace std;

int main()
{
    int a=123; 
	int b=798;
	a=a^b;
	b=b^a;
	a=a^b;
	cout<<a<<" "<<b;//输出结果为789 123 
	return 0; 
} 
798 123
--------------------------------
Process exited with return value 0
Press any key to continue . . .

有一组连续的数字,从1到n排列,中间丢失了一个数字,顺序也被打乱,放在一个n-1的数组里,请使用位运算的方法找出丢失的数字。
分析:由于1^1=0,2^2=0,n^n=0,因此将n-1个数异或后再来异或一下 1,2,…,n。
那么最终答案肯定是迷失的数字k^(1^1)^(2^2)^...^(n^n)。其时间复杂度为线性。

//缺失的数 
#include<iostream>
using namespace std;
int find(int a[] ,int size)
{
	int number=0;
	for(int i=0;i<size;i++)
	{
		number =number^(i+1)^a[i];
	}
	number^=(size+1);
	return number;
} 
int main()
{
  int a[10]={1,2,4,5,6,7,8,9,10,11};
  cout<<find(a,10)<<endl;
  return 0; 
} 
3

--------------------------------
Process exited with return value 0
Press any key to continue . . .

4.取反运算符

取反运算符(~),用来对一个二进制数按位取反,即将0变1,1变0.例如对二进制数1取反即:~1=0。
例如一个整数a为10,则~a=-11(~0…01010=1…10101,这里符号也取反(首位),因此变为负数)。

//取反运算符 
#include<iostream>
using namespace std;
int main()
{
 int a=10;
 int c=~a;
 cout<<c<<endl;//输出结果-11 
  return 0; 
} 
-11

--------------------------------
Process exited with return value 0
Press any key to continue . . .

使用取反运算时要格外小心,需要注意整数类型有没有符号。有符号的整数与无符号的整数取反结果是不一样的。对于无符号类型,取反后的效果就是把这个数在数轴上的位置"对称翻折到另一边去",因为无符号类型的数用0x00000000到0xFFFFFFFF依次表示的。
而对于有符号的类型,取反后最高位的变化导致了正负颠倒,又因为负数储存使用补码,所以效果就是变为-a-1。这与上下界没有任何关系。

//无符号取反 
#include<iostream>
using namespace std;
int main()
{
   unsigned short a=100;
   a=~a;
   cout<<a<<endl;//输出65435,即该类型的最大值-100,而不是-101
   return 0; 
} 
65435

--------------------------------
Process exited with return value 0
Press any key to continue . . .

移位运算符

1.左移运算符

左移运算符(<<);A<<B,表示A的所有二进制位整体向左移动B位,后面B位用0补充。与此相对应的为右移运算符(>>)。
例如100的二进制的值为1100100,则100<<2=110010000=400。可以看出,a<<b的值实际上就是a乘以2的b次方,因为在二进制数后添加一个0就相当于该数乘以2。
通常认为a<<1比aX2更快,因为前者是更底层一些的操作。因为程序中乘以2的操作请尽量用左移一位来代替。

#include<iostream>
using namespace std;
int main()
{
	int a=10;
	int b1=a<<2;//左移两位,即10*2^2=40
	int b2=a>>2;//右移两位,即10/2^2=2
	cout<<"b1="<<b1<<"b2="<<b2<<endl; 
} 
b1=40b2=2

--------------------------------
Process exited with return value 0
Press any key to continue . . .

定义一些常量可能会用到<<运算。你可以方便地用1<<16-1来表示32767。很多算法和数据结构要求数据规模必须是2的幂,此时可以用<<来定义Max_N等常量。

#include<iostream>
using namespace std;
int main()
{
short a;
unsigned short b;
a=1<<16-1;//short类型长度为16位 
b=1<<16-1;
cout<<a<<" "<<b<<endl;//输出-32768 32767
return 0; 

} 
-32768 32768

--------------------------------
Process exited with return value 0
Press any key to continue . . .

2.右移运算符

右移运算符:将一个数的各二进位右移,右移时,需要注意符号位问题,务必确保对非负整数进行运算,否则会出错。例如当A=-1时,对于任何位移运算A>>B,结果都是-1。
和左移相似,a>>b表示二进制右移b位(去掉末b位),相当于a除以2的b次方(取整)。我们也经常用>>1来代替除以2,比如二分查找、堆的插入操作等等。想办法用>>代替除法运算可以使程序效率大大提高。最大公约数的二进制算法用除以2操作来代替慢得出奇的mod运算,效率可以提高60%。

功能 示例 位运算
去掉最后一位 (101101→10110) x>>1
在最后加一个0 (101101→1011010) x<<1
在最后加一个1 (101101→1011011) (x<<1)+1
把最后一位变成1 (101101→101101) x
把最后一位变成0 (101101→101100) (x
最后一位取反 (101101→101100) x^1
把右数第k位变成1 (101101→101101,k=3) x|(1<<(k-1)
把右数第k位变成0 (101101→101001,k=3) X&~(1shl(k-1))
右数第k位取反 (101001→101101,k=3) x^(1<<(k-1))
取末三位 (1101101→101) x&7
取末k位 (1101101→1101,k=5) x&((1<<k)-1)
取右数第k位 (1101101→1,k=4) x>>(k-1)&1
把末k位变成1 (101001→101111,k=4) x|((1<<k)-1)
末k位取反 (101001→100110,k=4) x^((1<<k)-1)
把右边连续的1变成0 (100101111→100100000) x&(x+1)
把右起第一个0变成1 (100101111→100111111) x|(x+1)
把右边连续的0变成1 (11011000→11011111) x|(x-1)
取右边连续的1 (100101111→1111) (x^(x+1))>>1
去掉右起第一个1的左边 (100101000→1000) x&(x^(x-1))

可以用32位的整数的各个二进制位表示一个最多有32个元素的集合,第i位为1表示第i个元素在集合中,比如A=1011就可以表示集合{0,1,3},比如1<<x就可以表示一个状态集合,即集合中仅元素x存在而没有任何其他元素,因为其他所有位均为0。为0表示它不在集合中,常见操作有:
并集操作 A|B
交集操作 A&B
集合的差 A|~B
补集 -1~A(-1的二进制形式为111…111)
加入第i个元素A=A |(1<<i)
删除第i个元素A=A|~(1<<i)
判断第i个元素A|(i<<i)!=0
前面所说的位运算都没有涉及负数,都假设这些运算是在unsigned类型(只能表示正数的整形)上进行操作。
下面的程序是考察十六进制整数的储存方式。C++语言中表示十六进制数需要在数前加0x。

//考察十六进制整数的储存方式
#include<iostream>
using namespace std;
int main()
{
int a,b;
a=0x00000000;//00000000000000000000000000000000=0
b=0x00000001;//00000000000000000000000000000001=1
cout<<a<<" "<<b<<endl;
a=0xFFFFFFFE;//11111111111111111111111111111110=-2
b=0xFFFFFFFF;//11111111111111111111111111111111=-1
cout<<a<<" "<<b<<endl;
a=0x7FFFFFFF;//01111111111111111111111111111111=2147483647
b=0x80000000;//10000000000000000000000000000000=-2147483648
cout<<a<<" "<<b<<endl;
return 0;
} 
0 1
-2 -1
2147483647 -2147483648

--------------------------------
Process exited with return value 0
Press any key to continue . . .

程序的输出为0 1 -2 -1 2147483647 -2147483648。由此可以清楚地看到计算机是如何储存一个整数地:计算机用0x00000000到0x7FFFFFFF依次表示0到2147483647的数,剩下的0x80000000到0xFFFFFFF依次表示-2147483648到-1的数。
计算一个32位整数的二进制中1的个数的奇偶性,当输入数据的二进制表示里有偶数个数字1时程序输出0,有奇数个则输出1。例如,1314520的二进制101000000111011011000中有9个1,则x=1314520时程序输出1。

//最朴素程序 
#include<iostream>
using namespace std;
int main()
{
int i,x,c=0;
cin>>x;
for(i=1;i<=32;i++)
{
	c=c+(x&1);//判断最末位是0还是1
	x=x>>1;//去掉最右边一位 
}
cout<<(c&1);//判断奇偶 
return 0;
} 
7
1
--------------------------------
Process exited with return value 0
Press any key to continue . . .
//位运算判断
#include<iostream>
using namespace std;
int main()
{
	int x;
	cin>>x;
	x=x^(x>>1);
	x=x^(x>>2);
    x=x^(x>>4);
    x=x^(x>>8);
    x=x^(x>>16);
    cout<<(x&1)<<endl;
} 

例如,1314520的二进制为101000000111011011000,第一次异或操作的结果如下:
------00000000000101000000111011011000
XOR-0000000000010100000011101101100
————————————————————
------00000000000111100000100110110100
得到的结果是一个新的二进制数,其中右起第i位上的数表示原数中第i和i+1位上有奇数个i还是偶数个i。比如,最右边那个0表示原数末两位有偶数个1,右起第3位上的1就表示原数的第3位和第4位有奇数个1。对这个数进行第二次异或的结果如下:
-------00000000000111100000100110110100
XOR----000000000001111000001001101101
————————————————————
--------00000000000110011000101111011001
结果里的每个1表示原数的该位置及其前面三个位置中共有奇数个1,每个0就表示原数对应得四个位置上共偶数个1。一直做到第五次异或结束后,得到的二进制的最末位就表示整个32位数里有多少个1,这就是我们最终想要的答案。

//计算二进制中的1的个数
#include<iostream>
using namespace std;
int main()
{
	int x;
	cin>>x;
	//0x55555555=01010101010101010101010101010101
	x=(x&0x55555555)+((x>>1)&0x55555555);
	//0x33333333=00110011001100110011001100110011
	x=(x&0x33333333)+((x>>2)&0x33333333);
	//0x0F0F0F0F=00001111000011110000111100001111
	x=(x&0x0F0F0F0F)+((x>>4)&0x0F0F0F0F0);
	//0x00FF00FF=000000001111111100001111
	x=(x&0x00FF00FF)+((x>>8)&0x00FF00FF);
	//0x0000FFFF=00000000000000001111111111111111
	x=(x&0x0000FFFF)+((x>>16)&0x0000FFFF);
	cout<<"共有"<<x<<"个1"<<endl;
	return 0; 
} 
1
共有11

--------------------------------
Process exited with return value 0
Press any key to continue . . .

为了方便说明,假设机器字长8位,以数字211为例,211的二进制为11010011。计算结果如表

原始数据 1 1 0 1 0 0 1 1
第一次计算结果 1 0 0 1 0 0 1 0
第二次计算结果 0 0 1 1 0 0 1 1
第三次计算结果 0 0 0 0 0 1 0 1
最终结果 5 5 5 5 5 5 5 5

整个程序是一个分治的思想。第一次我们把每相邻的两位加起来,得到每两位里1的个数,比如前两位10就表示原数的前两位有2个1。第二次我们继续两两相加,10+01=11,00+10=10,得到的结果是00110010,它表示原数前4位有3个1,末4位有2个1。最后一次我们把0011和0010加起来,得到的就是整个二进制中1的个数。程序中巧妙地使用取位和右移,比如第二行中0x33333333的二进制为00110011001100…,用它和x做and运算就相当于以2为单位间隔取数>>的作用就是让加法运算的相同数位对齐。
二分查找32位整数的前导0个数

#include<iostream>
using namespace std;
int nlz(unsigned x)
{
    int n;
    if(x==0)
    return (32);
    n=1;
    if((x>>16)==0)
    {n+=16;x=x<<16;}
    if((x>>24)==0)
    {n+=8;x=x<<8;}
    if((x>>28)==0)
    {n+=4;x=x<<4;}
    if((x>>30)==0)
    {n+=2;x=x<<2;}
    n=n-(x>>31);
    return n;
} 
int main()
{
	unsigned x ,ans;
	cin>>x;//例如输入7,结果为29
	ans=nlz(x);
	cout<<ans<<endl;
	return 0; 
}
7
29

--------------------------------
Process exited with return value 0
Press any key to continue . . .

二、进制转换

除了十进制和二进制以外,还有其他进制,例如八进制和十六进制。
八进制采用0,1,2,3,4,5,6,7八个数码,逢八进位。八进制的数较二进制的数书写方便,常应用在计算机的计算中。例如:十进制的32表示成八进制就是40,八进制的32表示成十进制就是:3x81+2x80=26。
十六进制由0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F组成。其中A,B,C,D,E,F分别对应十进制的10,11,12,13,14,15。
各进制数之间的转换:
二进制转十进制:10110=1x24+0x23+1x22+1x21=0x20=22
八进制转十进制:125=1x82+281+5x80=85
十六进制转十进制:3A8=3x162+Ax161+8x160=936
十进制转二进制:
整数部分:
在这里插入图片描述
即53=110101
小数部分:
0.3125x2=0.6250 整数为0
0.6250x2=1.25 整数为1
0.25x2=0.50 整数为0
0.50x2=1.0 整数为1
即 0.3125x0.0101
二进制转八进制:
101 011 110=536
357=11 101 111
二进制转十六进制:
5AB=101 1010 1011
1 1001 0100 1011 =194B

C++处理数制转换的问题是相当方便的,我们完全可以用I/O流类库中的Dec(十进制表示)、Hex(十六进制表示)、Oct(八进制表示)的方法输出输出数据。

编写用除2取余法将十进制数转化为相应的二进制数的程序。

//取余法求二进制数
#include<iostream>
using namespace std;
void put(int number)
{
	int i;
	if(number>0)
	{
		i=number%2;
		number=number/2;
		put(number);
		cout<<i;
	}
} 
int main()
{
	int number;
	cin>>number;
	if(number==0)
	cout<<0;
	put(number);
	return 0;
}
2
10
--------------------------------
Process exited with return value 0
Press any key to continue . . .

利用位运算直接将十进制数转化为相应的二进制数。

//位运算求二进制数
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
	int number,i,j,m,ok=0;
	int s[50];
	memset(s,0,sizeof(s));//将数组所有元素初始化为0
	cin>>number;
	for(i=1;i<=32;i++)//32位的编译器
	{
		m=number>>(i-1)&1;//将每一位移到最右端与1进行与运算
		s[i]=m; 
	} 
	for(i=49;i>=1;i--)//倒序输出
	{
		if(ok==0&&s[i]==1)//忽略前面的0
		ok=1;
		if(ok==1)
		cout<<s[i]; 
	} 
	return 0;
} 
6
110
--------------------------------
Process exited with return value 0
Press any key to continue . . .

将十进制数转化为相应的十六进制数。

//十进制数转为十六进制数
#include<iostream>
#include<string>
using namespace std;
int main()
{
	int number,m,i;
	string s;
	cin>>number;
	for(i=0;i<=7;i++)
	{
		m=number>>(i*4)&15;//与15进行与运算后,再右移四位
		if(m<10)
		 s=char(m+48)+s;   //处理数字,注意相加的前后顺序
		 else
		 s=char(55+m)+s;//处理字母 
	}
	while(s[0]=='0')
	s.erase(0,1);//删除前导0
	cout<<s;
	return 0; 
} 
11
B
--------------------------------
Process exited with return value 0
Press any key to continue . . .

十进制转N进制数

/*
程序名称:十进制数转换为N进制数
程序说明:采用N反向除余的方式,注意特殊数据0的处理
*/
#include<iostream>
using namespace std;
string fun(int x,int n)
{
	const string a="0123456789ABCDEF";
	string s=" ";
	if(x==0)
	return "0";
	while(x>0)
	{
		s=a[x%n]+s;//后取得余数放在前面
		x=x/n; 
	}
	return s;
} 
int main()
{
	int x,n;
	cin>>x>>n;
	cout<<fun(x,n)<<endl;
	return 0;
}
6
2
110

--------------------------------
Process exited with return value 0
Press any key to continue . . .

十进制小数转为N进制数。转换的方法是"乘N顺序取整"。

//十进制小数转化为N进制
#include<iostream>
using namespace std;
double x;
int n;
string s;
void fun(double x,int n,int m)
{
	const string a="0123456789ABCDEF";
	int u;
	s='.';
	while(x>0&&m>0)
	{
		m--;//可用小数位减1 
		x=x*n;
		
		s=s+a[int(x)];//取余数依次放后面
		x=x-int(x);//取X的小数部分 
	}
	s='0'+s;
} 
int main()
{
	cin>>x>>n;
	if(x<1)
	fun(x,n,20);
	cout<<s;
	return 0;
}
0.1
8
0.0631463146314631464
--------------------------------
Process exited with return value 0
Press any key to continue . . .

N进制转换为十进制。

/*
程序名称 :N进制转为十进制
*/
#include<iostream>
using namespace std;
int fun(int n,string s)
{
	int i,t=0;
	for(i=0;i<=s.size();i++)
	{
		if(s[i]>='0'&&s[i]<='9')
		t=t*n+s[i]-48;
		else if(s[i]>='A'&&s[i]<='F')
		t=t*n+s[i]-55;
		else if(s[i]>='a'&&s[i]<='f')
		t=t*n+s[i]-87;
	}
	return t; 
} 
int main()
{
	int n;
	string str;
	cin>>n;
	cin>>str;
	cout<<fun(n,str)<<endl;
	return 0;
}
2
10
2

--------------------------------
Process exited with return value 0
Press any key to continue . . .

N进制小数转换为十进制。
转换的基本算法还是"乘权求和",只是程序有所不同,例如十进制数0.26345如果用2/10+6/100+3/1000+4/10000+5/100000计算的话只要做5次除法和4次加法就可以了。

//N进制小数转换为十进制
#include<iostream>
using namespace std;
double x,t,j;
double fun(double n,string s)
{
	int i;
	for(i=s.size();i>=1;i--)
	{
		if(s[i]>='0'&&s[i]<='9')
		t=t/n+s[i]-48;
		else if(s[i]>='A'&&s[i]<='F')
		t=t/n+s[i]-55;
		else if(s[i]>='a'&&s[i]<='f')
		t=t/n+s[i]-97;
		j=t/n;
	}
	return j;
}

int main()
{
	int n;
	string s;
	cin>>n;
	cin>>s;
	cout<<fun(n,s);
	return 0;
} 
10
0.1
0.1
--------------------------------
Process exited with return value 0
Press any key to continue . . .

N进制数的加法
N(N<37)进制数加法运算问题,即从键盘输入一个小于37的正整数N,再输入符号要求的两个N进制数,求两者之和,输出结果仍为N进制数。

//N进制数加法运算 
#include<iostream>
#include<cstring> 
using namespace std;
int main()
{
	string a,b,w;
	int x[100],y[100];
	int i,k,N;
	cin>>N;
	for(i=0;i<=N-1;i++)
	{
		if(i<10)
		w=w+char(i+48);//数字的处理
		else
		w=w+char(55+i);//字母的处理 
	}
	cout<<"w:"<<w<<endl;          //输出0123...ABC...序列 
	cin>>a>>b;
	while(a.length()<b.length())
	a='0'+a;
	while(b.length()<a.length())
	b='0'+b;             //前面多加一位,用于进位 
	a='0'+a; 
	b='0'+b;              
	cout<<"a:"<<a<<endl<<"b:"<<b<<endl<<endl;//检查输出是否正常
	for(i=a.length()-1;i>=0;i--)
	{
		x[i]=w.find(a[i],0);           //查找a[i]在W中的位置获得真实的数字
		y[i]=w.find(b[i],0);           //转换到x,y数组中准备相加 
	} 
	for(i=a.length()-1;i>=0;i--)       //进位加法
	{
		x[i]=x[i]+y[i];
		if(x[i]>=N)
		{
			k=i;
			while(x[k]>=N)
			{
				x[k]=x[k]-N;
				x[k-1]++;
				k--;
			}
		}
	} 
	for(i=a.length()-1;i>=0;i--)
	a[i]=w[x[i]];//转换为N进制数,a即是加法又是总数
	while (a[0]=='0')
	a.erase(0,1);//删除前导0
	cout<<a<<endl;
   	return 0; 
}
2
w:01
1
111
a:0001
b:0111

1000

--------------------------------
Process exited with return value 0
Press any key to continue . . .

N进制数转为十进制数的方法很简单,请看下面八进制转为十进制的方法就明白了。
(123)8=1x82+2x81+3x80//8在括号外右下角

发布了91 篇原创文章 · 获赞 101 · 访问量 3287

猜你喜欢

转载自blog.csdn.net/weixin_41096569/article/details/104791215