编程之美--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;
}

转载于:https://www.cnblogs.com/KingOfAlex/p/9134133.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值