1.纯小数转分数
假设当前小数为0.abc
转成分数方式如下:
①将小数点右移至最后一位右边
目前数字变为abc,记录右移位数x。
②分子p目前为abc,分母q为10 ^ x。
③设d = gcd(p, q), 小数0.abc则可表示为 (p / d) / (q / d)
其他位数的纯小数以此类推。
2.带小数转分数
假设当前小数为d.abc
先提出整数部分,对小数部分进行上面的
纯小数转分数步骤。在第二步的时候分子
变为p + d * q,其余步骤相同。
3.无限循环小数转分数
这个我举例子说明可能更清楚。
比如小数0.565656... 56这个数字循环
设x = 0.565656...
所以100 * x = 56.565656...
令 100 * x - x = 56
所以99 * x = 56
所以x = 56 / 99
再比如小数1.4723723723... 723这个循环节。
设x = 0.0723...
所以10000 * x = 723.723...
10000 * x - 10 * x = 723
x = 723 / 9990 = 241 / 3330
对于整体1.4723723... = 14 / 10 + 241 / 3330 = 4903 / 3330
很显然思路就是对于循环的部分,能得到一个有限的位数,
然后用分数表示出来,最后再跟前面不循环的部分通分。
纯小数转分数跟带小数转分数都比较好实现,我就不上代码了。
下面贴出无限循环小数转分数的代码。
对应的是一道题目:ICPC North Central NA Contest 2018 C. Rational Ratio
https://nanti.jisuanke.com/t/45022
#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = 100 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
#ifdef LOCAL
#define debug(x) cout << "[" __FUNCTION__ ": " #x " = " << (x) << "]\n"
#define TIME cout << "RuningTime: " << clock() << "ms\n", 0
#else
#define TIME 0
#endif
ll fpow(ll a, ll b) { ll res = 1; for (; b > 0; b >>= 1) { if (b & 1) res = res * a % mod; a = a * a % mod; } return res; }
ll gcd(ll a, ll b)
{
return b == 0 ? a : gcd(b, a % b);
}
ll ten(int x)
{
ll res = 1;
while (x--)
res *= 10;
return res;
}
char s[N];
int main()
{
#ifdef LOCAL
freopen("E:/input.txt", "r", stdin);
#endif
int k;
scanf("%s%d", s + 1, &k);
int n = strlen(s + 1);
int dot;
ll x = 0, y = 0;
for (int i = 1; i <= n; i++)
{
if (s[i] == '.')
dot = i;
else
{
if (i <= n - k)
x = x * 10 + s[i] - '0';
else
y = y * 10 + s[i] - '0';
}
}
ll f = ten(n - k - dot);
ll g = ten(n - dot) - f;
ll fz = x * g + y * f;
ll fm = f * g;
ll d = gcd(fz, fm);
printf("%lld/%lld\n", fz / d, fm / d);
return TIME;
}