在实现进制转换前,我们要先了解进制转换的算法原理,以十进制转二进制为例:所采用的方法是“除二取余,逆序输出”,所以要借助栈进行逆序输出。而对于含有小数的有理数来说,整数部分仍遵循“除二取余,逆序输出”的规则,但小数部分的进制转换的算法不同,为“乘二取整,正序输出”的规则,由于是正序输出,所以不用借助栈,通过简单的循环语句也可打印输出。
当对整数进行进制转换时,对待转换的数先判断正负,通过if...else...算法分别实现正数和负数的转化(全部转化为正整数),转换的思想利用了算数运算中的取余和取整操作,借助栈先进后出的操作,进行辗转相除来实现。
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
typedef int datatype;
typedef struct node
{
datatype data;
struct node *next;
}*linkstack;
/*入栈*/
int Push(linkstack *top, datatype x)
{
linkstack s = (linkstack)malloc(sizeof(struct node));
if (s == NULL)
return 0;
s->data = x;
s->next = (*top);
(*top) = s;
return 1;
}
/*判空*/
int Empty(linkstack top)
{
if (top == NULL)
return 1;
return 0;
}
/*出栈*/
int Pop(linkstack*top, datatype*x)
{
if (top != NULL)
{
linkstack p = (*top);
(*x) = (*top)->data;
(*top) = (*top)->next;
free(p);
return 1;
}
return 0;
}
/*十进制整数转化为任意进制数*/
void Convert(int num, int mode)
{
int h;
linkstack top = NULL;
printf("转化结果为:");
if (num>0)
{
while (num != 0)
{
h = num%mode;
Push(&top, h);
num = num / mode;
}
while (!Empty(top))
{
Pop(&top, &h);
printf("%d", h);
}
printf("\n");
}
else if (num<0)
{
printf("-");
num = num*(-1);
while (num != 0)
{
h = num%mode;
if (h >= 10)
{
h = h - 10 + 'A';
}
Push(&top, h);
num = num / mode;
}
while (!Empty(top))
{
Pop(&top, &h);
printf("%d", h);
}
printf("\n");
}
else
printf("%d\n", 0);
}
void main()
{
int num, mode;
printf("\n输入要转化的数:");
scanf("%d", &num);
printf("输入要转化的进制:");
scanf("%d", &mode);
Convert(num, mode);
}
该整数进制转换算法存在问题如下:首先是只能进行整数的进制转换,并没有将小数进行转换的功能,其次,在进行进制数大于10转换的过程中,会出现输出问题,例如在下面的测试用例中,999的16进制正确转换应为3e7,但程序输出的是3 14 7,无法将大于10的数转换为字符。该问题会在有理数转换为n进制中实现。
对待转换的有理数数先进行小数和整数部分的分离操作,分离操作的重点在于int和double间进行转换时会有精度损失,再对分离后的小数以及整数部分分别判断正负,通过if...else...算法分别实现正数和负数的转化(将负数转为正数)。
小数部分和整数部分的在进行进制转换时所采用的算法是不同的,整数部分进行的是:与进制相除后的取余和取整操作,且为倒序输出;小数部分进行的是:与进制相乘后的取余和取整操作,且正序输出即可。
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
typedef char datatype;
typedef struct node
{
datatype data;
struct node*next;
}*linkstack;
/*入栈*/
int Push(linkstack *top, datatype x)
{
linkstack s = (linkstack)malloc(sizeof(struct node));
if (s == NULL)
return 0;
s->data = x;
s->next = (*top);
(*top) = s;
return 1;
}
/*判空*/
int Empty(linkstack top)
{
if (top == NULL)
return 1;
return 0;
}
/*出栈*/
int Pop(linkstack*top, datatype*x)
{
if (top != NULL)
{
linkstack p = (*top);
(*x) = (*top)->data;
(*top) = (*top)->next;
free(p);
return 1;
}
return 0;
}
/*十进制整数转化为任意进制数*/
void Convert_integer(int num, int mode)
{
int n;
char h;
linkstack top = NULL;
if (num>0)
{
while (num != 0)
{
n = num%mode;
h = num%mode +'0';//将int型数字转为对应字符
if (n >= 10)
{
n = n - 10 ;
h = n + 'A';//将大于10的int型数字转为对应字符
}
Push(&top, h);
num = num / mode;
}
while (!Empty(top))
{
Pop(&top, &h);
printf("%c", h);
}
}
else if (num<0)
{
printf("-");
num = num*(-1);
while (num != 0)
{
n = num%mode;
h = num%mode + '0';//将int型数字转为对应字符
if (n >= 10)
{
n = n - 10;
h = n + 'A';//将大于10的int型数字转为对应字符
}
Push(&top, h);
num = num / mode;
}
while (!Empty(top))
{
Pop(&top, &h);
printf("%c", h);
}
}
else
printf("0");
}
/*小数转化为任意进制数*/
void Convert_decimal(double num, int mode)
{
if (num < 0)
{
num = num*(-1);//转为正数
}
int a;
char b;
double flag;
while (1)//进行死循环
{
flag = num * mode;
a = flag;
if (a >= 10)
{
b = a - 10 + 'A';
}else{
b = a + '0';//将int型数字转为对应字符
}
printf("%c", b);
num = flag - a;
if (num==0)
{
break;//break语句用于跳出while死循环
}
}
}
void main()
{
double num, decimal;
int mode, integer;
printf("输入要转化的数:");
scanf("%lf", &num);
//利用精度损失来实现整数,小数进行分离
integer = num;
decimal = num - integer;
printf("输入要转化的进制:");
scanf("%d", &mode);
printf("转化结果:\n");
Convert_integer(integer, mode);
printf(".");
Convert_decimal(decimal, mode);
//通过整数部分和小数部分的分别转换,拼接而成最终的转换结果
}
则进制数大于10的字符转换问题得到解决,同时也完成了有理数的整数小数的转换。但还是存在问题,对于像-0.89这样的负小数,进行进制转换后,负号会丢失。希望有大佬帮忙解决一下,求求了。