内容:
若将十进制有理数转换为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,不过无伤大雅。感谢阅读。 创作不易,走路路过,一键三联一下呗。