11076 浮点数的分数表达(优先做)
时间限制:1000MS 代码长度限制:10KB
提交次数:0 通过次数:0
题型: 编程题 语言: G++;GCC;VC;JAVA
Description
在计算机中,用float或double来存储小数有时不能得到精确值,若要精确表达一个浮点数的计算结果,
最好用分数来表示小数,有限小数或无限循环小数都可以转化为分数,无限循环小数的循环节用括号标记出来。如:
0.9 = 9/10
0.(3) = 0.3(3) = 0.3(33) = 1/3
当然一个小数可以用好几种分数形式来表示,我们只感兴趣最简的分数形式(即分母最小),如:
0.3(33) = 1/3 = 3/9
因为任何一个数都可以转化为一个整数和一个纯小数之和,整数部分较为简单无需做额外处理,只要将纯小数部分转
化为分数形式,整数部分的分数部分就很简单了。
现在给定一个正的纯小数(这个纯小数为有限小数或无限循环小数),请你以最简分数形式来返回这个纯小数。
输入格式
给定一个纯小数,若是无限循环小数,用括号标记循环节,输入小数表达不超过100个字符。
说明:这里如果觉得高精度数有难度,先考虑用64位整数来求解吧。测试数据没有太长,位数不超过64位整数表示范围。
即,你用64位整数做,可通过此题。
输出格式
输出:化为最简分数形式,分子在前,分母在后,中间空格连接。
输入样例
0.3(33)
输出样例
1 3
解题思路
考虑输入的是纯小数,先暂时不考虑分子和分母有公因子的情况。
1. 假设有限小数:X = 0.a1a2…an,式中的a1,a2,…,an都是0~9的数字。
X = 0.a1a2…an = a1a2…an/10^n
2. 假设无限循环小数:X = 0.a1a2…an(b1b2…bm),式中的a1,a2,…,an, b1,b2,…,bm都是0~9的数字,括号为循环节。
第一步,先将X化为只有循环部分的纯小数。
- X = 0.a1a2…an(b1b2…bm)
- (10^n)*X = a1a2…an + 0.(b1b2…bm)
- X = (a1a2…an + 0.(b1b2…bm)) / (10^n)
上式中,a1a2…an是整数部分,容易解决。重点考虑小数部分0.(b1b2…bm)如何化为分数形式,再加上整数部分即可。
第二步,考虑Y = 0.(b1b2…bm),将Y化为分数,
- (10^m)*Y = b1b2…bm + 0.(b1b2…bm)
- ((10^m)-1)*Y = b1b2…bm
- Y = b1b2…bm / ((10^m)-1)
将第二步的Y带入第一步的X,可得:
X = (a1a2…an+Y)/(10^n) = ((a1a2…an)*((10^m)-1) + (b1b2…bm)) / (((10m)-1)*(10n))
此时,可以将任何一个有限小数或无限循环小数,化为分数表示,分数的分子和分母如上分析的公式。
但此时的分子分母未必是最简化的,对分子分母再进行约分,删去公共的因子,A/B = (A/GCD(A,B))/(B/GCD(A,B)),【】化为简单形式。 这里,GCD(A,B)表示A和B的最大公约数。
题目给的例子0.3(33)按照如上公式分析看看是否是1/3。
这里设输入的数为X。
X = 0.3(33)
10X = 3.(33)
X = 3/10 + 0.(33)/10 //这一步目的化成只有循环节的小数,比如:0.(33),而把原数循环节前面的数都变
//为有限小数的部分(因为有限小数更容易处理),现在需要重点考虑只有循环节部
//分的纯小数怎么转化为分数即可。
另:Y = 0.(33)
(10^2)Y = 33 + Y
(10^2 - 1)Y = 33
Y = 33/99 //将这个Y代入上式求解X的分数表达
则初始数据:X = 3/10 + (1/10)Y
X = 3/10 + (1/10)(33/99)
X = 330/990
将分子分母约去最大公约数得:X = 1/3
更多注释可查看代码中,有助于理解
代码如下
#include <iostream>
#include <string>
#include <cmath>
#include <cstdlib>
#include <algorithm>
using namespace std;
int main()
{
string s1;
cin >> s1;
bool isInfinite = false, isfinite = true;
long long infiniteNum = 0, finiteNum = 0;
long long infiniteDigit = 1, finiteDigit = 1; // 记录有限和无限小数有多少位
for(int i = 2; i < s1.length(); i++)
{
if(s1[i] == ')')
{
break;
}
else if(s1[i] == '(')
{
isInfinite = true; // 开始遍历无限循环
isfinite = false;
}
// 遍历到有限循环小数部分
else if(isfinite)
{
finiteNum = finiteNum * 10 + s1[i] - '0';
finiteDigit *= 10;
}
// 遍历到无限循环小数部分
else if(isInfinite)
{
infiniteNum = infiniteNum * 10 + s1[i] - '0';
infiniteDigit *= 10;
}
}
//cout << finiteNum << " " << finiteDigit << " " << infiniteNum << " " << infiniteDigit << endl;
long long upper = 0, down = 0;
// 没无限循环节
if(infiniteNum == 0)
{
upper = finiteNum;
down = finiteDigit;
}
else
{
upper = finiteNum * (infiniteDigit - 1) + infiniteNum;
down = finiteDigit * (infiniteDigit - 1);
}
long long t = __gcd(upper, down);
cout << upper/t << " " << down/t << endl;
return 0;
}
最后
对我感兴趣的小伙伴可查看以下链接
- 我的掘金主页:https://juejin.cn/user/1302297507801358
- 博客主页:http://blog.zhangjiancong.top/
- 公众号:Smooth前端成长记录