2 qq 34174865 qq_34174865 于 2016.03.17 08:36 提问

c语言程序设计(很难的一道题)

一、将分数变小数:写出一个程序,接受一个以N/D的形式输入的分数,其中N为分子,D为分母,输出它的小数形式。如果它的小数形式存在循环节,要将其用括号括起来。例如:1/3=.00000...表示为.(3),又如41/333=.123123123...表示为.(123)。
一些转化的例子: 1/3=.(3) 22/5=4.4 1/7=.(142857) 3/8=.375 45/46=.803(571428)
  用上面的分数和13/79来测试你的程序。求高手

2个回答

cxsmarkchan
cxsmarkchan   2016.03.17 15:02
已采纳

有两个关键点:
1. 不能用float等浮点数类型,要用整数类型和高精度处理。
2. 需要了解循环小数的产生来源于除数中有2和5以外的因子。
以下C++代码在g++下编译通过,可以处理D<10000的情况,循环节不超过40位。我的电脑上没有C编译程序,但除了头文件包含部分,我都尽量按照C语言的格式写了,希望对你有帮助。
不过,45/46你给的结果不正确,应该是:.9(7826086956521739130434),你可以用计算器验算一下。
望采纳。

#include <cstdio>
#include <cstdlib>
#include <string>
#include <cstring>
using namespace std;

#define LEN 10
#define EACH_MAX 10000

//高精度取余
int exactRemainder(int* K, int D){
    int i;
    int tmp[LEN];
    memcpy(tmp, K, sizeof(int) * LEN);
    for(i = LEN - 1; i > 0; i--){
        tmp[i] %= D;
        tmp[i - 1] += tmp[i] * EACH_MAX;
    }
    return tmp[0] % D;
}

//高精度输出循环节(99999...999/D*N)
void printCirculator(int *K, int D, int N){
    int begin = 0;
    int i;
    int tmp[LEN];
    memcpy(tmp, K, sizeof(int) * LEN);

    for(i = LEN - 1; i > 0; i--){
        tmp[i - 1] += (tmp[i] % D) * EACH_MAX;
        tmp[i] /= D;
    }
    tmp[0] /= D;

    for(i = 0; i < LEN; i++){
        tmp[i] *= N;
    }
    for(i = 0; i < LEN - 1; i++){
        tmp[i + 1] += tmp[i] / EACH_MAX;
        tmp[i] %= EACH_MAX;
    }

    for(i = LEN - 1; i >= 0; i--){
        if(begin == 1){
            printf("%04d", tmp[i]);
        }else if(tmp[i] != 0){
            begin = 1;
            printf("%d", tmp[i]);
        }
    }
}

//在999..9前面再加一个9
void next9(int *K){
    int i;
    for(i = 0; i < LEN; i++){
        K[i] *= 10;
    }
    for(i = 0; i < LEN - 1; i++){
        if(K[i] >= EACH_MAX){
            K[i + 1] += K[i] / EACH_MAX;
            K[i] %= EACH_MAX;
        }
    }
    K[0] += 9;
}

int main(){
    int N, D;
    int K[LEN];
    memset(K, 0, sizeof(int) * LEN);
    scanf("%d%d", &N, &D);

    //如果N比D大,则有整数部分,先输出
    if(N >= D){
        printf("%d", N / D);
    }
    N %= D;
    //小数点
    printf(".");

    //把D因子中的10,2,5都除去
    while(1){
        if(D % 10 == 0){
            D /= 10;
            if(N % 10 == 0){
                N /= 10;
            }else if(N >= D){
                printf("%d", N / D);
                N %= D;
            }else{
                printf("%d", 0);
            }
        }else if(D % 2 == 0){
            N *= 5;
            D *= 5;
        }else if(D % 5 == 0){
            N *= 2;
            D *= 2;
        }else{
            break;
        }
    }
    //此时N < D且D因子中不含有2和5,即纯循环部分
    if(N != 0){
        printf("(");
        next9(K);
        while(exactRemainder(K, D) != 0){
            next9(K);
        }
        printCirculator(K, D, N);
        printf(")");
    }
    printf("\n");
    return 0;
}

cxsmarkchan
cxsmarkchan 问题是否解决了呢?写了这么长代码,解决了就采纳一下呗。
一年多之前 回复
mlw519
mlw519   2016.03.17 08:57

你这道题没意义。
因为计算机丢失的精度究竟是循环部分,还是精度失真的部分你没法说清楚。
N/D=(N/D)(括号中的代表结果),(N/D)*D这个值你能说清楚是怎么来的吗?

Csdn user default icon
上传中...
上传图片
插入图片
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!