将十进制有理数转化为m进制数(C语言实现)

内容:

若将十进制有理数转换为r进制的数,应如何实现。

步骤:

1.算法分析:

       进行算法分析前,首先需要了解一些进制转换的知识,十进制整数转换二制是采用“除2取余,逆序输出”的方法,即辗转相除法。但是有理数不止包含整数,也包含小数,小数的转换与整数略有不同。

       那么怎么利用辗转相除法进行整数进制转化呢?这里以789.8125为例进行二进制转换:

       因为整数和小数的转化方法略有不同,所以将789.8125分开处理,先处理整数部分:

       789 / 2 = 394  ( 1)

       394 / 2 = 197  ( 0)

       197 /2 = 98    ( 1)

       98 / 2 = 49    ( 0)

       49 / 2 = 24    ( 1)

       24 / 2 = 12    ( 0)

       12 / 2 = 6     ( 0)

       6 / 2 = 3      ( 0)

       3 / 2 =1       ( 1)

      1 / 2 =0       ( 1)

         则789的十进制转二进制结果为:1100010101

        由此可见,10进制转2进制就是,除2取余;再用商除2取余,一直到被除数(商)为0,余数的逆序就是该2进制数。所以,10进制转m进制就是,除m取余;再用商除m取余,一直到被除数(商)为0,余数的逆序就是该m进制数。

         上述即为整数转化进制的辗转相除法,但是小数部分要怎么处理呢?

        以十进制转二进制为例,十进制小数部分转二进制小数是采用“乘2取整,顺序排列”法。具体做法是:用2乘十进制小数,可以得到积,将积的整数部分取出,再用2乘余下的小数,又得到一个积,再将积的整数部分取出,如此进行,直到积中的小数部分为0,或者达到所要求的精度为止。然后把取出的整数部分按顺序排列起来,先取的整数作为二进制小数的高位有效位,后取的整数作为低位有效位。

        下面处理789.8125小数部分,将0.8125转换为二进制小数:

         0.8125 * 2 = 1.6250 ……….取整数:1

         0.6250 * 2 = 1.2500 ……….取整数:1

         0.2500 * 2 = 0.5000 ……….取整数:0

         0.5000 * 2 = 1.0000 ……….取整数:1

       所以0.8125转化为二进制结果为0.1101。

       所以789.8125转化为二进制结果为:1100010101.1101

       另外,有些数字在转换过程中会发生循环现象,会存在损失精度现象,这里不展开讨论。

       由上述过程可以看到,转换过程不同于整数的辗转相除法。所以在进行有理数转换时,需要将整数部分和小数部分分开进行转换。整数部分依然使用辗转相除法进行计算。小数使用(假设转为m进制)“乘m取整,顺序排列”的方法。

       同时考虑到较大进制中存在着字母,所以对于转换的目标进制也要考虑。

       因此算法设计是用三个函数分别实现链栈的入栈、判断栈空和出栈操作。先对传进来的数进行取小数操作,并判断是否有小数,无小数利用if……else语句分别实现整数和负数的转化,转化的思想是辗转相除法。小数部分乘以对应进制,进行进制的转换。若转化的进制大于10,则用字母A、B、C、D等表示,再将两部分合起来。整数部分利用栈的特性,先进后出,得到对应进制。小数部分因为是顺序输出,是先进先出,所以不需要栈,直接输出即可。

2.概要设计:

函数 作用
Seqstack() 初始化一个顺序栈
Conversion() 实现整数部分转换
Pop() 实现元素的出栈操作
Empty() 实现栈的判空操作
Conver() 实现小数部分的转换操作

3.程序的流程图

  

 4.源代码如下(编译环境:vc++6.0):

#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#define maxsize 1000000

typedef struct//栈
{
	char c[maxsize];
	int top;
}seqstack;

int empty_seqstack(seqstack *s)//判断栈是否满
{
	if(s->top==-1)
		return 1;
	else
		return 0;
}

void push_seqstack(seqstack *s,char x)//入栈
{
	if(s->top==maxsize-1)           //判断栈是否满
		printf("stack is full\n");
	else
	{
		s->top++;   //先是top加1,避免覆盖原始数据
		s->c[s->top]=x;
	}
}

void pop_seqstack(seqstack*s)
{
	char x;
	while(s->top!=-1) //判断是否为空栈
	{
		x=s->c[s->top];
		printf("%c",x);
		s->top--;
	}

}

void conversion(int a,int r,seqstack *s)
{
	char x;
	while(a!=0)
	{
		if(a%r<=9)
		{
			x=a%r+'0';
			push_seqstack(s,x);
		}
		else
		{
			x=a%r+'A'-10;
			push_seqstack(s,x);
		}
		a=a/r;
	}
}
void conver_decimal(float de,int r)
{
	float flag;
	de =de -(int)de;//先是对传进来的实数进行了取小数
	int dc;
	char x1;
	char s[100000]=".";
	int i=1;
	flag =de; //用于判断实数是否有小数部分

	while(de>0.000001)
	{
		if((int)(de*r)<=9)
		{
			dc = (int)(de*r);   //小数部分乘以对应进制,进行进制的转换
			de =de *r;
			de = de - dc;
			x1 = dc +'0';
			s[i++]=x1;
		}
		else
			{
			dc = (int)(de*r);
			de =de *r;
			de = de - dc;
			x1 = dc +'A'-10;//进制大于10,,则用字母A,B,C来表示
			s[i++]=x1;
		}
	}
	if(flag!=0)
	{
		printf("%s",s);
	}
}

int main()
{
	float a;
	int r;
	seqstack *s;
	s=(seqstack*)malloc(sizeof(seqstack));
	s->top=-1; // -1定义为栈空
	printf("请输入要转换的数和进制\n");
	scanf("%f %d",&a,&r);
	conversion(a,r,s); //将数字对的整数部分转换成对应进制
	pop_seqstack(s); //利用栈的特性,先进后出,得到对应进制。
	conver_decimal(a,r); //小数部分算法,不需要栈,先进先出即可,因此顺序输出
	return 0;
}

 5.样例测试:

5.1 纯小数二进制测试

5.2 整数+小数二进制测试:

5.3  整数+小数其他进制(16进制)测试:

5.4 小数其他进制(16进制)测试:

     至此,问题已全部解决。但还存在着一个小问题,就是纯小数输出时,小数点前面少0,不过无伤大雅。感谢阅读。 创作不易,走路路过,一键三联一下呗。

猜你喜欢

转载自blog.csdn.net/qbyyds/article/details/120799789