将分数表示为任意进制的小数

最近在翻看一本数学分析教材中关于实数的基本理论的章节,其中对有理数的小数表示方法给出了严密的定义和详细的讨论。看后很有收获,然后突然就想到了这么个问题,如何编个程序将有理数的分数表示转换为小数表示,并且对于无限循环小数还要给出循环节来。

 花了半天时间将程序写好调通。把程序放在这里做个记录。

首先我先写了个只能处理正的真分数的程序。这是最简单的情况。不用判断正负号,也不用考虑整数部分。虽然说是任意进制,但是程序只支持到36进制,如果需要更多进制,可以修改程序。


void properfrac2str(int numerator, int denominator, int radix, char str[], int strl)
{
    const char table[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    int *num_array;
    int  find_loop = 0;
    int loop_from, loop_to;
    int i = 0, j;
    if(numerator == 0 || strl <= 1)
    {
        str[0] = 0;
        return;
    }
    num_array = (int *) malloc(strl * sizeof(int));
    num_array[0] = numerator;

    for (i = 0; i < strl - 3; i++)
    {
        numerator *= radix;
        str[i] = table[numerator / denominator];
        numerator %= denominator;

        if(numerator == 0)
        {
            str[i + 1] = 0;
            break; //finish
        }

        num_array[i + 1] = numerator;

        for(j = 0; j < i; j++)
        {
            if( numerator == num_array[j] ) // Recurring decimal
            {
                loop_from = j;
                loop_to = i;
                //printf("\nloop from %d to %d\n", loop_from, loop_to);
                find_loop = 1;
                break;
            }
        }
        if(find_loop == 1)
        {
            str[loop_to + 2] = ']';
            str[loop_to + 3] = 0;
            for(j = loop_to; j >= loop_from; j --)
            {
                     str[j + 1] =  str[j];
            }
            str[loop_from] = '[';

            break;
        }
    }
    free(num_array);
}

一个简单的测试代码如下:

void properfrac2str(int numerator, int denominator, int radix, char str[], int strl);
int main()
{
    char str[100];
    properfrac2str(1, 71, 10, str, 99);
    printf("0.%s\n", str);
    return 0;
}

结果显示为: 0.[01408450704225352112676056338028169]  

[] 内为循环小数的循环节。

然后是处理任意分数,无非就是将分数分解为整数部分和真分数部分,还要判断下正负号。难度不大,下面是代码。

int frac2str(int numerator, int denominator, int radix, char *str, int strl)
{
    char strIntPart[33];
    int l;
    int intPart;

    int sign = 1;
    if(denominator == 0)
    {
        fprintf(stderr, "ERROR: denominator is 0\n");
        return -2;
    }
    if( (numerator ^ denominator) < 0)
    {
        sign = -1;
        numerator = abs(numerator);
        denominator = abs(denominator);
    }
// reduction of a fraction
    l = gcd(numerator, denominator);
    numerator /= l;
    denominator /= l;

// seperate the fraction to an integer part and a proper fraction
    intPart = numerator / denominator;
    numerator = numerator % denominator;

    itoa(intPart, strIntPart, radix);
    strcat(strIntPart, ".");
    l = strlen(strIntPart);
    if(sign == -1)
    {
        str[0] = '-';
        str ++;
        strl --;
    }
    if(strl < l)
    {
        fprintf(stderr, "ERROR:string is too short to hold the result!\n");
        return -1;
    }
    strcpy(str, strIntPart);

//    printf("%s", str);
    if(numerator != 0 && strl - l != 0)
    {
        properfrac2str(numerator, denominator, radix, str + l,  strl - l);
    }
    return 0;
}

其中用到了求两个整数的最大公因数的函数,代码如下:

int gcd(int a, int b)
{
    int temp;

    while(a != 0)
    {
        temp =  b % a;
        b = a;
        a = temp;
    }
    return b;
}

还用到了将整数转化成字符串的函数 itoa, 代码如下:

#define FALSE 0
#define TRUE 1

/**
* 把一整数转换为字符串
* @para num 待转化的整数
* @para str 保存转换后得到的字符串
* @para radix 基数
* @ret 指向生成的字符串
**/
char* itoa ( int num, char* str, int radix )
{
    const char table[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    char* ptr = str;
    int negative = FALSE;
    if ( num == 0 ) //num=0
    {
        *ptr++ = '0';
        *ptr = '\0'; // don`t forget the end of the string is '\0'!!!!!!!!!
        return str;
    }
    if ( num < 0 ) //if num is negative ,the add '-'and change num to positive
    {
        *ptr++ = '-';
        num *= -1;
        negative = TRUE;
    }
    while ( num )
    {
        *ptr++ = table[num % radix];
        num /= radix;
    }
    *ptr = '\0'; //if num is negative ,the add '-'and change num to positive
// in the below, we have to converse the string
    char* start = ( negative ? str + 1 : str ); //now start points the head of the string
    ptr--; //now prt points the end of the string
    while ( start < ptr )
    {
        char temp = *start;
        *start = *ptr;
        *ptr = temp;
        start++;
        ptr--;
    }
    return str;
}

最后是用例:

int main()
{
    char str[100];
    frac2str(-666, 71, 10, str, 99);
    puts(str);
    return 0;
}

显示结果为:

-9.[38028169014084507042253521126760563]

经验证,这个结果没有问题。


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值