编程之美--2.6 精确表达浮点数

/**

 * 本题目内容如下:

 * 在计算机中,有时使用float或double来存储小数是不能得到精确值的. 如果你需要得到精确计算结果,最好是用分数形式来表示小数。有限小数或者无限循环小数都可以转化为分数。

 * eg:
0.9 = 9/10;

 *
0.33(3) = 1/3(括号里的数字表示的的是循环节)

 * 当然一个小数可以用好几种弄分数形式来表示. 如:

 * 0.33(3) = 1 / 3 = 3 / 9;

 * 给定一个有限小数或无限循环小数, 你能否异分母最小的分数形式来返回这个小数呢?

 * 如果输入为循环小数, 循环节用括号标记出来.

 */

/**

 * 在此处假定, 输入的数字以回车为结束. 由于输入中带有括号, 所以可以把数字看成是字符串, 以字符的形式读入.

 * 新创建一个结构体用于表示分数, 结构体字段有两个即可: 一个分子, 一个分母;

 * 如此一来, 对于有限小数, 本题便转换成了求两个数字的最小公约数了.

 * 对于无限循环小数, 本题相对来说复杂一些, 需要寻求一种方法来计算出其循环节部分对应的分数形式

 */

#include<stdio.h>

#include<stdlib.h>

struct fraction {

int numerator;
// 分子

int denominator;
// 分母

};

int power(int base, int power) {

int i = 0;

int product = 1;

for (; i < power; ++i)

product *= base;

return product;

}

int ctoi(char ch[], int length) {

int i;

int target = 0;

for (i = length – 1; i >= 0; –i) {

target += (ch[length – i – 1] – ‘0’) * power(10, i);

}

return target;

}

int Substract(int x, int y){

int min, max, temp;

if (x > y) {

max = x;

min = y;

} else  {

max = y;

min = x;

}

while(max – min != 0) {

temp = max – min;

if (temp > min)

max = temp;

else {

max = min;

min = temp;

}

}

return min;

}

// 此函数中用于转化有限小数, 首先将小数部分转化为整数, 然后求小数部分与10^ld的最大公约数, 上下约分, 得到分数形式

struct fraction LimitedDecimals(char integer[], int li, char decimal[], int ld) {

struct fraction frac;

int numerator;

int denominator;

int divisor;

numerator = ctoi(decimal, ld);

denominator = power(10, ld);

divisor = Substract(numerator, denominator);

numerator /= divisor;

denominator /= divisor;

numerator += ctoi(integer, li) * denominator;

frac.numerator = numerator;

frac.denominator = denominator;

return frac;

}

// 此函数中用于转化无限循环小数

// integer为整数部分, decimal为小数不循环部分, cycle为循环节

// 将循环节部分转换成小数之后, 由于其位于小数点右侧ld位处, 因此需要除以10^ld, 再加上decimal转换成的分数部分, 然后再加上整数部分即可.

// 循环节转换算法:

// Y = 0.(C1C2…Cm)

// Y * 10^m = (C1C2…Cm).C1C2…Cm = C1C2…Cm + 0.(C1C2…Cm)

// Y * 10^m – Y = C1C2…Cm

// 所以, Y = C1C2…Cm / (10^m – 1)

struct fraction InfiniteLoopDecimal(char integer[], int li, char decimal[], int ld, char cycle[], int lc) {

struct fraction frac;

int numerator;
// 分子

int denominator;
// 分母

int numerator1, numerator2;

int denominator1, denominator2;

int divisor;

// 将循环部分转换成分数

numerator1 = ctoi(cycle, lc);
// 循环部分分子

denominator1 = (power(10, lc) – 1) * power(10, ld);
// 循环部分分母

numerator2 = ctoi(decimal, ld);

denominator2 = power(10, ld);

denominator = denominator1 * denominator2;

numerator = numerator1 * denominator2 + numerator2 * denominator1;

divisor = Substract(numerator, denominator);

numerator /= divisor;

denominator /= divisor;

numerator += ctoi(integer, li) * denominator;

frac.numerator = numerator;

frac.denominator = denominator;

return frac;

}

int main() {

// 分别定义三个字符串数组, 分别用于存储小数的整数部分、小数部分以及循环节

char integer[100];
// 整数部分

char decimal[100];
// 小数部分

char cycle[100];
// 循环节

int li, ld, lc;
// 分别记录整数部分、小数部分和循环节的长度

char ch;

struct fraction frac;

while ((ch = getchar()) != EOF) {

li = 0;

ld = 0;

lc = 0;

while (ch != ‘.’ && ch != ‘\n’) {

integer[li++] = ch;

ch = getchar();

}

integer[li] = ‘\0’;

if (ch == ‘\n’) {

printf(“这是个整数, %d\n”, ctoi(integer, li));

continue;

}

while ((ch = getchar()) != ‘(‘ && ch != ‘\n’) {

decimal[ld++] = ch;

}

decimal[ld] = ‘\0’;

if (ch == ‘(‘) {

while((ch = getchar()) != ‘)’) {

cycle[lc++] = ch;

}

cycle[lc] = ‘\0’;

}

while (ch != ‘\n’)

ch = getchar();

if (lc == 0) {

printf(“这是个有限小数: “);

frac = LimitedDecimals(integer, li, decimal, ld);

printf(“%d/%d\n”, frac.numerator, frac.denominator);

continue;

}

printf(“这是个无限循环小数: “);

frac = InfiniteLoopDecimal(integer, li, decimal, ld, cycle, lc);

printf(“%d/%d\n”, frac.numerator, frac.denominator);

}

return 0;

}

    原文作者:mxk19930509
    原文地址: https://blog.csdn.net/u011387543/article/details/80569359
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞