/*
精确表达浮点数:
在计算机中,使用float或double来存储小数不能得到精确值。希望得到精确值,最好用分数形式来表示小数。有限小数或者无限循环小数可以转化为分数
例如:
0.9 = 9/10
0.333(3) = 1/3(括号中的数字表示是循环节)
一个小数可以用好几种分数形式来表示。如:
0.333(3) = 1/3 = 3/9
给定一个有限小数或者无限循环小数,你能否用分母最小的分数形式来返回这个小数呢?如果输入为循环小数,循环节用括号标记出来。下面是一些可能的输入数据,
如0.3,0.30,0.3(000),0.3333(3333)、......
分析:
先从最简单的情况入手:所有小数可以分解成一个整数和一个纯小数之和,不妨只考虑大于0,小于1的纯小数,且暂时不考虑分子和分母的约分。
题目中输入的小数,要么为有限小数X = 0.a1a2...an,要么为无限循环小数X=0.a1a2...an(b1b2...bm),X表示式中的字母a1a2...an,b1b2...bm都是0~9的数字,括号
部分(b1b2...bm)表示循环节,
对于有限小数X = 0.a1a2...an来说,X = (a1a2..an)/10^n
对于无限循环小数X = 0.a1a2...an(b1b2...bm)来说,复杂部分在于小数点后同时又非循环和循环部分
X = 0.a1a2...an(b1b2...bm)
->10^n*X = a1a2...an.(b1b2...bm)
->10^n*X = a1a2...an + 0.(b1b2...bm)
->X = (a1a2...an + 0.(b1b2...bm)) / 10^n
对于整数部分a1a2...an,不需要二外处理,只需要把小数部分转化为分数形式再加上这个整数即可。对于无限循环部分,采用下面方式处理:
令Y = 0.(b1b2...bn),那么
10^m * Y = b1b2...bm.(b1b2...bm)
->10^m * Y = b1b2...bm + 0.(b1b2...bm)
->10^m * Y - Y = b1b2...bm
->Y = b1b2...bm/(10^m-1)
将Y带入得到
X = (a1a2...an+Y)/10^n
= (a1a2...an + b1b2...bm/(10^m-1))/10^n
=( (a1a2...an*(10^m-1) + b1b2...bm) )/(10^(m-1) * 10^n );
注意:分母未必是最简的,应该对分子和分母进行约分,即双方同时除以两者的最大公约数即可
A/B = (A/Gcd(A,B)) / (B/Gcd(A,B))
输入:
0.3(33)
0.285714(285714)
输出:
1/3
2/7
整个思路应该是:将输入的数字当成字符串,以找到第一个"("和第一个一个")"作为切分
切分为0.3 (33),计算出.后面的数字位数n,和()中间的数字位数m
利用公式
求公约数
*/
/*
关键:
1 求公约数是有大小的顺序的,必须确保第一个参数大于第二个参数
2 对于无限循环小数X = 0.a1a2...an(b1b2...bm)来说,复杂部分在于小数点后同时又非循环和循环部分
X = 0.a1a2...an(b1b2...bm)
->10^n*X = a1a2...an.(b1b2...bm)
->10^n*X = a1a2...an + 0.(b1b2...bm)
->X = (a1a2...an + 0.(b1b2...bm)) / 10^n
对于整数部分a1a2...an,不需要二外处理,只需要把小数部分转化为分数形式再加上这个整数即可。对于无限循环部分,采用下面方式处理:
令Y = 0.(b1b2...bn),那么
10^m * Y = b1b2...bm.(b1b2...bm)
->10^m * Y = b1b2...bm + 0.(b1b2...bm)
->10^m * Y - Y = b1b2...bm
->Y = b1b2...bm/(10^m-1)
3 X = (a1a2...an+Y)/10^n
= (a1a2...an + b1b2...bm/(10^m-1))/10^n
=( (a1a2...an*(10^m-1) + b1b2...bm) )/(10^(m-1) * 10^n );
注意:分母未必是最简的,应该对分子和分母进行约分,即双方同时除以两者的最大公约数即可
A/B = (A/Gcd(A,B)) / (B/Gcd(A,B))
4 lMolecule = lMolecule * lRadius + (long long)(*pCh - '0');//注意,这里始终是乘以10
5
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
const int MAXSIZE = 10000;
long long gcd(long long a,long long b)
{
return b == 0 ? a : gcd(b,a%b);
}
void swap(long long* pNum1,long long* pNum2)
{
long long lTemp = *pNum1;
*pNum1 = *pNum2;
*pNum2 = lTemp;
}
long long power_recursion(int n)//计算10^n的值
{
if(n == 1)
{
return 10;//10^1 = 10
}
long long lRes = power_recursion(n/2);
lRes *= lRes;
if((n & 1) == 1)//如果是奇数
{
lRes *= 10;
}
return lRes;
}
void fraction(char* str)
{
if(!str)
{
return;
}
char* pDot = strchr(str,'.');
char* pLeftBracket = strchr(str,'(');
char* pRightBracket = strchr(str,')');
assert(pDot && pLeftBracket && pRightBracket);
int iOutN = pLeftBracket - pDot - 1;//括号外的小数位数,例如0.3(33),求得是0.3中的3占一位
int iInM =pRightBracket - pLeftBracket - 1;//求得是括号内的小数卫视,例如0.3(33),求得是(33)中的33占两位
char* pCh;
long long lMolecule = 0;
long long lRadius = 10;
for(pCh = pDot + 1 ; pCh != pLeftBracket ; pCh++)//下面计算0.a1a2...an(b1b2...bm)中的a1a2...an
{
lMolecule = lMolecule * lRadius + (long long)(*pCh - '0');//注意,这里始终是乘以10
}
long long lDenominator = 0; //下面计算b1b2...bm
for(pCh = pLeftBracket + 1 ; pCh != pRightBracket ; pCh++)
{
lDenominator = lDenominator * lRadius + (long long)(*pCh - '0');
}
long long lM = power_recursion(iInM);
lM--;
long long lN = power_recursion(iOutN);
long long lUp = lMolecule * lM + lDenominator;
long long lDown = lM*lN;
long long lGcd = gcd(lDown,lUp);
//printf("%d%s%d\n",lUp/lGcd,'//',lDown/lGcd);//注意转义字符
printf("%d",lUp/lGcd);
printf("/");
printf("%d\n",lDown/lGcd);
}
void process()
{
char str[MAXSIZE];
while(EOF != scanf("%s",str))
{
fraction(str);
}
}
int main(int argc,char* argv[])
{
process();
getchar();
return 0;
}
编程之美:第二章 数字之魅 2.6精确表达浮点数
最新推荐文章于 2021-08-06 15:36:09 发布